From e354aec8a38a4a173fce8b242af3484bc9e72bb4 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 13 Dec 2015 18:25:45 -0800 Subject: [PATCH 1/2] Mark anonymous type as resolved before resolving call signatures --- src/compiler/checker.ts | 48 ++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ea23255472d2a..cf52531d6f525 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3608,37 +3608,29 @@ namespace ts { function resolveAnonymousTypeMembers(type: AnonymousType) { const symbol = type.symbol; - let members: SymbolTable; - let callSignatures: Signature[]; - let constructSignatures: Signature[]; - let stringIndexType: Type; - let numberIndexType: Type; - if (type.target) { - members = createInstantiatedSymbolTable(getPropertiesOfObjectType(type.target), type.mapper, /*mappingThisOnly*/ false); - callSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper, instantiateSignature); - constructSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper, instantiateSignature); - stringIndexType = instantiateType(getIndexTypeOfType(type.target, IndexKind.String), type.mapper); - numberIndexType = instantiateType(getIndexTypeOfType(type.target, IndexKind.Number), type.mapper); + const members = createInstantiatedSymbolTable(getPropertiesOfObjectType(type.target), type.mapper, /*mappingThisOnly*/ false); + const callSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper, instantiateSignature); + const constructSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper, instantiateSignature); + const stringIndexType = instantiateType(getIndexTypeOfType(type.target, IndexKind.String), type.mapper); + const numberIndexType = instantiateType(getIndexTypeOfType(type.target, IndexKind.Number), type.mapper); + setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType); } else if (symbol.flags & SymbolFlags.TypeLiteral) { - members = symbol.members; - callSignatures = getSignaturesOfSymbol(members["__call"]); - constructSignatures = getSignaturesOfSymbol(members["__new"]); - stringIndexType = getIndexTypeOfSymbol(symbol, IndexKind.String); - numberIndexType = getIndexTypeOfSymbol(symbol, IndexKind.Number); + const members = symbol.members; + const callSignatures = getSignaturesOfSymbol(members["__call"]); + const constructSignatures = getSignaturesOfSymbol(members["__new"]); + const stringIndexType = getIndexTypeOfSymbol(symbol, IndexKind.String); + const numberIndexType = getIndexTypeOfSymbol(symbol, IndexKind.Number); + setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType); } else { // Combinations of function, class, enum and module - members = emptySymbols; - callSignatures = emptyArray; - constructSignatures = emptyArray; + let members = emptySymbols; + let constructSignatures: Signature[] = emptyArray; if (symbol.flags & SymbolFlags.HasExports) { members = getExportsOfSymbol(symbol); } - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) { - callSignatures = getSignaturesOfSymbol(symbol); - } if (symbol.flags & SymbolFlags.Class) { const classType = getDeclaredTypeOfClassOrInterface(symbol); constructSignatures = getSignaturesOfSymbol(symbol.members["__constructor"]); @@ -3651,10 +3643,16 @@ namespace ts { addInheritedMembers(members, getPropertiesOfObjectType(baseConstructorType)); } } - stringIndexType = undefined; - numberIndexType = (symbol.flags & SymbolFlags.Enum) ? stringType : undefined; + const numberIndexType = (symbol.flags & SymbolFlags.Enum) ? stringType : undefined; + setObjectTypeMembers(type, members, emptyArray, constructSignatures, undefined, numberIndexType); + // We resolve the members before computing the signatures because a signature may use + // typeof with a qualified name expression that circularly references the type we are + // in the process of resolving (see issue #6072). The temporarily empty signature list + // will never be observed because a qualified name can't reference signatures. + if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) { + (type).callSignatures = getSignaturesOfSymbol(symbol); + } } - setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType); } function resolveStructuredTypeMembers(type: ObjectType): ResolvedType { From 3c8ad42a62021a1aa1a76851b059b61f72b17b31 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 13 Dec 2015 18:32:46 -0800 Subject: [PATCH 2/2] Adding regression test --- .../circularTypeofWithFunctionModule.js | 40 +++++++++++++++++++ .../circularTypeofWithFunctionModule.symbols | 27 +++++++++++++ .../circularTypeofWithFunctionModule.types | 27 +++++++++++++ .../circularTypeofWithFunctionModule.ts | 11 +++++ 4 files changed, 105 insertions(+) create mode 100644 tests/baselines/reference/circularTypeofWithFunctionModule.js create mode 100644 tests/baselines/reference/circularTypeofWithFunctionModule.symbols create mode 100644 tests/baselines/reference/circularTypeofWithFunctionModule.types create mode 100644 tests/cases/compiler/circularTypeofWithFunctionModule.ts diff --git a/tests/baselines/reference/circularTypeofWithFunctionModule.js b/tests/baselines/reference/circularTypeofWithFunctionModule.js new file mode 100644 index 0000000000000..6ce1dd62fc5d7 --- /dev/null +++ b/tests/baselines/reference/circularTypeofWithFunctionModule.js @@ -0,0 +1,40 @@ +//// [circularTypeofWithFunctionModule.ts] +// Repro from #6072 + +class Foo {} + +function maker (value: string): typeof maker.Bar { + return maker.Bar; +} + +namespace maker { + export class Bar extends Foo {} +} + + +//// [circularTypeofWithFunctionModule.js] +// Repro from #6072 +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var Foo = (function () { + function Foo() { + } + return Foo; +}()); +function maker(value) { + return maker.Bar; +} +var maker; +(function (maker) { + var Bar = (function (_super) { + __extends(Bar, _super); + function Bar() { + _super.apply(this, arguments); + } + return Bar; + }(Foo)); + maker.Bar = Bar; +})(maker || (maker = {})); diff --git a/tests/baselines/reference/circularTypeofWithFunctionModule.symbols b/tests/baselines/reference/circularTypeofWithFunctionModule.symbols new file mode 100644 index 0000000000000..19dde10852f69 --- /dev/null +++ b/tests/baselines/reference/circularTypeofWithFunctionModule.symbols @@ -0,0 +1,27 @@ +=== tests/cases/compiler/circularTypeofWithFunctionModule.ts === +// Repro from #6072 + +class Foo {} +>Foo : Symbol(Foo, Decl(circularTypeofWithFunctionModule.ts, 0, 0)) + +function maker (value: string): typeof maker.Bar { +>maker : Symbol(maker, Decl(circularTypeofWithFunctionModule.ts, 2, 12), Decl(circularTypeofWithFunctionModule.ts, 6, 1)) +>value : Symbol(value, Decl(circularTypeofWithFunctionModule.ts, 4, 16)) +>maker.Bar : Symbol(maker.Bar, Decl(circularTypeofWithFunctionModule.ts, 8, 17)) +>maker : Symbol(maker, Decl(circularTypeofWithFunctionModule.ts, 2, 12), Decl(circularTypeofWithFunctionModule.ts, 6, 1)) +>Bar : Symbol(maker.Bar, Decl(circularTypeofWithFunctionModule.ts, 8, 17)) + + return maker.Bar; +>maker.Bar : Symbol(maker.Bar, Decl(circularTypeofWithFunctionModule.ts, 8, 17)) +>maker : Symbol(maker, Decl(circularTypeofWithFunctionModule.ts, 2, 12), Decl(circularTypeofWithFunctionModule.ts, 6, 1)) +>Bar : Symbol(maker.Bar, Decl(circularTypeofWithFunctionModule.ts, 8, 17)) +} + +namespace maker { +>maker : Symbol(maker, Decl(circularTypeofWithFunctionModule.ts, 2, 12), Decl(circularTypeofWithFunctionModule.ts, 6, 1)) + + export class Bar extends Foo {} +>Bar : Symbol(Bar, Decl(circularTypeofWithFunctionModule.ts, 8, 17)) +>Foo : Symbol(Foo, Decl(circularTypeofWithFunctionModule.ts, 0, 0)) +} + diff --git a/tests/baselines/reference/circularTypeofWithFunctionModule.types b/tests/baselines/reference/circularTypeofWithFunctionModule.types new file mode 100644 index 0000000000000..f1c2431bfde3e --- /dev/null +++ b/tests/baselines/reference/circularTypeofWithFunctionModule.types @@ -0,0 +1,27 @@ +=== tests/cases/compiler/circularTypeofWithFunctionModule.ts === +// Repro from #6072 + +class Foo {} +>Foo : Foo + +function maker (value: string): typeof maker.Bar { +>maker : typeof maker +>value : string +>maker.Bar : typeof maker.Bar +>maker : typeof maker +>Bar : typeof maker.Bar + + return maker.Bar; +>maker.Bar : typeof maker.Bar +>maker : typeof maker +>Bar : typeof maker.Bar +} + +namespace maker { +>maker : typeof maker + + export class Bar extends Foo {} +>Bar : Bar +>Foo : Foo +} + diff --git a/tests/cases/compiler/circularTypeofWithFunctionModule.ts b/tests/cases/compiler/circularTypeofWithFunctionModule.ts new file mode 100644 index 0000000000000..b4c9fdb9fd553 --- /dev/null +++ b/tests/cases/compiler/circularTypeofWithFunctionModule.ts @@ -0,0 +1,11 @@ +// Repro from #6072 + +class Foo {} + +function maker (value: string): typeof maker.Bar { + return maker.Bar; +} + +namespace maker { + export class Bar extends Foo {} +}