mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 12:32:08 -06:00
Ensure instantiation expressions have symbols, preventing crash in signature relations (#56064)
This commit is contained in:
parent
649e614496
commit
4dd1e2f844
@ -6838,6 +6838,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const typeId = type.id;
|
||||
const symbol = type.symbol;
|
||||
if (symbol) {
|
||||
const isInstantiationExpressionType = !!(getObjectFlags(type) & ObjectFlags.InstantiationExpressionType);
|
||||
if (isInstantiationExpressionType) {
|
||||
const instantiationExpressionType = type as InstantiationExpressionType;
|
||||
const existing = instantiationExpressionType.node;
|
||||
if (isTypeQueryNode(existing) && getTypeFromTypeNode(existing) === type) {
|
||||
const typeNode = serializeExistingTypeNode(context, existing);
|
||||
if (typeNode) {
|
||||
return typeNode;
|
||||
}
|
||||
}
|
||||
if (context.visitedTypes?.has(typeId)) {
|
||||
return createElidedInformationPlaceholder(context);
|
||||
}
|
||||
return visitAndTransformType(type, createTypeNodeFromObjectType);
|
||||
}
|
||||
const isInstanceType = isClassInstanceSide(type) ? SymbolFlags.Type : SymbolFlags.Value;
|
||||
if (isJSConstructor(symbol.valueDeclaration)) {
|
||||
// Instance and static types share the same symbol; only add 'typeof' for the static side.
|
||||
@ -6869,20 +6884,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
else {
|
||||
const isInstantiationExpressionType = !!(getObjectFlags(type) & ObjectFlags.InstantiationExpressionType);
|
||||
if (isInstantiationExpressionType) {
|
||||
const instantiationExpressionType = type as InstantiationExpressionType;
|
||||
if (isTypeQueryNode(instantiationExpressionType.node)) {
|
||||
const typeNode = serializeExistingTypeNode(context, instantiationExpressionType.node);
|
||||
if (typeNode) {
|
||||
return typeNode;
|
||||
}
|
||||
}
|
||||
if (context.visitedTypes?.has(typeId)) {
|
||||
return createElidedInformationPlaceholder(context);
|
||||
}
|
||||
return visitAndTransformType(type, createTypeNodeFromObjectType);
|
||||
}
|
||||
// Anonymous types without a symbol are never circular.
|
||||
return createTypeNodeFromObjectType(type);
|
||||
}
|
||||
@ -19542,6 +19543,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): AnonymousType {
|
||||
Debug.assert(type.symbol, "anonymous type must have symbol to be instantiated");
|
||||
const result = createObjectType(type.objectFlags & ~(ObjectFlags.CouldContainTypeVariablesComputed | ObjectFlags.CouldContainTypeVariables) | ObjectFlags.Instantiated, type.symbol) as AnonymousType;
|
||||
if (type.objectFlags & ObjectFlags.Mapped) {
|
||||
(result as MappedType).declaration = (type as MappedType).declaration;
|
||||
@ -23074,6 +23076,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// method). Simply do a pairwise comparison of the signatures in the two signature lists instead
|
||||
// of the much more expensive N * M comparison matrix we explore below. We erase type parameters
|
||||
// as they are known to always be the same.
|
||||
Debug.assertEqual(sourceSignatures.length, targetSignatures.length);
|
||||
for (let i = 0; i < targetSignatures.length; i++) {
|
||||
const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, intersectionState, incompatibleReporter(sourceSignatures[i], targetSignatures[i]));
|
||||
if (!related) {
|
||||
@ -35677,7 +35680,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
hasSignatures ||= resolved.callSignatures.length !== 0 || resolved.constructSignatures.length !== 0;
|
||||
hasApplicableSignature ||= callSignatures.length !== 0 || constructSignatures.length !== 0;
|
||||
if (callSignatures !== resolved.callSignatures || constructSignatures !== resolved.constructSignatures) {
|
||||
const result = createAnonymousType(/*symbol*/ undefined, resolved.members, callSignatures, constructSignatures, resolved.indexInfos) as ResolvedType & InstantiationExpressionType;
|
||||
const result = createAnonymousType(createSymbol(SymbolFlags.None, InternalSymbolName.InstantiationExpression), resolved.members, callSignatures, constructSignatures, resolved.indexInfos) as ResolvedType & InstantiationExpressionType;
|
||||
result.objectFlags |= ObjectFlags.InstantiationExpressionType;
|
||||
result.node = node;
|
||||
return result;
|
||||
|
||||
@ -5955,6 +5955,7 @@ export const enum InternalSymbolName {
|
||||
ExportEquals = "export=", // Export assignment symbol
|
||||
Default = "default", // Default export symbol (technically not wholly internal, but included here for usability)
|
||||
This = "this",
|
||||
InstantiationExpression = "__instantiationExpression", // Instantiation expressions
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
aliasInstantiationExpressionGenericIntersectionNoCrash1.ts(10,1): error TS2352: Conversion of type '{ new (): ErrImpl<number>; prototype: ErrImpl<any>; } & (() => number)' to type '{ new (): ErrImpl<string>; prototype: ErrImpl<any>; } & (() => string)' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
|
||||
Type '{ new (): ErrImpl<number>; prototype: ErrImpl<any>; } & (() => number)' is not comparable to type '{ new (): ErrImpl<string>; prototype: ErrImpl<any>; }'.
|
||||
Type 'ErrImpl<number>' is not comparable to type 'ErrImpl<string>'.
|
||||
Type 'number' is not comparable to type 'string'.
|
||||
|
||||
|
||||
==== aliasInstantiationExpressionGenericIntersectionNoCrash1.ts (1 errors) ====
|
||||
class ErrImpl<E> {
|
||||
e!: E;
|
||||
}
|
||||
|
||||
declare const Err: typeof ErrImpl & (<T>() => T);
|
||||
|
||||
type ErrAlias<U> = typeof Err<U>;
|
||||
|
||||
declare const e: ErrAlias<number>;
|
||||
e as ErrAlias<string>;
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2352: Conversion of type '{ new (): ErrImpl<number>; prototype: ErrImpl<any>; } & (() => number)' to type '{ new (): ErrImpl<string>; prototype: ErrImpl<any>; } & (() => string)' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
|
||||
!!! error TS2352: Type '{ new (): ErrImpl<number>; prototype: ErrImpl<any>; } & (() => number)' is not comparable to type '{ new (): ErrImpl<string>; prototype: ErrImpl<any>; }'.
|
||||
!!! error TS2352: Type 'ErrImpl<number>' is not comparable to type 'ErrImpl<string>'.
|
||||
!!! error TS2352: Type 'number' is not comparable to type 'string'.
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
//// [tests/cases/compiler/aliasInstantiationExpressionGenericIntersectionNoCrash1.ts] ////
|
||||
|
||||
//// [aliasInstantiationExpressionGenericIntersectionNoCrash1.ts]
|
||||
class ErrImpl<E> {
|
||||
e!: E;
|
||||
}
|
||||
|
||||
declare const Err: typeof ErrImpl & (<T>() => T);
|
||||
|
||||
type ErrAlias<U> = typeof Err<U>;
|
||||
|
||||
declare const e: ErrAlias<number>;
|
||||
e as ErrAlias<string>;
|
||||
|
||||
|
||||
//// [aliasInstantiationExpressionGenericIntersectionNoCrash1.js]
|
||||
"use strict";
|
||||
var ErrImpl = /** @class */ (function () {
|
||||
function ErrImpl() {
|
||||
}
|
||||
return ErrImpl;
|
||||
}());
|
||||
e;
|
||||
@ -0,0 +1,32 @@
|
||||
//// [tests/cases/compiler/aliasInstantiationExpressionGenericIntersectionNoCrash1.ts] ////
|
||||
|
||||
=== aliasInstantiationExpressionGenericIntersectionNoCrash1.ts ===
|
||||
class ErrImpl<E> {
|
||||
>ErrImpl : Symbol(ErrImpl, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 0, 0))
|
||||
>E : Symbol(E, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 0, 14))
|
||||
|
||||
e!: E;
|
||||
>e : Symbol(ErrImpl.e, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 0, 18))
|
||||
>E : Symbol(E, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 0, 14))
|
||||
}
|
||||
|
||||
declare const Err: typeof ErrImpl & (<T>() => T);
|
||||
>Err : Symbol(Err, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 4, 13))
|
||||
>ErrImpl : Symbol(ErrImpl, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 4, 38))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 4, 38))
|
||||
|
||||
type ErrAlias<U> = typeof Err<U>;
|
||||
>ErrAlias : Symbol(ErrAlias, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 4, 49))
|
||||
>U : Symbol(U, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 6, 14))
|
||||
>Err : Symbol(Err, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 4, 13))
|
||||
>U : Symbol(U, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 6, 14))
|
||||
|
||||
declare const e: ErrAlias<number>;
|
||||
>e : Symbol(e, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 8, 13))
|
||||
>ErrAlias : Symbol(ErrAlias, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 4, 49))
|
||||
|
||||
e as ErrAlias<string>;
|
||||
>e : Symbol(e, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 8, 13))
|
||||
>ErrAlias : Symbol(ErrAlias, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash1.ts, 4, 49))
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
//// [tests/cases/compiler/aliasInstantiationExpressionGenericIntersectionNoCrash1.ts] ////
|
||||
|
||||
=== aliasInstantiationExpressionGenericIntersectionNoCrash1.ts ===
|
||||
class ErrImpl<E> {
|
||||
>ErrImpl : ErrImpl<E>
|
||||
|
||||
e!: E;
|
||||
>e : E
|
||||
}
|
||||
|
||||
declare const Err: typeof ErrImpl & (<T>() => T);
|
||||
>Err : typeof ErrImpl & (<T>() => T)
|
||||
>ErrImpl : typeof ErrImpl
|
||||
|
||||
type ErrAlias<U> = typeof Err<U>;
|
||||
>ErrAlias : { new (): ErrImpl<U>; prototype: ErrImpl<any>; } & (() => U)
|
||||
>Err : typeof ErrImpl & (<T>() => T)
|
||||
|
||||
declare const e: ErrAlias<number>;
|
||||
>e : { new (): ErrImpl<number>; prototype: ErrImpl<any>; } & (() => number)
|
||||
|
||||
e as ErrAlias<string>;
|
||||
>e as ErrAlias<string> : { new (): ErrImpl<string>; prototype: ErrImpl<any>; } & (() => string)
|
||||
>e : { new (): ErrImpl<number>; prototype: ErrImpl<any>; } & (() => number)
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
aliasInstantiationExpressionGenericIntersectionNoCrash2.ts(15,1): error TS2352: Conversion of type 'Wat<number>' to type 'Wat<string>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
|
||||
Type 'Wat<number>' is not comparable to type '{ new (): Class<string>; prototype: Class<any>; }'.
|
||||
Type 'Class<number>' is not comparable to type 'Class<string>'.
|
||||
Type 'number' is not comparable to type 'string'.
|
||||
|
||||
|
||||
==== aliasInstantiationExpressionGenericIntersectionNoCrash2.ts (1 errors) ====
|
||||
declare class Class<T> {
|
||||
x: T;
|
||||
}
|
||||
|
||||
declare function fn<T>(): T;
|
||||
|
||||
|
||||
type ClassAlias<T> = typeof Class<T>;
|
||||
type FnAlias<T> = typeof fn<T>;
|
||||
|
||||
type Wat<T> = ClassAlias<T> & FnAlias<T>;
|
||||
|
||||
|
||||
declare const wat: Wat<number>;
|
||||
wat as Wat<string>;
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2352: Conversion of type 'Wat<number>' to type 'Wat<string>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
|
||||
!!! error TS2352: Type 'Wat<number>' is not comparable to type '{ new (): Class<string>; prototype: Class<any>; }'.
|
||||
!!! error TS2352: Type 'Class<number>' is not comparable to type 'Class<string>'.
|
||||
!!! error TS2352: Type 'number' is not comparable to type 'string'.
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
//// [tests/cases/compiler/aliasInstantiationExpressionGenericIntersectionNoCrash2.ts] ////
|
||||
|
||||
//// [aliasInstantiationExpressionGenericIntersectionNoCrash2.ts]
|
||||
declare class Class<T> {
|
||||
x: T;
|
||||
}
|
||||
|
||||
declare function fn<T>(): T;
|
||||
|
||||
|
||||
type ClassAlias<T> = typeof Class<T>;
|
||||
type FnAlias<T> = typeof fn<T>;
|
||||
|
||||
type Wat<T> = ClassAlias<T> & FnAlias<T>;
|
||||
|
||||
|
||||
declare const wat: Wat<number>;
|
||||
wat as Wat<string>;
|
||||
|
||||
|
||||
//// [aliasInstantiationExpressionGenericIntersectionNoCrash2.js]
|
||||
"use strict";
|
||||
wat;
|
||||
@ -0,0 +1,47 @@
|
||||
//// [tests/cases/compiler/aliasInstantiationExpressionGenericIntersectionNoCrash2.ts] ////
|
||||
|
||||
=== aliasInstantiationExpressionGenericIntersectionNoCrash2.ts ===
|
||||
declare class Class<T> {
|
||||
>Class : Symbol(Class, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 0, 20))
|
||||
|
||||
x: T;
|
||||
>x : Symbol(Class.x, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 0, 24))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 0, 20))
|
||||
}
|
||||
|
||||
declare function fn<T>(): T;
|
||||
>fn : Symbol(fn, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 2, 1))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 4, 20))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 4, 20))
|
||||
|
||||
|
||||
type ClassAlias<T> = typeof Class<T>;
|
||||
>ClassAlias : Symbol(ClassAlias, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 4, 28))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 7, 16))
|
||||
>Class : Symbol(Class, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 7, 16))
|
||||
|
||||
type FnAlias<T> = typeof fn<T>;
|
||||
>FnAlias : Symbol(FnAlias, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 7, 37))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 8, 13))
|
||||
>fn : Symbol(fn, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 2, 1))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 8, 13))
|
||||
|
||||
type Wat<T> = ClassAlias<T> & FnAlias<T>;
|
||||
>Wat : Symbol(Wat, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 8, 31))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 10, 9))
|
||||
>ClassAlias : Symbol(ClassAlias, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 4, 28))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 10, 9))
|
||||
>FnAlias : Symbol(FnAlias, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 7, 37))
|
||||
>T : Symbol(T, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 10, 9))
|
||||
|
||||
|
||||
declare const wat: Wat<number>;
|
||||
>wat : Symbol(wat, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 13, 13))
|
||||
>Wat : Symbol(Wat, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 8, 31))
|
||||
|
||||
wat as Wat<string>;
|
||||
>wat : Symbol(wat, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 13, 13))
|
||||
>Wat : Symbol(Wat, Decl(aliasInstantiationExpressionGenericIntersectionNoCrash2.ts, 8, 31))
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
//// [tests/cases/compiler/aliasInstantiationExpressionGenericIntersectionNoCrash2.ts] ////
|
||||
|
||||
=== aliasInstantiationExpressionGenericIntersectionNoCrash2.ts ===
|
||||
declare class Class<T> {
|
||||
>Class : Class<T>
|
||||
|
||||
x: T;
|
||||
>x : T
|
||||
}
|
||||
|
||||
declare function fn<T>(): T;
|
||||
>fn : <T>() => T
|
||||
|
||||
|
||||
type ClassAlias<T> = typeof Class<T>;
|
||||
>ClassAlias : typeof Class<T>
|
||||
>Class : typeof Class
|
||||
|
||||
type FnAlias<T> = typeof fn<T>;
|
||||
>FnAlias : typeof fn<T>
|
||||
>fn : <T_1>() => T_1
|
||||
|
||||
type Wat<T> = ClassAlias<T> & FnAlias<T>;
|
||||
>Wat : Wat<T>
|
||||
|
||||
|
||||
declare const wat: Wat<number>;
|
||||
>wat : Wat<number>
|
||||
|
||||
wat as Wat<string>;
|
||||
>wat as Wat<string> : Wat<string>
|
||||
>wat : Wat<number>
|
||||
|
||||
@ -7049,6 +7049,7 @@ declare namespace ts {
|
||||
ExportEquals = "export=",
|
||||
Default = "default",
|
||||
This = "this",
|
||||
InstantiationExpression = "__instantiationExpression",
|
||||
}
|
||||
/**
|
||||
* This represents a string whose leading underscore have been escaped by adding extra leading underscores.
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
// @strict: true
|
||||
|
||||
class ErrImpl<E> {
|
||||
e!: E;
|
||||
}
|
||||
|
||||
declare const Err: typeof ErrImpl & (<T>() => T);
|
||||
|
||||
type ErrAlias<U> = typeof Err<U>;
|
||||
|
||||
declare const e: ErrAlias<number>;
|
||||
e as ErrAlias<string>;
|
||||
@ -0,0 +1,17 @@
|
||||
// @strict: true
|
||||
|
||||
declare class Class<T> {
|
||||
x: T;
|
||||
}
|
||||
|
||||
declare function fn<T>(): T;
|
||||
|
||||
|
||||
type ClassAlias<T> = typeof Class<T>;
|
||||
type FnAlias<T> = typeof fn<T>;
|
||||
|
||||
type Wat<T> = ClassAlias<T> & FnAlias<T>;
|
||||
|
||||
|
||||
declare const wat: Wat<number>;
|
||||
wat as Wat<string>;
|
||||
Loading…
x
Reference in New Issue
Block a user