Skip to content

Commit b7e466b

Browse files
committed
Revert "Revert "Explicitly typed special assignments are context sensitive (#25619)""
This reverts commit 16676f2.
1 parent 204ce17 commit b7e466b

7 files changed

+579
-22
lines changed

src/compiler/checker.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15786,22 +15786,22 @@ namespace ts {
1578615786
}
1578715787

1578815788
// In an assignment expression, the right operand is contextually typed by the type of the left operand.
15789-
// Don't do this for special property assignments to avoid circularity.
15789+
// Don't do this for special property assignments unless there is a type tag on the assignment, to avoid circularity from checking the right operand.
1579015790
function isContextSensitiveAssignment(binaryExpression: BinaryExpression): boolean {
1579115791
const kind = getSpecialPropertyAssignmentKind(binaryExpression);
1579215792
switch (kind) {
1579315793
case SpecialPropertyAssignmentKind.None:
1579415794
return true;
1579515795
case SpecialPropertyAssignmentKind.Property:
15796-
// If `binaryExpression.left` was assigned a symbol, then this is a new declaration; otherwise it is an assignment to an existing declaration.
15797-
// See `bindStaticPropertyAssignment` in `binder.ts`.
15798-
return !binaryExpression.left.symbol;
1579915796
case SpecialPropertyAssignmentKind.ExportsProperty:
15800-
case SpecialPropertyAssignmentKind.ModuleExports:
15797+
case SpecialPropertyAssignmentKind.Prototype:
1580115798
case SpecialPropertyAssignmentKind.PrototypeProperty:
15799+
// If `binaryExpression.left` was assigned a symbol, then this is a new declaration; otherwise it is an assignment to an existing declaration.
15800+
// See `bindStaticPropertyAssignment` in `binder.ts`.
15801+
return !binaryExpression.left.symbol || binaryExpression.left.symbol.valueDeclaration && !!getJSDocTypeTag(binaryExpression.left.symbol.valueDeclaration);
1580215802
case SpecialPropertyAssignmentKind.ThisProperty:
15803-
case SpecialPropertyAssignmentKind.Prototype:
15804-
return false;
15803+
case SpecialPropertyAssignmentKind.ModuleExports:
15804+
return !binaryExpression.symbol || binaryExpression.symbol.valueDeclaration && !!getJSDocTypeTag(binaryExpression.symbol.valueDeclaration);
1580515805
default:
1580615806
return Debug.assertNever(kind);
1580715807
}

tests/baselines/reference/conflictingCommonJSES2015Exports.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ export function abc(a, b, c) { return 5; }
77
>5 : 5
88

99
module.exports = { abc };
10-
>module.exports = { abc } : { [x: string]: any; abc: (a: any, b: any, c: any) => number; }
10+
>module.exports = { abc } : { abc: (a: any, b: any, c: any) => number; }
1111
>module.exports : any
1212
>module : any
1313
>exports : any
14-
>{ abc } : { [x: string]: any; abc: (a: any, b: any, c: any) => number; }
14+
>{ abc } : { abc: (a: any, b: any, c: any) => number; }
1515
>abc : (a: any, b: any, c: any) => number
1616

1717
=== tests/cases/conformance/salsa/use.js ===
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
tests/cases/conformance/salsa/mod.js(5,7): error TS7006: Parameter 'n' implicitly has an 'any' type.
2+
tests/cases/conformance/salsa/test.js(52,7): error TS7006: Parameter 'n' implicitly has an 'any' type.
3+
tests/cases/conformance/salsa/test.js(70,7): error TS7006: Parameter 'n' implicitly has an 'any' type.
4+
5+
6+
==== tests/cases/conformance/salsa/test.js (2 errors) ====
7+
/** @typedef {{
8+
status: 'done'
9+
m(n: number): void
10+
}} DoneStatus */
11+
12+
// property assignment
13+
var ns = {}
14+
/** @type {DoneStatus} */
15+
ns.x = {
16+
status: 'done',
17+
m(n) { }
18+
}
19+
20+
ns.x = {
21+
status: 'done',
22+
m(n) { }
23+
}
24+
ns.x
25+
26+
27+
// this-property assignment
28+
class Thing {
29+
constructor() {
30+
/** @type {DoneStatus} */
31+
this.s = {
32+
status: 'done',
33+
m(n) { }
34+
}
35+
}
36+
37+
fail() {
38+
this.s = {
39+
status: 'done',
40+
m(n) { }
41+
}
42+
}
43+
}
44+
45+
// exports-property assignment
46+
47+
/** @type {DoneStatus} */
48+
exports.x = {
49+
status: "done",
50+
m(n) { }
51+
}
52+
exports.x
53+
54+
/** @type {DoneStatus} contextual typing is allowed, but module.exports.y: any.
55+
Guess it doesn't check the type tag? */
56+
module.exports.y = {
57+
status: "done",
58+
m(n) { }
59+
~
60+
!!! error TS7006: Parameter 'n' implicitly has an 'any' type.
61+
}
62+
module.exports.y
63+
64+
// prototype-property assignment
65+
/** @type {DoneStatus} */
66+
Thing.prototype.x = {
67+
status: 'done',
68+
m(n) { }
69+
}
70+
Thing.prototype.x
71+
72+
// prototype assignment
73+
function F() {
74+
}
75+
/** @type {DoneStatus} */
76+
F.prototype = {
77+
status: "done",
78+
m(n) { }
79+
~
80+
!!! error TS7006: Parameter 'n' implicitly has an 'any' type.
81+
}
82+
83+
==== tests/cases/conformance/salsa/mod.js (1 errors) ====
84+
// module.exports assignment
85+
/** @type {{ status: 'done' }} */
86+
module.exports = {
87+
status: "done",
88+
m(n) { }
89+
~
90+
!!! error TS7006: Parameter 'n' implicitly has an 'any' type.
91+
}
92+
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
=== tests/cases/conformance/salsa/test.js ===
2+
/** @typedef {{
3+
status: 'done'
4+
m(n: number): void
5+
}} DoneStatus */
6+
7+
// property assignment
8+
var ns = {}
9+
>ns : Symbol(ns, Decl(test.js, 6, 3))
10+
11+
/** @type {DoneStatus} */
12+
ns.x = {
13+
>ns.x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
14+
>ns : Symbol(ns, Decl(test.js, 6, 3))
15+
>x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
16+
17+
status: 'done',
18+
>status : Symbol(status, Decl(test.js, 8, 8))
19+
20+
m(n) { }
21+
>m : Symbol(m, Decl(test.js, 9, 19))
22+
>n : Symbol(n, Decl(test.js, 10, 6))
23+
}
24+
25+
ns.x = {
26+
>ns.x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
27+
>ns : Symbol(ns, Decl(test.js, 6, 3))
28+
>x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
29+
30+
status: 'done',
31+
>status : Symbol(status, Decl(test.js, 13, 8))
32+
33+
m(n) { }
34+
>m : Symbol(m, Decl(test.js, 14, 19))
35+
>n : Symbol(n, Decl(test.js, 15, 6))
36+
}
37+
ns.x
38+
>ns.x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
39+
>ns : Symbol(ns, Decl(test.js, 6, 3))
40+
>x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
41+
42+
43+
// this-property assignment
44+
class Thing {
45+
>Thing : Symbol(Thing, Decl(test.js, 17, 4))
46+
47+
constructor() {
48+
/** @type {DoneStatus} */
49+
this.s = {
50+
>this.s : Symbol(Thing.s, Decl(test.js, 22, 19), Decl(test.js, 30, 12))
51+
>this : Symbol(Thing, Decl(test.js, 17, 4))
52+
>s : Symbol(Thing.s, Decl(test.js, 22, 19), Decl(test.js, 30, 12))
53+
54+
status: 'done',
55+
>status : Symbol(status, Decl(test.js, 24, 18))
56+
57+
m(n) { }
58+
>m : Symbol(m, Decl(test.js, 25, 27))
59+
>n : Symbol(n, Decl(test.js, 26, 14))
60+
}
61+
}
62+
63+
fail() {
64+
>fail : Symbol(Thing.fail, Decl(test.js, 28, 5))
65+
66+
this.s = {
67+
>this.s : Symbol(Thing.s, Decl(test.js, 22, 19), Decl(test.js, 30, 12))
68+
>this : Symbol(Thing, Decl(test.js, 17, 4))
69+
>s : Symbol(Thing.s, Decl(test.js, 22, 19), Decl(test.js, 30, 12))
70+
71+
status: 'done',
72+
>status : Symbol(status, Decl(test.js, 31, 18))
73+
74+
m(n) { }
75+
>m : Symbol(m, Decl(test.js, 32, 27))
76+
>n : Symbol(n, Decl(test.js, 33, 14))
77+
}
78+
}
79+
}
80+
81+
// exports-property assignment
82+
83+
/** @type {DoneStatus} */
84+
exports.x = {
85+
>exports.x : Symbol(x, Decl(test.js, 36, 1))
86+
>exports : Symbol(x, Decl(test.js, 36, 1))
87+
>x : Symbol(x, Decl(test.js, 36, 1))
88+
89+
status: "done",
90+
>status : Symbol(status, Decl(test.js, 41, 13))
91+
92+
m(n) { }
93+
>m : Symbol(m, Decl(test.js, 42, 19))
94+
>n : Symbol(n, Decl(test.js, 43, 6))
95+
}
96+
exports.x
97+
>exports.x : Symbol(x, Decl(test.js, 36, 1))
98+
>exports : Symbol("tests/cases/conformance/salsa/test", Decl(test.js, 0, 0))
99+
>x : Symbol(x, Decl(test.js, 36, 1))
100+
101+
/** @type {DoneStatus} contextual typing is allowed, but module.exports.y: any.
102+
Guess it doesn't check the type tag? */
103+
module.exports.y = {
104+
>module.exports : Symbol(y, Decl(test.js, 45, 9))
105+
>module : Symbol(module)
106+
>y : Symbol(y, Decl(test.js, 45, 9))
107+
108+
status: "done",
109+
>status : Symbol(status, Decl(test.js, 49, 20))
110+
111+
m(n) { }
112+
>m : Symbol(m, Decl(test.js, 50, 19))
113+
>n : Symbol(n, Decl(test.js, 51, 6))
114+
}
115+
module.exports.y
116+
>module : Symbol(module)
117+
118+
// prototype-property assignment
119+
/** @type {DoneStatus} */
120+
Thing.prototype.x = {
121+
>Thing.prototype.x : Symbol(Thing.x, Decl(test.js, 53, 16))
122+
>Thing.prototype : Symbol(Thing.x, Decl(test.js, 53, 16))
123+
>Thing : Symbol(Thing, Decl(test.js, 17, 4))
124+
>prototype : Symbol(Thing.prototype)
125+
>x : Symbol(Thing.x, Decl(test.js, 53, 16))
126+
127+
status: 'done',
128+
>status : Symbol(status, Decl(test.js, 57, 21))
129+
130+
m(n) { }
131+
>m : Symbol(m, Decl(test.js, 58, 19))
132+
>n : Symbol(n, Decl(test.js, 59, 6))
133+
}
134+
Thing.prototype.x
135+
>Thing.prototype.x : Symbol(Thing.x, Decl(test.js, 53, 16))
136+
>Thing.prototype : Symbol(Thing.prototype)
137+
>Thing : Symbol(Thing, Decl(test.js, 17, 4))
138+
>prototype : Symbol(Thing.prototype)
139+
>x : Symbol(Thing.x, Decl(test.js, 53, 16))
140+
141+
// prototype assignment
142+
function F() {
143+
>F : Symbol(F, Decl(test.js, 61, 17), Decl(test.js, 65, 1))
144+
}
145+
/** @type {DoneStatus} */
146+
F.prototype = {
147+
>F.prototype : Symbol(F.prototype, Decl(test.js, 65, 1))
148+
>F : Symbol(F, Decl(test.js, 61, 17), Decl(test.js, 65, 1))
149+
>prototype : Symbol(F.prototype, Decl(test.js, 65, 1))
150+
151+
status: "done",
152+
>status : Symbol(status, Decl(test.js, 67, 15))
153+
154+
m(n) { }
155+
>m : Symbol(m, Decl(test.js, 68, 19))
156+
>n : Symbol(n, Decl(test.js, 69, 6))
157+
}
158+
159+
=== tests/cases/conformance/salsa/mod.js ===
160+
// module.exports assignment
161+
/** @type {{ status: 'done' }} */
162+
module.exports = {
163+
>module : Symbol(export=, Decl(mod.js, 0, 0))
164+
>exports : Symbol(export=, Decl(mod.js, 0, 0))
165+
166+
status: "done",
167+
>status : Symbol(status, Decl(mod.js, 2, 18))
168+
169+
m(n) { }
170+
>m : Symbol(m, Decl(mod.js, 3, 19))
171+
>n : Symbol(n, Decl(mod.js, 4, 6))
172+
}
173+

0 commit comments

Comments
 (0)