Merge pull request #25336 from Microsoft/fixResolveTypeMembers
Fix runaway recursion in object type member resolution
This commit is contained in:
commit
e8d64a9c7c
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]>
|
||||
|
11
tests/baselines/reference/recursiveResolveTypeMembers.js
Normal file
11
tests/baselines/reference/recursiveResolveTypeMembers.js
Normal 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
|
|
@ -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))
|
||||
|
25
tests/baselines/reference/recursiveResolveTypeMembers.types
Normal file
25
tests/baselines/reference/recursiveResolveTypeMembers.types
Normal 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>
|
||||
|
6
tests/cases/compiler/recursiveResolveTypeMembers.ts
Normal file
6
tests/cases/compiler/recursiveResolveTypeMembers.ts
Normal 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]>
|
Loading…
Reference in a new issue