Skip to content

Commit ef9f404

Browse files
committed
Merge pull request #6091 from Microsoft/circularTypeofIssue
Fix circular typeof issue in function/namespace combo
2 parents 87036fe + 3c8ad42 commit ef9f404

File tree

5 files changed

+128
-25
lines changed

5 files changed

+128
-25
lines changed

Diff for: src/compiler/checker.ts

+23-25
Original file line numberDiff line numberDiff line change
@@ -3608,37 +3608,29 @@ namespace ts {
36083608

36093609
function resolveAnonymousTypeMembers(type: AnonymousType) {
36103610
const symbol = type.symbol;
3611-
let members: SymbolTable;
3612-
let callSignatures: Signature[];
3613-
let constructSignatures: Signature[];
3614-
let stringIndexType: Type;
3615-
let numberIndexType: Type;
3616-
36173611
if (type.target) {
3618-
members = createInstantiatedSymbolTable(getPropertiesOfObjectType(type.target), type.mapper, /*mappingThisOnly*/ false);
3619-
callSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper, instantiateSignature);
3620-
constructSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper, instantiateSignature);
3621-
stringIndexType = instantiateType(getIndexTypeOfType(type.target, IndexKind.String), type.mapper);
3622-
numberIndexType = instantiateType(getIndexTypeOfType(type.target, IndexKind.Number), type.mapper);
3612+
const members = createInstantiatedSymbolTable(getPropertiesOfObjectType(type.target), type.mapper, /*mappingThisOnly*/ false);
3613+
const callSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper, instantiateSignature);
3614+
const constructSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper, instantiateSignature);
3615+
const stringIndexType = instantiateType(getIndexTypeOfType(type.target, IndexKind.String), type.mapper);
3616+
const numberIndexType = instantiateType(getIndexTypeOfType(type.target, IndexKind.Number), type.mapper);
3617+
setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
36233618
}
36243619
else if (symbol.flags & SymbolFlags.TypeLiteral) {
3625-
members = symbol.members;
3626-
callSignatures = getSignaturesOfSymbol(members["__call"]);
3627-
constructSignatures = getSignaturesOfSymbol(members["__new"]);
3628-
stringIndexType = getIndexTypeOfSymbol(symbol, IndexKind.String);
3629-
numberIndexType = getIndexTypeOfSymbol(symbol, IndexKind.Number);
3620+
const members = symbol.members;
3621+
const callSignatures = getSignaturesOfSymbol(members["__call"]);
3622+
const constructSignatures = getSignaturesOfSymbol(members["__new"]);
3623+
const stringIndexType = getIndexTypeOfSymbol(symbol, IndexKind.String);
3624+
const numberIndexType = getIndexTypeOfSymbol(symbol, IndexKind.Number);
3625+
setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
36303626
}
36313627
else {
36323628
// Combinations of function, class, enum and module
3633-
members = emptySymbols;
3634-
callSignatures = emptyArray;
3635-
constructSignatures = emptyArray;
3629+
let members = emptySymbols;
3630+
let constructSignatures: Signature[] = emptyArray;
36363631
if (symbol.flags & SymbolFlags.HasExports) {
36373632
members = getExportsOfSymbol(symbol);
36383633
}
3639-
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) {
3640-
callSignatures = getSignaturesOfSymbol(symbol);
3641-
}
36423634
if (symbol.flags & SymbolFlags.Class) {
36433635
const classType = getDeclaredTypeOfClassOrInterface(symbol);
36443636
constructSignatures = getSignaturesOfSymbol(symbol.members["__constructor"]);
@@ -3651,10 +3643,16 @@ namespace ts {
36513643
addInheritedMembers(members, getPropertiesOfObjectType(baseConstructorType));
36523644
}
36533645
}
3654-
stringIndexType = undefined;
3655-
numberIndexType = (symbol.flags & SymbolFlags.Enum) ? stringType : undefined;
3646+
const numberIndexType = (symbol.flags & SymbolFlags.Enum) ? stringType : undefined;
3647+
setObjectTypeMembers(type, members, emptyArray, constructSignatures, undefined, numberIndexType);
3648+
// We resolve the members before computing the signatures because a signature may use
3649+
// typeof with a qualified name expression that circularly references the type we are
3650+
// in the process of resolving (see issue #6072). The temporarily empty signature list
3651+
// will never be observed because a qualified name can't reference signatures.
3652+
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) {
3653+
(<ResolvedType>type).callSignatures = getSignaturesOfSymbol(symbol);
3654+
}
36563655
}
3657-
setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
36583656
}
36593657

