mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Optimize substitution types (#50397)
* Optimize substitution type infrastructure * Accept new baselines * Preserve instantiated substitution types for type variables * Restrictive type parameters should have no constraint * Fix issues from top100 test run * Accept new baselines
This commit is contained in:
parent
226dd0b7bf
commit
6e8337ef70
@ -12366,7 +12366,7 @@ namespace ts {
|
||||
return constraint && getBaseConstraint(constraint);
|
||||
}
|
||||
if (t.flags & TypeFlags.Substitution) {
|
||||
return getBaseConstraint((t as SubstitutionType).substitute);
|
||||
return getBaseConstraint(getSubstitutionIntersection(t as SubstitutionType));
|
||||
}
|
||||
return t;
|
||||
}
|
||||
@ -13903,22 +13903,27 @@ namespace ts {
|
||||
return links.resolvedJSDocType;
|
||||
}
|
||||
|
||||
function getSubstitutionType(baseType: Type, substitute: Type) {
|
||||
if (substitute.flags & TypeFlags.AnyOrUnknown || substitute === baseType) {
|
||||
function getSubstitutionType(baseType: Type, constraint: Type) {
|
||||
if (constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType ||
|
||||
!isGenericType(baseType) && !isGenericType(constraint)) {
|
||||
return baseType;
|
||||
}
|
||||
const id = `${getTypeId(baseType)}>${getTypeId(substitute)}`;
|
||||
const id = `${getTypeId(baseType)}>${getTypeId(constraint)}`;
|
||||
const cached = substitutionTypes.get(id);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const result = createType(TypeFlags.Substitution) as SubstitutionType;
|
||||
result.baseType = baseType;
|
||||
result.substitute = substitute;
|
||||
result.constraint = constraint;
|
||||
substitutionTypes.set(id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
function getSubstitutionIntersection(substitutionType: SubstitutionType) {
|
||||
return getIntersectionType([substitutionType.constraint, substitutionType.baseType]);
|
||||
}
|
||||
|
||||
function isUnaryTupleTypeNode(node: TypeNode) {
|
||||
return node.kind === SyntaxKind.TupleType && (node as TupleTypeNode).elements.length === 1;
|
||||
}
|
||||
@ -13963,7 +13968,7 @@ namespace ts {
|
||||
}
|
||||
node = parent;
|
||||
}
|
||||
return constraints ? getSubstitutionType(type, getIntersectionType(append(constraints, type))) : type;
|
||||
return constraints ? getSubstitutionType(type, getIntersectionType(constraints)) : type;
|
||||
}
|
||||
|
||||
function isJSDocTypeReference(node: Node): node is TypeReferenceNode {
|
||||
@ -15363,7 +15368,7 @@ namespace ts {
|
||||
type.flags & TypeFlags.Conditional ? (type as ConditionalType).root.isDistributive && (type as ConditionalType).checkType === typeVariable :
|
||||
type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) ? every((type as UnionOrIntersectionType | TemplateLiteralType).types, isDistributive) :
|
||||
type.flags & TypeFlags.IndexedAccess ? isDistributive((type as IndexedAccessType).objectType) && isDistributive((type as IndexedAccessType).indexType) :
|
||||
type.flags & TypeFlags.Substitution ? isDistributive((type as SubstitutionType).substitute) :
|
||||
type.flags & TypeFlags.Substitution ? isDistributive((type as SubstitutionType).baseType) && isDistributive((type as SubstitutionType).constraint):
|
||||
type.flags & TypeFlags.StringMapping ? isDistributive((type as StringMappingType).type) :
|
||||
false;
|
||||
}
|
||||
@ -15883,7 +15888,7 @@ namespace ts {
|
||||
if (type.flags & TypeFlags.Substitution) {
|
||||
if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) {
|
||||
(type as SubstitutionType).objectFlags |= ObjectFlags.IsGenericTypeComputed |
|
||||
getGenericObjectFlags((type as SubstitutionType).substitute) | getGenericObjectFlags((type as SubstitutionType).baseType);
|
||||
getGenericObjectFlags((type as SubstitutionType).baseType) | getGenericObjectFlags((type as SubstitutionType).constraint);
|
||||
}
|
||||
return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType;
|
||||
}
|
||||
@ -16095,11 +16100,7 @@ namespace ts {
|
||||
const objectType = getTypeFromTypeNode(node.objectType);
|
||||
const indexType = getTypeFromTypeNode(node.indexType);
|
||||
const potentialAlias = getAliasSymbolForTypeNode(node);
|
||||
const resolved = getIndexedAccessType(objectType, indexType, AccessFlags.None, node, potentialAlias, getTypeArgumentsForAliasSymbol(potentialAlias));
|
||||
links.resolvedType = resolved.flags & TypeFlags.IndexedAccess &&
|
||||
(resolved as IndexedAccessType).objectType === objectType &&
|
||||
(resolved as IndexedAccessType).indexType === indexType ?
|
||||
getConditionalFlowTypeOfType(resolved, node) : resolved;
|
||||
links.resolvedType = getIndexedAccessType(objectType, indexType, AccessFlags.None, node, potentialAlias, getTypeArgumentsForAliasSymbol(potentialAlias));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
@ -17040,9 +17041,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getRestrictiveTypeParameter(tp: TypeParameter) {
|
||||
return tp.constraint === unknownType ? tp : tp.restrictiveInstantiation || (
|
||||
return !tp.constraint && !getConstraintDeclaration(tp) || tp.constraint === noConstraintType ? tp : tp.restrictiveInstantiation || (
|
||||
tp.restrictiveInstantiation = createTypeParameter(tp.symbol),
|
||||
(tp.restrictiveInstantiation as TypeParameter).constraint = unknownType,
|
||||
(tp.restrictiveInstantiation as TypeParameter).constraint = noConstraintType,
|
||||
tp.restrictiveInstantiation
|
||||
);
|
||||
}
|
||||
@ -17429,17 +17430,18 @@ namespace ts {
|
||||
return getConditionalTypeInstantiation(type as ConditionalType, combineTypeMappers((type as ConditionalType).mapper, mapper), aliasSymbol, aliasTypeArguments);
|
||||
}
|
||||
if (flags & TypeFlags.Substitution) {
|
||||
const maybeVariable = instantiateType((type as SubstitutionType).baseType, mapper);
|
||||
if (maybeVariable.flags & TypeFlags.TypeVariable) {
|
||||
return getSubstitutionType(maybeVariable as TypeVariable, instantiateType((type as SubstitutionType).substitute, mapper));
|
||||
const newBaseType = instantiateType((type as SubstitutionType).baseType, mapper);
|
||||
const newConstraint = instantiateType((type as SubstitutionType).constraint, mapper);
|
||||
// A substitution type originates in the true branch of a conditional type and can be resolved
|
||||
// to just the base type in the same cases as the conditional type resolves to its true branch
|
||||
// (because the base type is then known to satisfy the constraint).
|
||||
if (newBaseType.flags & TypeFlags.TypeVariable && isGenericType(newConstraint)) {
|
||||
return getSubstitutionType(newBaseType, newConstraint);
|
||||
}
|
||||
else {
|
||||
const sub = instantiateType((type as SubstitutionType).substitute, mapper);
|
||||
if (sub.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(maybeVariable), getRestrictiveInstantiation(sub))) {
|
||||
return maybeVariable;
|
||||
}
|
||||
return sub;
|
||||
if (newConstraint.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(newBaseType), getRestrictiveInstantiation(newConstraint))) {
|
||||
return newBaseType;
|
||||
}
|
||||
return newBaseType.flags & TypeFlags.TypeVariable ? getSubstitutionType(newBaseType, newConstraint) : getIntersectionType([newConstraint, newBaseType]);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@ -18478,7 +18480,7 @@ namespace ts {
|
||||
const t = isFreshLiteralType(type) ? (type as FreshableType).regularType :
|
||||
getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).node ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) : getSingleBaseForNonAugmentingSubtype(type) || type :
|
||||
type.flags & TypeFlags.UnionOrIntersection ? getNormalizedUnionOrIntersectionType(type as UnionOrIntersectionType, writing) :
|
||||
type.flags & TypeFlags.Substitution ? writing ? (type as SubstitutionType).baseType : (type as SubstitutionType).substitute :
|
||||
type.flags & TypeFlags.Substitution ? writing ? (type as SubstitutionType).baseType : getSubstitutionIntersection(type as SubstitutionType) :
|
||||
type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) :
|
||||
type;
|
||||
if (t === type) return t;
|
||||
@ -19561,7 +19563,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
if (sourceFlags & TypeFlags.Substitution) {
|
||||
return isRelatedTo((source as SubstitutionType).substitute, (target as SubstitutionType).substitute, RecursionFlags.Both, /*reportErrors*/ false);
|
||||
if (result = isRelatedTo((source as SubstitutionType).baseType, (target as SubstitutionType).baseType, RecursionFlags.Both, /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo((source as SubstitutionType).constraint, (target as SubstitutionType).constraint, RecursionFlags.Both, /*reportErrors*/ false)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(sourceFlags & TypeFlags.Object)) {
|
||||
return Ternary.False;
|
||||
@ -22699,7 +22705,7 @@ namespace ts {
|
||||
}
|
||||
else if (source.flags & TypeFlags.Substitution) {
|
||||
inferFromTypes((source as SubstitutionType).baseType, target);
|
||||
inferWithPriority((source as SubstitutionType).substitute, target, InferencePriority.SubstituteSource); // Make substitute inference at a lower priority
|
||||
inferWithPriority(getSubstitutionIntersection(source as SubstitutionType), target, InferencePriority.SubstituteSource); // Make substitute inference at a lower priority
|
||||
}
|
||||
else if (target.flags & TypeFlags.Conditional) {
|
||||
invokeOnce(source, target, inferToConditionalType);
|
||||
|
||||
@ -253,7 +253,7 @@ namespace ts { // eslint-disable-line local/one-namespace-per-file
|
||||
const substitutionType = type as SubstitutionType;
|
||||
substitutionProperties = {
|
||||
substitutionBaseType: substitutionType.baseType?.id,
|
||||
substituteType: substitutionType.substitute?.id,
|
||||
constraintType: substitutionType.constraint?.id,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -6145,8 +6145,8 @@ namespace ts {
|
||||
// types disappear upon instantiation (just like type parameters).
|
||||
export interface SubstitutionType extends InstantiableType {
|
||||
objectFlags: ObjectFlags;
|
||||
baseType: Type; // Target type
|
||||
substitute: Type; // Type to substitute for type parameter
|
||||
baseType: Type; // Target type
|
||||
constraint: Type; // Constraint that target type is known to satisfy
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
@ -2840,7 +2840,7 @@ declare namespace ts {
|
||||
export interface SubstitutionType extends InstantiableType {
|
||||
objectFlags: ObjectFlags;
|
||||
baseType: Type;
|
||||
substitute: Type;
|
||||
constraint: Type;
|
||||
}
|
||||
export enum SignatureKind {
|
||||
Call = 0,
|
||||
|
||||
@ -2840,7 +2840,7 @@ declare namespace ts {
|
||||
export interface SubstitutionType extends InstantiableType {
|
||||
objectFlags: ObjectFlags;
|
||||
baseType: Type;
|
||||
substitute: Type;
|
||||
constraint: Type;
|
||||
}
|
||||
export enum SignatureKind {
|
||||
Call = 0,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user