Skip to content

Commit 5e84ed3

Browse files
committed
Merge pull request microsoft#5706 from Microsoft/nameResolutionForParameters
restrict the scope of parameters\type parameters
2 parents 1f61ecf + 31039a3 commit 5e84ed3

10 files changed

Lines changed: 224 additions & 7 deletions

src/compiler/checker.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -476,15 +476,41 @@ namespace ts {
476476
// Locals of a source file are not in scope (because they get merged into the global symbol table)
477477
if (location.locals && !isGlobalSourceFile(location)) {
478478
if (result = getSymbol(location.locals, name, meaning)) {
479-
// Type parameters of a function are in scope in the entire function declaration, including the parameter
480-
// list and return type. However, local types are only in scope in the function body.
481-
if (!(meaning & SymbolFlags.Type) ||
482-
!(result.flags & (SymbolFlags.Type & ~SymbolFlags.TypeParameter)) ||
483-
!isFunctionLike(location) ||
484-
lastLocation === (<FunctionLikeDeclaration>location).body) {
479+
let useResult = true;
480+
if (isFunctionLike(location) && lastLocation && lastLocation !== (<FunctionLikeDeclaration>location).body) {
481+
// symbol lookup restrictions for function-like declarations
482+
// - Type parameters of a function are in scope in the entire function declaration, including the parameter
483+
// list and return type. However, local types are only in scope in the function body.
484+
// - parameters are only in the scope of function body
485+
if (meaning & result.flags & SymbolFlags.Type) {
486+
useResult = result.flags & SymbolFlags.TypeParameter
487+
// type parameters are visible in parameter list, return type and type parameter list
488+
? lastLocation === (<FunctionLikeDeclaration>location).type ||
489+
lastLocation.kind === SyntaxKind.Parameter ||
490+
lastLocation.kind === SyntaxKind.TypeParameter
491+
// local types not visible outside the function body
492+
: false;
493+
}
494+
if (meaning & SymbolFlags.Value && result.flags & SymbolFlags.FunctionScopedVariable) {
495+
// parameters are visible only inside function body, parameter list and return type
496+
// technically for parameter list case here we might mix parameters and variables declared in function,
497+
// however it is detected separately when checking initializers of parameters
498+
// to make sure that they reference no variables declared after them.
499+
useResult =
500+
lastLocation.kind === SyntaxKind.Parameter ||
501+
(
502+
lastLocation === (<FunctionLikeDeclaration>location).type &&
503+
result.valueDeclaration.kind === SyntaxKind.Parameter
504+
);
505+
}
506+
}
507+
508+
if (useResult) {
485509
break loop;
486510
}
487-
result = undefined;
511+
else {
512+
result = undefined;
513+
}
488514
}
489515
}
490516
switch (location.kind) {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
tests/cases/compiler/functionVariableInReturnTypeAnnotation.ts(1,24): error TS2304: Cannot find name 'b'.
2+
3+
4+
==== tests/cases/compiler/functionVariableInReturnTypeAnnotation.ts (1 errors) ====
5+
function bar(): typeof b {
6+
~
7+
!!! error TS2304: Cannot find name 'b'.
8+
var b = 1;
9+
return undefined;
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//// [functionVariableInReturnTypeAnnotation.ts]
2+
function bar(): typeof b {
3+
var b = 1;
4+
return undefined;
5+
}
6+
7+
//// [functionVariableInReturnTypeAnnotation.js]
8+
function bar() {
9+
var b = 1;
10+
return undefined;
11+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
tests/cases/compiler/parameterNamesInTypeParameterList.ts(1,30): error TS2304: Cannot find name 'a'.
2+
tests/cases/compiler/parameterNamesInTypeParameterList.ts(5,30): error TS2304: Cannot find name 'a'.
3+
tests/cases/compiler/parameterNamesInTypeParameterList.ts(9,30): error TS2304: Cannot find name 'a'.
4+
tests/cases/compiler/parameterNamesInTypeParameterList.ts(14,22): error TS2304: Cannot find name 'a'.
5+
tests/cases/compiler/parameterNamesInTypeParameterList.ts(17,22): error TS2304: Cannot find name 'a'.
6+
tests/cases/compiler/parameterNamesInTypeParameterList.ts(20,22): error TS2304: Cannot find name 'a'.
7+
8+
9+
==== tests/cases/compiler/parameterNamesInTypeParameterList.ts (6 errors) ====
10+
function f0<T extends typeof a>(a: T) {
11+
~
12+
!!! error TS2304: Cannot find name 'a'.
13+
a.b;
14+
}
15+
16+
function f1<T extends typeof a>({a}: {a:T}) {
17+
~
18+
!!! error TS2304: Cannot find name 'a'.
19+
a.b;
20+
}
21+
22+
function f2<T extends typeof a>([a]: T[]) {
23+
~
24+
!!! error TS2304: Cannot find name 'a'.
25+
a.b;
26+
}
27+
28+
class A {
29+
m0<T extends typeof a>(a: T) {
30+
~
31+
!!! error TS2304: Cannot find name 'a'.
32+
a.b
33+
}
34+
m1<T extends typeof a>({a}: {a:T}) {
35+
~
36+
!!! error TS2304: Cannot find name 'a'.
37+
a.b
38+
}
39+
m2<T extends typeof a>([a]: T[]) {
40+
~
41+
!!! error TS2304: Cannot find name 'a'.
42+
a.b
43+
}
44+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//// [parameterNamesInTypeParameterList.ts]
2+
function f0<T extends typeof a>(a: T) {
3+
a.b;
4+
}
5+
6+
function f1<T extends typeof a>({a}: {a:T}) {
7+
a.b;
8+
}
9+
10+
function f2<T extends typeof a>([a]: T[]) {
11+
a.b;
12+
}
13+
14+
class A {
15+
m0<T extends typeof a>(a: T) {
16+
a.b
17+
}
18+
m1<T extends typeof a>({a}: {a:T}) {
19+
a.b
20+
}
21+
m2<T extends typeof a>([a]: T[]) {
22+
a.b
23+
}
24+
}
25+
26+
//// [parameterNamesInTypeParameterList.js]
27+
function f0(a) {
28+
a.b;
29+
}
30+
function f1(_a) {
31+
var a = _a.a;
32+
a.b;
33+
}
34+
function f2(_a) {
35+
var a = _a[0];
36+
a.b;
37+
}
38+
var A = (function () {
39+
function A() {
40+
}
41+
A.prototype.m0 = function (a) {
42+
a.b;
43+
};
44+
A.prototype.m1 = function (_a) {
45+
var a = _a.a;
46+
a.b;
47+
};
48+
A.prototype.m2 = function (_a) {
49+
var a = _a[0];
50+
a.b;
51+
};
52+
return A;
53+
})();
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/compiler/typeParametersAndParametersInComputedNames.ts(6,10): error TS2304: Cannot find name 'T'.
2+
tests/cases/compiler/typeParametersAndParametersInComputedNames.ts(6,13): error TS2304: Cannot find name 'a'.
3+
4+
5+
==== tests/cases/compiler/typeParametersAndParametersInComputedNames.ts (2 errors) ====
6+
function foo<T>(a: T) : string {
7+
return "";
8+
}
9+
10+
class A {
11+
[foo<T>(a)]<T>(a: T) {
12+
~
13+
!!! error TS2304: Cannot find name 'T'.
14+
~
15+
!!! error TS2304: Cannot find name 'a'.
16+
}
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//// [typeParametersAndParametersInComputedNames.ts]
2+
function foo<T>(a: T) : string {
3+
return "";
4+
}
5+
6+
class A {
7+
[foo<T>(a)]<T>(a: T) {
8+
}
9+
}
10+
11+
//// [typeParametersAndParametersInComputedNames.js]
12+
function foo(a) {
13+
return "";
14+
}
15+
var A = (function () {
16+
function A() {
17+
}
18+
A.prototype[foo(a)] = function (a) {
19+
};
20+
return A;
21+
})();
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
function bar(): typeof b {
2+
var b = 1;
3+
return undefined;
4+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
function f0<T extends typeof a>(a: T) {
2+
a.b;
3+
}
4+
5+
function f1<T extends typeof a>({a}: {a:T}) {
6+
a.b;
7+
}
8+
9+
function f2<T extends typeof a>([a]: T[]) {
10+
a.b;
11+
}
12+
13+
class A {
14+
m0<T extends typeof a>(a: T) {
15+
a.b
16+
}
17+
m1<T extends typeof a>({a}: {a:T}) {
18+
a.b
19+
}
20+
m2<T extends typeof a>([a]: T[]) {
21+
a.b
22+
}
23+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function foo<T>(a: T) : string {
2+
return "";
3+
}
4+
5+
class A {
6+
[foo<T>(a)]<T>(a: T) {
7+
}
8+
}

0 commit comments

Comments
 (0)