36603658
function resolveStructuredTypeMembers(type: ObjectType): ResolvedType {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//// [circularTypeofWithFunctionModule.ts]
2+
// Repro from #6072
3+
4+
class Foo {}
5+
6+
function maker (value: string): typeof maker.Bar {
7+
return maker.Bar;
8+
}
9+
10+
namespace maker {
11+
export class Bar extends Foo {}
12+
}
13+
14+
15+
//// [circularTypeofWithFunctionModule.js]
16+
// Repro from #6072
17+
var __extends = (this && this.__extends) || function (d, b) {
18+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
19+
function __() { this.constructor = d; }
20+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
21+
};
22+
var Foo = (function () {
23+
function Foo() {
24+
}
25+
return Foo;
26+
}());
27+
function maker(value) {
28+
return maker.Bar;
29+
}
30+
var maker;
31+
(function (maker) {
32+
var Bar = (function (_super) {
33+
__extends(Bar, _super);
34+
function Bar() {
35+
_super.apply(this, arguments);
36+
}
37+
return Bar;
38+
}(Foo));
39+
maker.Bar = Bar;
40+
})(maker || (maker = {}));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
=== tests/cases/compiler/circularTypeofWithFunctionModule.ts ===
2+
// Repro from #6072
3+
4+
class Foo {}
5+
>Foo : Symbol(Foo, Decl(circularTypeofWithFunctionModule.ts, 0, 0))
6+
7+
function maker (value: string): typeof maker.Bar {
8+
>maker : Symbol(maker, Decl(circularTypeofWithFunctionModule.ts, 2, 12), Decl(circularTypeofWithFunctionModule.ts, 6, 1))
9+
>value : Symbol(value, Decl(circularTypeofWithFunctionModule.ts, 4, 16))
10+
>maker.Bar : Symbol(maker.Bar, Decl(circularTypeofWithFunctionModule.ts, 8, 17))
11+
>maker : Symbol(maker, Decl(circularTypeofWithFunctionModule.ts, 2, 12), Decl(circularTypeofWithFunctionModule.ts, 6, 1))
12+
>Bar : Symbol(maker.Bar, Decl(circularTypeofWithFunctionModule.ts, 8, 17))
13+
14+
return maker.Bar;
15+
>maker.Bar : Symbol(maker.Bar, Decl(circularTypeofWithFunctionModule.ts, 8, 17))
16+
>maker : Symbol(maker, Decl(circularTypeofWithFunctionModule.ts, 2, 12), Decl(circularTypeofWithFunctionModule.ts, 6, 1))
17+
>Bar : Symbol(maker.Bar, Decl(circularTypeofWithFunctionModule.ts, 8, 17))
18+
}
19+
20+
namespace maker {
21+
>maker : Symbol(maker, Decl(circularTypeofWithFunctionModule.ts, 2, 12), Decl(circularTypeofWithFunctionModule.ts, 6, 1))
22+
23+
export class Bar extends Foo {}
24+
>Bar : Symbol(Bar, Decl(circularTypeofWithFunctionModule.ts, 8, 17))
25+
>Foo : Symbol(Foo, Decl(circularTypeofWithFunctionModule.ts, 0, 0))
26+
}
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
=== tests/cases/compiler/circularTypeofWithFunctionModule.ts ===
2+
// Repro from #6072
3+
4+
class Foo {}
5+
>Foo : Foo
6+
7+
function maker (value: string): typeof maker.Bar {
8+
>maker : typeof maker
9+
>value : string
10+
>maker.Bar : typeof maker.Bar
11+
>maker : typeof maker
12+
>Bar : typeof maker.Bar
13+
14+
return maker.Bar;
15+
>maker.Bar : typeof maker.Bar
16+
>maker : typeof maker
17+
>Bar : typeof maker.Bar
18+
}
19+
20+
namespace maker {
21+
>maker : typeof maker
22+
23+
export class Bar extends Foo {}
24+
>Bar : Bar
25+
>Foo : Foo
26+
}
27+
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Repro from #6072
2+
3+
class Foo {}
4+
5+
function maker (value: string): typeof maker.Bar {
6+
return maker.Bar;
7+
}
8+
9+
namespace maker {
10+
export class Bar extends Foo {}
11+
}

0 commit comments

Comments
 (0)