diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b54b13932534e..c6260a958dea3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16296,11 +16296,17 @@ namespace ts { const type = tryGetThisTypeAt(node, container); if (!type && noImplicitThis) { // With noImplicitThis, functions may not reference 'this' if it has type 'any' - error( + const diag = error( node, capturedByArrowFunction && container.kind === SyntaxKind.SourceFile ? Diagnostics.The_containing_arrow_function_captures_the_global_value_of_this_which_implicitly_has_type_any : Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation); + if (!isSourceFile(container)) { + const outsideThis = tryGetThisTypeAt(container); + if (outsideThis) { + addRelatedInfo(diag, createDiagnosticForNode(container, Diagnostics.An_outer_value_of_this_is_shadowed_by_this_container)); + } + } } return type || anyType; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 49f682c4d582d..6e80e391f9ad2 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2509,6 +2509,10 @@ "category": "Error", "code": 2737 }, + "An outer value of 'this' is shadowed by this container.": { + "category": "Message", + "code": 2738 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/thisBinding2.errors.txt b/tests/baselines/reference/thisBinding2.errors.txt index c91a16c812a5b..a5cff14f94940 100644 --- a/tests/baselines/reference/thisBinding2.errors.txt +++ b/tests/baselines/reference/thisBinding2.errors.txt @@ -14,6 +14,7 @@ tests/cases/compiler/thisBinding2.ts(10,11): error TS2683: 'this' implicitly has return this.x; ~~~~ !!! error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +!!! related TS2738 tests/cases/compiler/thisBinding2.ts:8:12: An outer value of 'this' is shadowed by this container. }(); } } diff --git a/tests/baselines/reference/thisShadowingErrorSpans.errors.txt b/tests/baselines/reference/thisShadowingErrorSpans.errors.txt new file mode 100644 index 0000000000000..46c4be3a3b84d --- /dev/null +++ b/tests/baselines/reference/thisShadowingErrorSpans.errors.txt @@ -0,0 +1,16 @@ +tests/cases/compiler/thisShadowingErrorSpans.ts(5,13): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. + + +==== tests/cases/compiler/thisShadowingErrorSpans.ts (1 errors) ==== + class C { + m() { + this.m(); + function f() { + this.m(); + ~~~~ +!!! error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +!!! related TS2738 tests/cases/compiler/thisShadowingErrorSpans.ts:4:18: An outer value of 'this' is shadowed by this container. + } + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/thisShadowingErrorSpans.js b/tests/baselines/reference/thisShadowingErrorSpans.js new file mode 100644 index 0000000000000..78682322fc42d --- /dev/null +++ b/tests/baselines/reference/thisShadowingErrorSpans.js @@ -0,0 +1,24 @@ +//// [thisShadowingErrorSpans.ts] +class C { + m() { + this.m(); + function f() { + this.m(); + } + } +} + + +//// [thisShadowingErrorSpans.js] +"use strict"; +var C = /** @class */ (function () { + function C() { + } + C.prototype.m = function () { + this.m(); + function f() { + this.m(); + } + }; + return C; +}()); diff --git a/tests/baselines/reference/thisShadowingErrorSpans.symbols b/tests/baselines/reference/thisShadowingErrorSpans.symbols new file mode 100644 index 0000000000000..9ad12ffa433c5 --- /dev/null +++ b/tests/baselines/reference/thisShadowingErrorSpans.symbols @@ -0,0 +1,20 @@ +=== tests/cases/compiler/thisShadowingErrorSpans.ts === +class C { +>C : Symbol(C, Decl(thisShadowingErrorSpans.ts, 0, 0)) + + m() { +>m : Symbol(C.m, Decl(thisShadowingErrorSpans.ts, 0, 9)) + + this.m(); +>this.m : Symbol(C.m, Decl(thisShadowingErrorSpans.ts, 0, 9)) +>this : Symbol(C, Decl(thisShadowingErrorSpans.ts, 0, 0)) +>m : Symbol(C.m, Decl(thisShadowingErrorSpans.ts, 0, 9)) + + function f() { +>f : Symbol(f, Decl(thisShadowingErrorSpans.ts, 2, 17)) + + this.m(); + } + } +} + diff --git a/tests/baselines/reference/thisShadowingErrorSpans.types b/tests/baselines/reference/thisShadowingErrorSpans.types new file mode 100644 index 0000000000000..2efd099400d42 --- /dev/null +++ b/tests/baselines/reference/thisShadowingErrorSpans.types @@ -0,0 +1,25 @@ +=== tests/cases/compiler/thisShadowingErrorSpans.ts === +class C { +>C : C + + m() { +>m : () => void + + this.m(); +>this.m() : void +>this.m : () => void +>this : this +>m : () => void + + function f() { +>f : () => void + + this.m(); +>this.m() : any +>this.m : any +>this : any +>m : any + } + } +} + diff --git a/tests/cases/compiler/thisShadowingErrorSpans.ts b/tests/cases/compiler/thisShadowingErrorSpans.ts new file mode 100644 index 0000000000000..d6c351f0080fa --- /dev/null +++ b/tests/cases/compiler/thisShadowingErrorSpans.ts @@ -0,0 +1,9 @@ +// @strict: true +class C { + m() { + this.m(); + function f() { + this.m(); + } + } +}