Merge pull request #25336 from Microsoft/fixResolveTypeMembers

Fix runaway recursion in object type member resolution
This commit is contained in:
Anders Hejlsberg 2018-07-03 07:53:02 -10:00 committed by GitHub
commit e8d64a9c7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 114 additions and 17 deletions

View file

@ -2542,6 +2542,12 @@ namespace ts {
const type = <ObjectType>createType(TypeFlags.Object);
type.objectFlags = objectFlags;
type.symbol = symbol!;
type.members = undefined;
type.properties = undefined;
type.callSignatures = undefined;
type.constructSignatures = undefined;
type.stringIndexInfo = undefined;
type.numberIndexInfo = undefined;
return type;
}
@ -2563,11 +2569,8 @@ namespace ts {
function getNamedMembers(members: SymbolTable): Symbol[] {
let result: Symbol[] | undefined;
members.forEach((symbol, id) => {
if (!isReservedMemberName(id)) {
if (!result) result = [];
if (symbolIsValue(symbol)) {
result.push(symbol);
}
if (!isReservedMemberName(id) && symbolIsValue(symbol)) {
(result || (result = [])).push(symbol);
}
});
return result || emptyArray;
@ -2575,11 +2578,11 @@ namespace ts {
function setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: ReadonlyArray<Signature>, constructSignatures: ReadonlyArray<Signature>, stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): ResolvedType {
(<ResolvedType>type).members = members;
(<ResolvedType>type).properties = getNamedMembers(members);
(<ResolvedType>type).properties = members === emptySymbols ? emptyArray : getNamedMembers(members);
(<ResolvedType>type).callSignatures = callSignatures;
(<ResolvedType>type).constructSignatures = constructSignatures;
if (stringIndexInfo) (<ResolvedType>type).stringIndexInfo = stringIndexInfo;
if (numberIndexInfo) (<ResolvedType>type).numberIndexInfo = numberIndexInfo;
(<ResolvedType>type).stringIndexInfo = stringIndexInfo;
(<ResolvedType>type).numberIndexInfo = numberIndexInfo;
return <ResolvedType>type;
}
@ -5450,7 +5453,7 @@ namespace ts {
// (otherwise there'd be an error from hasBaseType) - this is fine, but `.members` should be reset
// as `getIndexedAccessType` via `instantiateType` via `getTypeFromClassOrInterfaceReference` forces a
// partial instantiation of the members without the base types fully resolved
(type as Type as ResolvedType).members = undefined!; // TODO: GH#18217
type.members = undefined;
}
return type.resolvedBaseTypes = [baseType];
}
@ -6380,6 +6383,7 @@ namespace ts {
function resolveAnonymousTypeMembers(type: AnonymousType) {
const symbol = type.symbol;
if (type.target) {
setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, undefined, undefined);
const members = createInstantiatedSymbolTable(getPropertiesOfObjectType(type.target), type.mapper!, /*mappingThisOnly*/ false);
const callSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper!);
const constructSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper!);
@ -6388,6 +6392,7 @@ namespace ts {
setStructuredTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
}
else if (symbol.flags & SymbolFlags.TypeLiteral) {
setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, undefined, undefined);
const members = getMembersOfSymbol(symbol);
const callSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.Call));
const constructSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.New));
@ -6421,7 +6426,7 @@ namespace ts {
// 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);
type.callSignatures = getSignaturesOfSymbol(symbol);
}
// And likewise for construct signatures for classes
if (symbol.flags & SymbolFlags.Class) {
@ -6430,7 +6435,7 @@ namespace ts {
if (!constructSignatures.length) {
constructSignatures = getDefaultConstructSignatures(classType);
}
(<ResolvedType>type).constructSignatures = constructSignatures;
type.constructSignatures = constructSignatures;
}
}
}
@ -7610,7 +7615,7 @@ namespace ts {
// will result in a different declaration kind.
if (!signature.isolatedSignatureType) {
const isConstructor = signature.declaration!.kind === SyntaxKind.Constructor || signature.declaration!.kind === SyntaxKind.ConstructSignature; // TODO: GH#18217
const type = <ResolvedType>createObjectType(ObjectFlags.Anonymous);
const type = createObjectType(ObjectFlags.Anonymous);
type.members = emptySymbols;
type.properties = emptyArray;
type.callSignatures = !isConstructor ? [signature] : emptyArray;
@ -10046,7 +10051,7 @@ namespace ts {
if (type.flags & TypeFlags.Object) {
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
if (resolved.constructSignatures.length) {
const result = <ResolvedType>createObjectType(ObjectFlags.Anonymous, type.symbol);
const result = createObjectType(ObjectFlags.Anonymous, type.symbol);
result.members = resolved.members;
result.properties = resolved.properties;
result.callSignatures = emptyArray;

View file

@ -3802,6 +3802,12 @@ namespace ts {
// Object types (TypeFlags.ObjectType)
export interface ObjectType extends Type {
objectFlags: ObjectFlags;
/* @internal */ members?: SymbolTable; // Properties by name
/* @internal */ properties?: Symbol[]; // Properties
/* @internal */ callSignatures?: ReadonlyArray<Signature>; // Call signatures of type
/* @internal */ constructSignatures?: ReadonlyArray<Signature>; // Construct signatures of type
/* @internal */ stringIndexInfo?: IndexInfo; // String indexing info
/* @internal */ numberIndexInfo?: IndexInfo; // Numeric indexing info
}
/** Class and interface types (ObjectFlags.Class and ObjectFlags.Interface). */
@ -3928,8 +3934,6 @@ namespace ts {
properties: Symbol[]; // Properties
callSignatures: ReadonlyArray<Signature>; // Call signatures of type
constructSignatures: ReadonlyArray<Signature>; // Construct signatures of type
stringIndexInfo?: IndexInfo; // String indexing info
numberIndexInfo?: IndexInfo; // Numeric indexing info
}
/* @internal */

View file

@ -3292,6 +3292,12 @@ declare namespace ts {
}
interface ObjectType extends Type {
objectFlags: ObjectFlags;
members?: SymbolTable;
properties?: Symbol[];
callSignatures?: ReadonlyArray<Signature>;
constructSignatures?: ReadonlyArray<Signature>;
stringIndexInfo?: IndexInfo;
numberIndexInfo?: IndexInfo;
}
/** Class and interface types (ObjectFlags.Class and ObjectFlags.Interface). */
interface InterfaceType extends ObjectType {
@ -3382,8 +3388,6 @@ declare namespace ts {
properties: Symbol[];
callSignatures: ReadonlyArray<Signature>;
constructSignatures: ReadonlyArray<Signature>;
stringIndexInfo?: IndexInfo;
numberIndexInfo?: IndexInfo;
}
interface FreshObjectLiteralType extends ResolvedType {
regularType: ResolvedType;

View file

@ -0,0 +1,19 @@
tests/cases/compiler/recursiveResolveTypeMembers.ts(4,58): error TS2304: Cannot find name 'H'.
tests/cases/compiler/recursiveResolveTypeMembers.ts(4,62): error TS2574: A rest element type must be an array type.
tests/cases/compiler/recursiveResolveTypeMembers.ts(4,79): error TS2304: Cannot find name 'R'.
==== tests/cases/compiler/recursiveResolveTypeMembers.ts (3 errors) ====
// Repro from #25291
type PromisedTuple<L extends any[], U = (...args: L) => void> =
U extends (h: infer H, ...args: infer R) => [Promise<H>, ...PromisedTuple<R>] ? [] : []
~
!!! error TS2304: Cannot find name 'H'.
~~~~~~~~~~~~~~~~~~~
!!! error TS2574: A rest element type must be an array type.
~
!!! error TS2304: Cannot find name 'R'.
type Promised = PromisedTuple<[1, 2, 3]>

View file

@ -0,0 +1,11 @@
//// [recursiveResolveTypeMembers.ts]
// Repro from #25291
type PromisedTuple<L extends any[], U = (...args: L) => void> =
U extends (h: infer H, ...args: infer R) => [Promise<H>, ...PromisedTuple<R>] ? [] : []
type Promised = PromisedTuple<[1, 2, 3]>
//// [recursiveResolveTypeMembers.js]
// Repro from #25291

View file

@ -0,0 +1,23 @@
=== tests/cases/compiler/recursiveResolveTypeMembers.ts ===
// Repro from #25291
type PromisedTuple<L extends any[], U = (...args: L) => void> =
>PromisedTuple : Symbol(PromisedTuple, Decl(recursiveResolveTypeMembers.ts, 0, 0))
>L : Symbol(L, Decl(recursiveResolveTypeMembers.ts, 2, 19))
>U : Symbol(U, Decl(recursiveResolveTypeMembers.ts, 2, 35))
>args : Symbol(args, Decl(recursiveResolveTypeMembers.ts, 2, 41))
>L : Symbol(L, Decl(recursiveResolveTypeMembers.ts, 2, 19))
U extends (h: infer H, ...args: infer R) => [Promise<H>, ...PromisedTuple<R>] ? [] : []
>U : Symbol(U, Decl(recursiveResolveTypeMembers.ts, 2, 35))
>h : Symbol(h, Decl(recursiveResolveTypeMembers.ts, 3, 15))
>H : Symbol(H, Decl(recursiveResolveTypeMembers.ts, 3, 23))
>args : Symbol(args, Decl(recursiveResolveTypeMembers.ts, 3, 26))
>R : Symbol(R, Decl(recursiveResolveTypeMembers.ts, 3, 41))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
>PromisedTuple : Symbol(PromisedTuple, Decl(recursiveResolveTypeMembers.ts, 0, 0))
type Promised = PromisedTuple<[1, 2, 3]>
>Promised : Symbol(Promised, Decl(recursiveResolveTypeMembers.ts, 3, 91))
>PromisedTuple : Symbol(PromisedTuple, Decl(recursiveResolveTypeMembers.ts, 0, 0))

View file

@ -0,0 +1,25 @@
=== tests/cases/compiler/recursiveResolveTypeMembers.ts ===
// Repro from #25291
type PromisedTuple<L extends any[], U = (...args: L) => void> =
>PromisedTuple : PromisedTuple<L, U>
>L : L
>U : U
>args : L
>L : L
U extends (h: infer H, ...args: infer R) => [Promise<H>, ...PromisedTuple<R>] ? [] : []
>U : U
>h : H
>H : H
>args : R
>R : R
>Promise : Promise<T>
>H : No type information available!
>PromisedTuple : PromisedTuple<L, U>
>R : No type information available!
type Promised = PromisedTuple<[1, 2, 3]>
>Promised : []
>PromisedTuple : PromisedTuple<L, U>

View file

@ -0,0 +1,6 @@
// Repro from #25291
type PromisedTuple<L extends any[], U = (...args: L) => void> =
U extends (h: infer H, ...args: infer R) => [Promise<H>, ...PromisedTuple<R>] ? [] : []
type Promised = PromisedTuple<[1, 2, 3]>