Skip to content

Fix circular typeof issue in function/namespace combo #6091

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 14, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 23 additions & 25 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"]);
Expand All @@ -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)) {
(<ResolvedType>type).callSignatures = getSignaturesOfSymbol(symbol);
}
}
setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
}

function resolveStructuredTypeMembers(type: ObjectType): ResolvedType {
Expand Down
40 changes: 40 additions & 0 deletions tests/baselines/reference/circularTypeofWithFunctionModule.js
Original file line number Diff line number Diff line change
@@ -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 = {}));
27 changes: 27 additions & 0 deletions tests/baselines/reference/circularTypeofWithFunctionModule.symbols
Original file line number Diff line number Diff line change
@@ -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))
}

27 changes: 27 additions & 0 deletions tests/baselines/reference/circularTypeofWithFunctionModule.types
Original file line number Diff line number Diff line change
@@ -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
}

11 changes: 11 additions & 0 deletions tests/cases/compiler/circularTypeofWithFunctionModule.ts
Original file line number Diff line number Diff line change
@@ -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 {}
}