mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-30 01:04:49 -05:00
Relate non-augmenting subtypes without resorting to structural comparison (#43624)
* Relate non-augmenting array subtypes without resorting to structural comparison
* Fix lint
* Generalize performance enhancement
* Cache results, feed through via getNormalizedType to remove error intermediates
* Use newly freed up object flags to limit member setting, fix crash with those object flags
* Move flags because there is no TypeFlags.Reference 🤦
This commit is contained in:
@@ -17232,12 +17232,13 @@ namespace ts {
|
||||
|
||||
function getNormalizedType(type: Type, writing: boolean): Type {
|
||||
while (true) {
|
||||
const t = isFreshLiteralType(type) ? (<FreshableType>type).regularType :
|
||||
let t = isFreshLiteralType(type) ? (<FreshableType>type).regularType :
|
||||
getObjectFlags(type) & ObjectFlags.Reference && (<TypeReference>type).node ? createTypeReference((<TypeReference>type).target, getTypeArguments(<TypeReference>type)) :
|
||||
type.flags & TypeFlags.UnionOrIntersection ? getReducedType(type) :
|
||||
type.flags & TypeFlags.Substitution ? writing ? (<SubstitutionType>type).baseType : (<SubstitutionType>type).substitute :
|
||||
type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) :
|
||||
type;
|
||||
t = getSingleBaseForNonAugmentingSubtype(t) || t;
|
||||
if (t === type) break;
|
||||
type = t;
|
||||
}
|
||||
@@ -17739,8 +17740,10 @@ namespace ts {
|
||||
|
||||
function reportErrorResults(source: Type, target: Type, result: Ternary, isComparingJsxAttributes: boolean) {
|
||||
if (!result && reportErrors) {
|
||||
source = originalSource.aliasSymbol ? originalSource : source;
|
||||
target = originalTarget.aliasSymbol ? originalTarget : target;
|
||||
const sourceHasBase = !!getSingleBaseForNonAugmentingSubtype(originalSource);
|
||||
const targetHasBase = !!getSingleBaseForNonAugmentingSubtype(originalTarget);
|
||||
source = (originalSource.aliasSymbol || sourceHasBase) ? originalSource : source;
|
||||
target = (originalTarget.aliasSymbol || targetHasBase) ? originalTarget : target;
|
||||
let maybeSuppress = overrideNextErrorInfo > 0;
|
||||
if (maybeSuppress) {
|
||||
overrideNextErrorInfo--;
|
||||
@@ -19993,6 +19996,30 @@ namespace ts {
|
||||
return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType);
|
||||
}
|
||||
|
||||
function getSingleBaseForNonAugmentingSubtype(type: Type) {
|
||||
if (!(getObjectFlags(type) & ObjectFlags.Reference) || !(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface)) {
|
||||
return undefined;
|
||||
}
|
||||
if (getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeCalculated) {
|
||||
return getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeExists ? (type as TypeReference).cachedEquivalentBaseType : undefined;
|
||||
}
|
||||
(type as TypeReference).objectFlags |= ObjectFlags.IdenticalBaseTypeCalculated;
|
||||
const target = (type as TypeReference).target as InterfaceType;
|
||||
const bases = getBaseTypes(target);
|
||||
if (bases.length !== 1) {
|
||||
return undefined;
|
||||
}
|
||||
if (getMembersOfSymbol(type.symbol).size) {
|
||||
return undefined; // If the interface has any members, they may subtype members in the base, so we should do a full structural comparison
|
||||
}
|
||||
let instantiatedBase = !length(target.typeParameters) ? bases[0] : instantiateType(bases[0], createTypeMapper(target.typeParameters!, getTypeArguments(type as TypeReference).slice(0, target.typeParameters!.length)));
|
||||
if (length(getTypeArguments(type as TypeReference)) > length(target.typeParameters)) {
|
||||
instantiatedBase = getTypeWithThisArgument(instantiatedBase, last(getTypeArguments(type as TypeReference)));
|
||||
}
|
||||
(type as TypeReference).objectFlags |= ObjectFlags.IdenticalBaseTypeExists;
|
||||
return (type as TypeReference).cachedEquivalentBaseType = instantiatedBase;
|
||||
}
|
||||
|
||||
function isEmptyArrayLiteralType(type: Type): boolean {
|
||||
const elementType = getElementTypeOfArrayType(type);
|
||||
return strictNullChecks ? elementType === implicitNeverType : elementType === undefinedWideningType;
|
||||
|
||||
@@ -5200,6 +5200,11 @@ namespace ts {
|
||||
ObjectRestType = 1 << 23, // Originates in object rest declaration
|
||||
/* @internal */
|
||||
IsClassInstanceClone = 1 << 24, // Type is a clone of a class instance type
|
||||
// Flags that require TypeFlags.Object and ObjectFlags.Reference
|
||||
/* @internal */
|
||||
IdenticalBaseTypeCalculated = 1 << 25, // has had `getSingleBaseForNonAugmentingSubtype` invoked on it already
|
||||
/* @internal */
|
||||
IdenticalBaseTypeExists = 1 << 26, // has a defined cachedEquivalentBaseType member
|
||||
|
||||
// Flags that require TypeFlags.UnionOrIntersection or TypeFlags.Substitution
|
||||
/* @internal */
|
||||
@@ -5281,6 +5286,8 @@ namespace ts {
|
||||
resolvedTypeArguments?: readonly Type[]; // Resolved type reference type arguments
|
||||
/* @internal */
|
||||
literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set
|
||||
/* @internal */
|
||||
cachedEquivalentBaseType?: Type; // Only set on references to class or interfaces with a single base type and no augmentations
|
||||
}
|
||||
|
||||
export interface DeferredTypeReference extends TypeReference {
|
||||
|
||||
Reference in New Issue
Block a user