Skip to content

Commit

Permalink
Fix stack overflow when resolving default construct signatures (#17878)
Browse files Browse the repository at this point in the history
* Fix stack overflow when resolving default construct signatures

* No need for || emptyArray
  • Loading branch information
weswigham authored Aug 19, 2017
1 parent 45c62ac commit a136f55
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 6 deletions.
16 changes: 10 additions & 6 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5657,17 +5657,12 @@ namespace ts {
else {
// Combinations of function, class, enum and module
let members = emptySymbols;
let constructSignatures: Signature[] = emptyArray;
let stringIndexInfo: IndexInfo = undefined;
if (symbol.exports) {
members = getExportsOfSymbol(symbol);
}
if (symbol.flags & SymbolFlags.Class) {
const classType = getDeclaredTypeOfClassOrInterface(symbol);
constructSignatures = getSignaturesOfSymbol(symbol.members.get(InternalSymbolName.Constructor));
if (!constructSignatures.length) {
constructSignatures = getDefaultConstructSignatures(classType);
}
const baseConstructorType = getBaseConstructorTypeOfClass(classType);
if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.TypeVariable)) {
members = createSymbolTable(getNamedMembers(members));
Expand All @@ -5678,14 +5673,23 @@ namespace ts {
}
}
const numberIndexInfo = symbol.flags & SymbolFlags.Enum ? enumNumberIndexInfo : undefined;
setStructuredTypeMembers(type, members, emptyArray, constructSignatures, stringIndexInfo, numberIndexInfo);
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
// 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);
}
// And likewise for construct signatures for classes
if (symbol.flags & SymbolFlags.Class) {
const classType = getDeclaredTypeOfClassOrInterface(symbol);
let constructSignatures = getSignaturesOfSymbol(symbol.members.get(InternalSymbolName.Constructor));
if (!constructSignatures.length) {
constructSignatures = getDefaultConstructSignatures(classType);
}
(<ResolvedType>type).constructSignatures = constructSignatures;
}
}
}

Expand Down
42 changes: 42 additions & 0 deletions tests/baselines/reference/cloduleGenericOnSelfMember.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//// [cloduleGenericOnSelfMember.ts]
class ServiceBase<T> {
field: T;
}
class Service extends ServiceBase<typeof Service.Base> {
}
namespace Service {
export const Base = {
name: "1",
value: 5
};
}

//// [cloduleGenericOnSelfMember.js]
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var ServiceBase = /** @class */ (function () {
function ServiceBase() {
}
return ServiceBase;
}());
var Service = /** @class */ (function (_super) {
__extends(Service, _super);
function Service() {
return _super !== null && _super.apply(this, arguments) || this;
}
return Service;
}(ServiceBase));
(function (Service) {
Service.Base = {
name: "1",
value: 5
};
})(Service || (Service = {}));
30 changes: 30 additions & 0 deletions tests/baselines/reference/cloduleGenericOnSelfMember.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
=== tests/cases/compiler/cloduleGenericOnSelfMember.ts ===
class ServiceBase<T> {
>ServiceBase : Symbol(ServiceBase, Decl(cloduleGenericOnSelfMember.ts, 0, 0))
>T : Symbol(T, Decl(cloduleGenericOnSelfMember.ts, 0, 18))

field: T;
>field : Symbol(ServiceBase.field, Decl(cloduleGenericOnSelfMember.ts, 0, 22))
>T : Symbol(T, Decl(cloduleGenericOnSelfMember.ts, 0, 18))
}
class Service extends ServiceBase<typeof Service.Base> {
>Service : Symbol(Service, Decl(cloduleGenericOnSelfMember.ts, 2, 1), Decl(cloduleGenericOnSelfMember.ts, 4, 1))
>ServiceBase : Symbol(ServiceBase, Decl(cloduleGenericOnSelfMember.ts, 0, 0))
>Service.Base : Symbol(Service.Base, Decl(cloduleGenericOnSelfMember.ts, 6, 16))
>Service : Symbol(Service, Decl(cloduleGenericOnSelfMember.ts, 2, 1), Decl(cloduleGenericOnSelfMember.ts, 4, 1))
>Base : Symbol(Service.Base, Decl(cloduleGenericOnSelfMember.ts, 6, 16))
}
namespace Service {
>Service : Symbol(Service, Decl(cloduleGenericOnSelfMember.ts, 2, 1), Decl(cloduleGenericOnSelfMember.ts, 4, 1))

export const Base = {
>Base : Symbol(Base, Decl(cloduleGenericOnSelfMember.ts, 6, 16))

name: "1",
>name : Symbol(name, Decl(cloduleGenericOnSelfMember.ts, 6, 25))

value: 5
>value : Symbol(value, Decl(cloduleGenericOnSelfMember.ts, 7, 18))

};
}
33 changes: 33 additions & 0 deletions tests/baselines/reference/cloduleGenericOnSelfMember.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
=== tests/cases/compiler/cloduleGenericOnSelfMember.ts ===
class ServiceBase<T> {
>ServiceBase : ServiceBase<T>
>T : T

field: T;
>field : T
>T : T
}
class Service extends ServiceBase<typeof Service.Base> {
>Service : Service
>ServiceBase : ServiceBase<{ name: string; value: number; }>
>Service.Base : { name: string; value: number; }
>Service : typeof Service
>Base : { name: string; value: number; }
}
namespace Service {
>Service : typeof Service

export const Base = {
>Base : { name: string; value: number; }
>{ name: "1", value: 5 } : { name: string; value: number; }

name: "1",
>name : string
>"1" : "1"

value: 5
>value : number
>5 : 5

};
}
11 changes: 11 additions & 0 deletions tests/cases/compiler/cloduleGenericOnSelfMember.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class ServiceBase<T> {
field: T;
}
class Service extends ServiceBase<typeof Service.Base> {
}
namespace Service {
export const Base = {
name: "1",
value: 5
};
}

0 comments on commit a136f55

Please sign in to comment.