diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 81d4857ad073a..74c745df1dc41 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2465,7 +2465,7 @@ namespace ts { node.left.parent = node; node.right.parent = node; const lhs = node.left as PropertyAccessEntityNameExpression; - bindPropertyAssignment(lhs, lhs, /*isPrototypeProperty*/ false); + bindPropertyAssignment(lhs.expression, lhs, /*isPrototypeProperty*/ false); } /** @@ -2522,7 +2522,7 @@ namespace ts { const isToplevel = isBinaryExpression(propertyAccess.parent) ? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile : propertyAccess.parent.parent.kind === SyntaxKind.SourceFile; - if (!isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace)) && isToplevel) { + if (isToplevel && !isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace))) { // make symbols or add declarations for intermediate containers const flags = SymbolFlags.Module | SymbolFlags.Assignment; const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.Assignment; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3e9a33007261a..3b031198b38b6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20173,18 +20173,15 @@ namespace ts { assigned || inferred; } - function getAssignedClassType(symbol: Symbol) { + function getAssignedClassType(symbol: Symbol): Type | undefined { const decl = symbol.valueDeclaration; const assignmentSymbol = decl && decl.parent && (isFunctionDeclaration(decl) && getSymbolOfNode(decl) || isBinaryExpression(decl.parent) && getSymbolOfNode(decl.parent.left) || isVariableDeclaration(decl.parent) && getSymbolOfNode(decl.parent)); - if (assignmentSymbol) { - const prototype = forEach(assignmentSymbol.declarations, getAssignedJSPrototype); - if (prototype) { - return checkExpression(prototype); - } - } + const prototype = assignmentSymbol && assignmentSymbol.exports && assignmentSymbol.exports.get("prototype" as __String); + const init = prototype && getAssignedJSPrototype(prototype.valueDeclaration); + return init ? checkExpression(init) : undefined; } function getAssignedJSPrototype(node: Node) { diff --git a/tests/baselines/reference/typeFromPrototypeAssignment2.errors.txt b/tests/baselines/reference/typeFromPrototypeAssignment2.errors.txt new file mode 100644 index 0000000000000..d4f66132d44a0 --- /dev/null +++ b/tests/baselines/reference/typeFromPrototypeAssignment2.errors.txt @@ -0,0 +1,47 @@ +tests/cases/conformance/salsa/a.js(28,24): error TS2339: Property 'addon' does not exist on type '{ set: () => void; get(): void; }'. + + +==== tests/cases/conformance/salsa/a.js (1 errors) ==== + // non top-level: + // all references to _map, set, get, addon should be ok + (function container() { + /** @constructor */ + var Multimap = function() { + this._map = {}; + this._map + this.set + this.get + this.addon + }; + + Multimap.prototype = { + set: function() { + this._map + this.set + this.get + this.addon + }, + get() { + this._map + this.set + this.get + this.addon + } + } + + Multimap.prototype.addon = function () { + ~~~~~ +!!! error TS2339: Property 'addon' does not exist on type '{ set: () => void; get(): void; }'. + this._map + this.set + this.get + this.addon + } + + var mm = new Multimap(); + mm._map + mm.set + mm.get + mm.addon + }); + \ No newline at end of file diff --git a/tests/baselines/reference/typeFromPrototypeAssignment2.symbols b/tests/baselines/reference/typeFromPrototypeAssignment2.symbols new file mode 100644 index 0000000000000..25ae9e31c698b --- /dev/null +++ b/tests/baselines/reference/typeFromPrototypeAssignment2.symbols @@ -0,0 +1,127 @@ +=== tests/cases/conformance/salsa/a.js === +// non top-level: +// all references to _map, set, get, addon should be ok +(function container() { +>container : Symbol(container, Decl(a.js, 2, 1)) + + /** @constructor */ + var Multimap = function() { +>Multimap : Symbol(Multimap, Decl(a.js, 4, 7)) + + this._map = {}; +>this._map : Symbol(Multimap._map, Decl(a.js, 4, 31)) +>_map : Symbol(Multimap._map, Decl(a.js, 4, 31)) + + this._map +>this._map : Symbol(Multimap._map, Decl(a.js, 4, 31)) +>_map : Symbol(Multimap._map, Decl(a.js, 4, 31)) + + this.set +>this.set : Symbol(set, Decl(a.js, 12, 26)) +>set : Symbol(set, Decl(a.js, 12, 26)) + + this.get +>this.get : Symbol(get, Decl(a.js, 18, 10)) +>get : Symbol(get, Decl(a.js, 18, 10)) + + this.addon +>this.addon : Symbol(Multimap.addon, Decl(a.js, 25, 5)) +>addon : Symbol(Multimap.addon, Decl(a.js, 25, 5)) + + }; + + Multimap.prototype = { +>Multimap.prototype : Symbol(Multimap.prototype, Decl(a.js, 10, 6)) +>Multimap : Symbol(Multimap, Decl(a.js, 4, 7)) +>prototype : Symbol(Multimap.prototype, Decl(a.js, 10, 6)) + + set: function() { +>set : Symbol(set, Decl(a.js, 12, 26)) + + this._map +>this._map : Symbol(Multimap._map, Decl(a.js, 4, 31)) +>_map : Symbol(Multimap._map, Decl(a.js, 4, 31)) + + this.set +>this.set : Symbol(set, Decl(a.js, 12, 26)) +>set : Symbol(set, Decl(a.js, 12, 26)) + + this.get +>this.get : Symbol(get, Decl(a.js, 18, 10)) +>get : Symbol(get, Decl(a.js, 18, 10)) + + this.addon +>this.addon : Symbol(Multimap.addon, Decl(a.js, 25, 5)) +>addon : Symbol(Multimap.addon, Decl(a.js, 25, 5)) + + }, + get() { +>get : Symbol(get, Decl(a.js, 18, 10)) + + this._map +>this._map : Symbol(Multimap._map, Decl(a.js, 4, 31)) +>_map : Symbol(Multimap._map, Decl(a.js, 4, 31)) + + this.set +>this.set : Symbol(set, Decl(a.js, 12, 26)) +>set : Symbol(set, Decl(a.js, 12, 26)) + + this.get +>this.get : Symbol(get, Decl(a.js, 18, 10)) +>get : Symbol(get, Decl(a.js, 18, 10)) + + this.addon +>this.addon : Symbol(Multimap.addon, Decl(a.js, 25, 5)) +>addon : Symbol(Multimap.addon, Decl(a.js, 25, 5)) + } + } + + Multimap.prototype.addon = function () { +>Multimap.prototype : Symbol(Multimap.addon, Decl(a.js, 25, 5)) +>Multimap : Symbol(Multimap, Decl(a.js, 4, 7)) +>prototype : Symbol(Multimap.prototype, Decl(a.js, 10, 6)) +>addon : Symbol(Multimap.addon, Decl(a.js, 25, 5)) + + this._map +>this._map : Symbol(Multimap._map, Decl(a.js, 4, 31)) +>_map : Symbol(Multimap._map, Decl(a.js, 4, 31)) + + this.set +>this.set : Symbol(set, Decl(a.js, 12, 26)) +>set : Symbol(set, Decl(a.js, 12, 26)) + + this.get +>this.get : Symbol(get, Decl(a.js, 18, 10)) +>get : Symbol(get, Decl(a.js, 18, 10)) + + this.addon +>this.addon : Symbol(Multimap.addon, Decl(a.js, 25, 5)) +>addon : Symbol(Multimap.addon, Decl(a.js, 25, 5)) + } + + var mm = new Multimap(); +>mm : Symbol(mm, Decl(a.js, 34, 7)) +>Multimap : Symbol(Multimap, Decl(a.js, 4, 7)) + + mm._map +>mm._map : Symbol(Multimap._map, Decl(a.js, 4, 31)) +>mm : Symbol(mm, Decl(a.js, 34, 7)) +>_map : Symbol(Multimap._map, Decl(a.js, 4, 31)) + + mm.set +>mm.set : Symbol(set, Decl(a.js, 12, 26)) +>mm : Symbol(mm, Decl(a.js, 34, 7)) +>set : Symbol(set, Decl(a.js, 12, 26)) + + mm.get +>mm.get : Symbol(get, Decl(a.js, 18, 10)) +>mm : Symbol(mm, Decl(a.js, 34, 7)) +>get : Symbol(get, Decl(a.js, 18, 10)) + + mm.addon +>mm.addon : Symbol(Multimap.addon, Decl(a.js, 25, 5)) +>mm : Symbol(mm, Decl(a.js, 34, 7)) +>addon : Symbol(Multimap.addon, Decl(a.js, 25, 5)) + +}); + diff --git a/tests/baselines/reference/typeFromPrototypeAssignment2.types b/tests/baselines/reference/typeFromPrototypeAssignment2.types new file mode 100644 index 0000000000000..d37f421a356e8 --- /dev/null +++ b/tests/baselines/reference/typeFromPrototypeAssignment2.types @@ -0,0 +1,156 @@ +=== tests/cases/conformance/salsa/a.js === +// non top-level: +// all references to _map, set, get, addon should be ok +(function container() { +>(function container() { /** @constructor */ var Multimap = function() { this._map = {}; this._map this.set this.get this.addon }; Multimap.prototype = { set: function() { this._map this.set this.get this.addon }, get() { this._map this.set this.get this.addon } } Multimap.prototype.addon = function () { this._map this.set this.get this.addon } var mm = new Multimap(); mm._map mm.set mm.get mm.addon}) : () => void +>function container() { /** @constructor */ var Multimap = function() { this._map = {}; this._map this.set this.get this.addon }; Multimap.prototype = { set: function() { this._map this.set this.get this.addon }, get() { this._map this.set this.get this.addon } } Multimap.prototype.addon = function () { this._map this.set this.get this.addon } var mm = new Multimap(); mm._map mm.set mm.get mm.addon} : () => void +>container : () => void + + /** @constructor */ + var Multimap = function() { +>Multimap : typeof Multimap +>function() { this._map = {}; this._map this.set this.get this.addon } : typeof Multimap + + this._map = {}; +>this._map = {} : {} +>this._map : {} +>this : Multimap & { set: () => void; get(): void; } +>_map : {} +>{} : {} + + this._map +>this._map : {} +>this : Multimap & { set: () => void; get(): void; } +>_map : {} + + this.set +>this.set : () => void +>this : Multimap & { set: () => void; get(): void; } +>set : () => void + + this.get +>this.get : () => void +>this : Multimap & { set: () => void; get(): void; } +>get : () => void + + this.addon +>this.addon : () => void +>this : Multimap & { set: () => void; get(): void; } +>addon : () => void + + }; + + Multimap.prototype = { +>Multimap.prototype = { set: function() { this._map this.set this.get this.addon }, get() { this._map this.set this.get this.addon } } : { set: () => void; get(): void; } +>Multimap.prototype : { set: () => void; get(): void; } +>Multimap : typeof Multimap +>prototype : { set: () => void; get(): void; } +>{ set: function() { this._map this.set this.get this.addon }, get() { this._map this.set this.get this.addon } } : { set: () => void; get(): void; } + + set: function() { +>set : () => void +>function() { this._map this.set this.get this.addon } : () => void + + this._map +>this._map : {} +>this : Multimap & { set: () => void; get(): void; } +>_map : {} + + this.set +>this.set : () => void +>this : Multimap & { set: () => void; get(): void; } +>set : () => void + + this.get +>this.get : () => void +>this : Multimap & { set: () => void; get(): void; } +>get : () => void + + this.addon +>this.addon : () => void +>this : Multimap & { set: () => void; get(): void; } +>addon : () => void + + }, + get() { +>get : () => void + + this._map +>this._map : {} +>this : Multimap & { set: () => void; get(): void; } +>_map : {} + + this.set +>this.set : () => void +>this : Multimap & { set: () => void; get(): void; } +>set : () => void + + this.get +>this.get : () => void +>this : Multimap & { set: () => void; get(): void; } +>get : () => void + + this.addon +>this.addon : () => void +>this : Multimap & { set: () => void; get(): void; } +>addon : () => void + } + } + + Multimap.prototype.addon = function () { +>Multimap.prototype.addon = function () { this._map this.set this.get this.addon } : () => void +>Multimap.prototype.addon : any +>Multimap.prototype : { set: () => void; get(): void; } +>Multimap : typeof Multimap +>prototype : { set: () => void; get(): void; } +>addon : any +>function () { this._map this.set this.get this.addon } : () => void + + this._map +>this._map : {} +>this : Multimap & { set: () => void; get(): void; } +>_map : {} + + this.set +>this.set : () => void +>this : Multimap & { set: () => void; get(): void; } +>set : () => void + + this.get +>this.get : () => void +>this : Multimap & { set: () => void; get(): void; } +>get : () => void + + this.addon +>this.addon : () => void +>this : Multimap & { set: () => void; get(): void; } +>addon : () => void + } + + var mm = new Multimap(); +>mm : Multimap & { set: () => void; get(): void; } +>new Multimap() : Multimap & { set: () => void; get(): void; } +>Multimap : typeof Multimap + + mm._map +>mm._map : {} +>mm : Multimap & { set: () => void; get(): void; } +>_map : {} + + mm.set +>mm.set : () => void +>mm : Multimap & { set: () => void; get(): void; } +>set : () => void + + mm.get +>mm.get : () => void +>mm : Multimap & { set: () => void; get(): void; } +>get : () => void + + mm.addon +>mm.addon : () => void +>mm : Multimap & { set: () => void; get(): void; } +>addon : () => void + +}); + diff --git a/tests/cases/conformance/salsa/typeFromPrototypeAssignment2.ts b/tests/cases/conformance/salsa/typeFromPrototypeAssignment2.ts new file mode 100644 index 0000000000000..68966c923d5c8 --- /dev/null +++ b/tests/cases/conformance/salsa/typeFromPrototypeAssignment2.ts @@ -0,0 +1,46 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @Filename: a.js +// @strict: true + +// non top-level: +// all references to _map, set, get, addon should be ok +(function container() { + /** @constructor */ + var Multimap = function() { + this._map = {}; + this._map + this.set + this.get + this.addon + }; + + Multimap.prototype = { + set: function() { + this._map + this.set + this.get + this.addon + }, + get() { + this._map + this.set + this.get + this.addon + } + } + + Multimap.prototype.addon = function () { + this._map + this.set + this.get + this.addon + } + + var mm = new Multimap(); + mm._map + mm.set + mm.get + mm.addon +});