Skip to content

Commit 6c2e851

Browse files
Merge pull request #26317 from Kingwl/parameter-initializer-lookup-fix
add special check for parameter initializer lookup if targeting es2015+
2 parents b183418 + 8869f39 commit 6c2e851

11 files changed

+622
-6
lines changed

src/compiler/checker.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,17 +1208,23 @@ namespace ts {
12081208
// local types not visible outside the function body
12091209
: false;
12101210
}
1211-
if (meaning & SymbolFlags.Value && result.flags & SymbolFlags.FunctionScopedVariable) {
1212-
// parameters are visible only inside function body, parameter list and return type
1213-
// technically for parameter list case here we might mix parameters and variables declared in function,
1214-
// however it is detected separately when checking initializers of parameters
1215-
// to make sure that they reference no variables declared after them.
1216-
useResult =
1211+
if (meaning & SymbolFlags.Value && result.flags & SymbolFlags.Variable) {
1212+
// parameter initializer will lookup as normal variable scope when targeting es2015+
1213+
if (compilerOptions.target && compilerOptions.target >= ScriptTarget.ES2015 && isParameter(lastLocation) && result.valueDeclaration !== lastLocation) {
1214+
useResult = false;
1215+
}
1216+
else if (result.flags & SymbolFlags.FunctionScopedVariable) {
1217+
// parameters are visible only inside function body, parameter list and return type
1218+
// technically for parameter list case here we might mix parameters and variables declared in function,
1219+
// however it is detected separately when checking initializers of parameters
1220+
// to make sure that they reference no variables declared after them.
1221+
useResult =
12171222
lastLocation.kind === SyntaxKind.Parameter ||
12181223
(
12191224
lastLocation === (<FunctionLikeDeclaration>location).type &&
12201225
!!findAncestor(result.valueDeclaration, isParameter)
12211226
);
1227+
}
12221228
}
12231229
}
12241230
else if (location.kind === SyntaxKind.ConditionalType) {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(3,20): error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
2+
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(8,27): error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
3+
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(13,20): error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
4+
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(21,18): error TS2372: Parameter 'a' cannot be referenced in its initializer.
5+
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(25,22): error TS2372: Parameter 'async' cannot be referenced in its initializer.
6+
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(29,15): error TS2448: Block-scoped variable 'foo' used before its declaration.
7+
8+
9+
==== tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts (6 errors) ====
10+
let foo: string = "";
11+
12+
function f1 (bar = foo) { // unexpected compiler error; works at runtime
13+
~~~
14+
!!! error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
15+
var foo: number = 2;
16+
return bar; // returns 1
17+
}
18+
19+
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
20+
~~~
21+
!!! error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
22+
var foo: number = 2;
23+
return bar(); // returns 1
24+
}
25+
26+
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
27+
~~~
28+
!!! error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
29+
return bar;
30+
}
31+
32+
function f4 (foo, bar = foo) {
33+
return bar
34+
}
35+
36+
function f5 (a = a) {
37+
~
38+
!!! error TS2372: Parameter 'a' cannot be referenced in its initializer.
39+
return a
40+
}
41+
42+
function f6 (async = async) {
43+
~~~~~
44+
!!! error TS2372: Parameter 'async' cannot be referenced in its initializer.
45+
return async
46+
}
47+
48+
function f7({[foo]: bar}: any[]) {
49+
~~~
50+
!!! error TS2448: Block-scoped variable 'foo' used before its declaration.
51+
!!! related TS2728 tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts:30:9: 'foo' is declared here.
52+
let foo: number = 2;
53+
}
54+
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//// [parameterInitializersForwardReferencing1.ts]
2+
let foo: string = "";
3+
4+
function f1 (bar = foo) { // unexpected compiler error; works at runtime
5+
var foo: number = 2;
6+
return bar; // returns 1
7+
}
8+
9+
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
10+
var foo: number = 2;
11+
return bar(); // returns 1
12+
}
13+
14+
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
15+
return bar;
16+
}
17+
18+
function f4 (foo, bar = foo) {
19+
return bar
20+
}
21+
22+
function f5 (a = a) {
23+
return a
24+
}
25+
26+
function f6 (async = async) {
27+
return async
28+
}
29+
30+
function f7({[foo]: bar}: any[]) {
31+
let foo: number = 2;
32+
}
33+
34+
35+
//// [parameterInitializersForwardReferencing1.js]
36+
var foo = "";
37+
function f1(bar) {
38+
if (bar === void 0) { bar = foo; }
39+
var foo = 2;
40+
return bar; // returns 1
41+
}
42+
function f2(bar) {
43+
if (bar === void 0) { bar = function (baz) {
44+
if (baz === void 0) { baz = foo; }
45+
return baz;
46+
}; }
47+
var foo = 2;
48+
return bar(); // returns 1
49+
}
50+
function f3(bar, foo) {
51+
if (bar === void 0) { bar = foo; }
52+
if (foo === void 0) { foo = 2; }
53+
return bar;
54+
}
55+
function f4(foo, bar) {
56+
if (bar === void 0) { bar = foo; }
57+
return bar;
58+
}
59+
function f5(a) {
60+
if (a === void 0) { a = a; }
61+
return a;
62+
}
63+
function f6(async) {
64+
if (async === void 0) { async = async; }
65+
return async;
66+
}
67+
function f7(_a) {
68+
var _b = foo, bar = _a[_b];
69+
var foo = 2;
70+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
=== tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts ===
2+
let foo: string = "";
3+
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 0, 3))
4+
5+
function f1 (bar = foo) { // unexpected compiler error; works at runtime
6+
>f1 : Symbol(f1, Decl(parameterInitializersForwardReferencing1.ts, 0, 21))
7+
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 2, 13))
8+
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 3, 7))
9+
10+
var foo: number = 2;
11+
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 3, 7))
12+
13+
return bar; // returns 1
14+
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 2, 13))
15+
}
16+
17+
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
18+
>f2 : Symbol(f2, Decl(parameterInitializersForwardReferencing1.ts, 5, 1))
19+
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 7, 13))
20+
>baz : Symbol(baz, Decl(parameterInitializersForwardReferencing1.ts, 7, 20))
21+
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 8, 7))
22+
>baz : Symbol(baz, Decl(parameterInitializersForwardReferencing1.ts, 7, 20))
23+
24+
var foo: number = 2;
25+
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 8, 7))
26+
27+
return bar(); // returns 1
28+
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 7, 13))
29+
}
30+
31+
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
32+
>f3 : Symbol(f3, Decl(parameterInitializersForwardReferencing1.ts, 10, 1))
33+
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 12, 13))
34+
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 12, 23))
35+
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 12, 23))
36+
37+
return bar;
38+
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 12, 13))
39+
}
40+
41+
function f4 (foo, bar = foo) {
42+
>f4 : Symbol(f4, Decl(parameterInitializersForwardReferencing1.ts, 14, 1))
43+
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 16, 13))
44+
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 16, 17))
45+
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 16, 13))
46+
47+
return bar
48+
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 16, 17))
49+
}
50+
51+
function f5 (a = a) {
52+
>f5 : Symbol(f5, Decl(parameterInitializersForwardReferencing1.ts, 18, 1))
53+
>a : Symbol(a, Decl(parameterInitializersForwardReferencing1.ts, 20, 13))
54+
>a : Symbol(a, Decl(parameterInitializersForwardReferencing1.ts, 20, 13))
55+
56+
return a
57+
>a : Symbol(a, Decl(parameterInitializersForwardReferencing1.ts, 20, 13))
58+
}
59+
60+
function f6 (async = async) {
61+
>f6 : Symbol(f6, Decl(parameterInitializersForwardReferencing1.ts, 22, 1))
62+
>async : Symbol(async, Decl(parameterInitializersForwardReferencing1.ts, 24, 13))
63+
>async : Symbol(async, Decl(parameterInitializersForwardReferencing1.ts, 24, 13))
64+
65+
return async
66+
>async : Symbol(async, Decl(parameterInitializersForwardReferencing1.ts, 24, 13))
67+
}
68+
69+
function f7({[foo]: bar}: any[]) {
70+
>f7 : Symbol(f7, Decl(parameterInitializersForwardReferencing1.ts, 26, 1))
71+
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 29, 7))
72+
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 28, 13))
73+
74+
let foo: number = 2;
75+
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 29, 7))
76+
}
77+
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
=== tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts ===
2+
let foo: string = "";
3+
>foo : string
4+
>"" : ""
5+
6+
function f1 (bar = foo) { // unexpected compiler error; works at runtime
7+
>f1 : (bar?: number) => number
8+
>bar : number
9+
>foo : number
10+
11+
var foo: number = 2;
12+
>foo : number
13+
>2 : 2
14+
15+
return bar; // returns 1
16+
>bar : number
17+
}
18+
19+
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
20+
>f2 : (bar?: (baz?: number) => number) => number
21+
>bar : (baz?: number) => number
22+
>(baz = foo) => baz : (baz?: number) => number
23+
>baz : number
24+
>foo : number
25+
>baz : number
26+
27+
var foo: number = 2;
28+
>foo : number
29+
>2 : 2
30+
31+
return bar(); // returns 1
32+
>bar() : number
33+
>bar : (baz?: number) => number
34+
}
35+
36+
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
37+
>f3 : (bar?: number, foo?: number) => number
38+
>bar : number
39+
>foo : number
40+
>foo : number
41+
>2 : 2
42+
43+
return bar;
44+
>bar : number
45+
}
46+
47+
function f4 (foo, bar = foo) {
48+
>f4 : (foo: any, bar?: any) => any
49+
>foo : any
50+
>bar : any
51+
>foo : any
52+
53+
return bar
54+
>bar : any
55+
}
56+
57+
function f5 (a = a) {
58+
>f5 : (a?: any) => any
59+
>a : any
60+
>a : any
61+
62+
return a
63+
>a : any
64+
}
65+
66+
function f6 (async = async) {
67+
>f6 : (async?: any) => any
68+
>async : any
69+
>async : any
70+
71+
return async
72+
>async : any
73+
}
74+
75+
function f7({[foo]: bar}: any[]) {
76+
>f7 : ({ [foo]: bar }: any[]) => void
77+
>foo : number
78+
>bar : any
79+
80+
let foo: number = 2;
81+
>foo : number
82+
>2 : 2
83+
}
84+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts(21,18): error TS2372: Parameter 'a' cannot be referenced in its initializer.
2+
tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts(25,22): error TS2372: Parameter 'async' cannot be referenced in its initializer.
3+
4+
5+
==== tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts (2 errors) ====
6+
let foo: string = "";
7+
8+
function f1 (bar = foo) { // unexpected compiler error; works at runtime
9+
var foo: number = 2;
10+
return bar; // returns 1
11+
}
12+
13+
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
14+
var foo: number = 2;
15+
return bar(); // returns 1
16+
}
17+
18+
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
19+
return bar;
20+
}
21+
22+
function f4 (foo, bar = foo) {
23+
return bar
24+
}
25+
26+
function f5 (a = a) {
27+
~
28+
!!! error TS2372: Parameter 'a' cannot be referenced in its initializer.
29+
return a
30+
}
31+
32+
function f6 (async = async) {
33+
~~~~~
34+
!!! error TS2372: Parameter 'async' cannot be referenced in its initializer.
35+
return async
36+
}
37+
38+
function f7({[foo]: bar}: any[]) {
39+
let foo: number = 2;
40+
}
41+

0 commit comments

Comments
 (0)