mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-04-17 12:32:42 -05:00
Use type arguments instead of flags to detect variance marker types
This commit is contained in:
@@ -15189,12 +15189,14 @@ namespace ts {
|
||||
// is more predictable than other, interned types, which may or may not have an alias depending on
|
||||
// the order in which things were checked.
|
||||
if (source.flags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol &&
|
||||
source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol &&
|
||||
!(source.aliasTypeArgumentsContainsMarker || target.aliasTypeArgumentsContainsMarker)) {
|
||||
source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) {
|
||||
// Compute variances eagerly to ensure reliability flags are properly propagated.
|
||||
const variances = getAliasVariances(source.aliasSymbol);
|
||||
const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances, isIntersectionConstituent);
|
||||
if (varianceResult !== undefined) {
|
||||
return varianceResult;
|
||||
if (!(containsMarkerType(source.aliasTypeArguments) || containsMarkerType(target.aliasTypeArguments))) {
|
||||
const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances, isIntersectionConstituent);
|
||||
if (varianceResult !== undefined) {
|
||||
return varianceResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15383,7 +15385,7 @@ namespace ts {
|
||||
return Ternary.False;
|
||||
}
|
||||
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target &&
|
||||
!(getObjectFlags(source) & ObjectFlags.MarkerType || getObjectFlags(target) & ObjectFlags.MarkerType)) {
|
||||
!(containsMarkerType(getTypeArguments(<TypeReference>source)) || containsMarkerType(getTypeArguments(<TypeReference>target)))) {
|
||||
// We have type references to the same generic type, and the type references are not marker
|
||||
// type references (which are intended by be compared structurally). Obtain the variance
|
||||
// information for the type parameters and relate the type arguments accordingly.
|
||||
@@ -16157,21 +16159,24 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return a type reference where the source type parameter is replaced with the target marker
|
||||
// type, and flag the result as a marker type reference.
|
||||
function getMarkerTypeReference(type: GenericType, source: TypeParameter, target: Type) {
|
||||
const result = createTypeReference(type, map(type.typeParameters, t => t === source ? target : t));
|
||||
result.objectFlags |= ObjectFlags.MarkerType;
|
||||
return result;
|
||||
function containsMarkerType(types: readonly Type[] | undefined) {
|
||||
return some(types, t => t === markerSuperType || t === markerSubType || t === markerOtherType);
|
||||
}
|
||||
|
||||
function getVariances(type: GenericType): VarianceFlags[] {
|
||||
// Arrays and tuples are known to be covariant, no need to spend time computing this (emptyArray implies covariance for all parameters)
|
||||
if (type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple) {
|
||||
return emptyArray;
|
||||
}
|
||||
return getVariancesWorker(type, type, createTypeReference);
|
||||
}
|
||||
|
||||
function getAliasVariances(symbol: Symbol) {
|
||||
const links = getSymbolLinks(symbol);
|
||||
return getVariancesWorker(links.typeParameters, links, (_links, param, marker) => {
|
||||
const type = getTypeAliasInstantiation(symbol, instantiateTypes(links.typeParameters!, makeUnaryTypeMapper(param, marker)));
|
||||
type.aliasTypeArgumentsContainsMarker = true;
|
||||
return type;
|
||||
});
|
||||
return getVariancesWorker(symbol, getSymbolLinks(symbol), getTypeAliasInstantiation);
|
||||
}
|
||||
|
||||
function getTypeArgumentsWithMarker(typeParameters: TypeParameter[], source: TypeParameter, marker: TypeParameter) {
|
||||
return map(typeParameters, makeUnaryTypeMapper(source, marker));
|
||||
}
|
||||
|
||||
// Return an array containing the variance of each type parameter. The variance is effectively
|
||||
@@ -16180,12 +16185,13 @@ namespace ts {
|
||||
// instantiations of the generic type for type arguments with known relations. The function
|
||||
// returns the emptyArray singleton if we're not in strictFunctionTypes mode or if the function
|
||||
// has been invoked recursively for the given generic type.
|
||||
function getVariancesWorker<TCache extends { variances?: VarianceFlags[] }>(typeParameters: readonly TypeParameter[] = emptyArray, cache: TCache, createMarkerType: (input: TCache, param: TypeParameter, marker: Type) => Type): VarianceFlags[] {
|
||||
function getVariancesWorker<T extends GenericType | Symbol>(target: T, cache: GenericType | SymbolLinks, getInstance: (target: T, typeArguments: readonly Type[]) => Type): VarianceFlags[] {
|
||||
let variances = cache.variances;
|
||||
if (!variances) {
|
||||
// The emptyArray singleton is used to signal a recursive invocation.
|
||||
cache.variances = emptyArray;
|
||||
variances = [];
|
||||
const typeParameters = cache.typeParameters || emptyArray;
|
||||
for (const tp of typeParameters) {
|
||||
let unmeasurable = false;
|
||||
let unreliable = false;
|
||||
@@ -16194,15 +16200,15 @@ namespace ts {
|
||||
// We first compare instantiations where the type parameter is replaced with
|
||||
// marker types that have a known subtype relationship. From this we can infer
|
||||
// invariance, covariance, contravariance or bivariance.
|
||||
const typeWithSuper = createMarkerType(cache, tp, markerSuperType);
|
||||
const typeWithSub = createMarkerType(cache, tp, markerSubType);
|
||||
const typeWithSuper = getInstance(target, getTypeArgumentsWithMarker(typeParameters, tp, markerSuperType));
|
||||
const typeWithSub = getInstance(target, getTypeArgumentsWithMarker(typeParameters, tp, markerSubType));
|
||||
let variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? VarianceFlags.Covariant : 0) |
|
||||
(isTypeAssignableTo(typeWithSuper, typeWithSub) ? VarianceFlags.Contravariant : 0);
|
||||
// If the instantiations appear to be related bivariantly it may be because the
|
||||
// type parameter is independent (i.e. it isn't witnessed anywhere in the generic
|
||||
// type). To determine this we compare instantiations where the type parameter is
|
||||
// replaced with marker types that are known to be unrelated.
|
||||
if (variance === VarianceFlags.Bivariant && isTypeAssignableTo(createMarkerType(cache, tp, markerOtherType), typeWithSuper)) {
|
||||
if (variance === VarianceFlags.Bivariant && isTypeAssignableTo(getInstance(target, getTypeArgumentsWithMarker(typeParameters, tp, markerOtherType)), typeWithSuper)) {
|
||||
variance = VarianceFlags.Independent;
|
||||
}
|
||||
outofbandVarianceMarkerHandler = oldHandler;
|
||||
@@ -16221,14 +16227,6 @@ namespace ts {
|
||||
return variances;
|
||||
}
|
||||
|
||||
function getVariances(type: GenericType): VarianceFlags[] {
|
||||
// Arrays and tuples are known to be covariant, no need to spend time computing this (emptyArray implies covariance for all parameters)
|
||||
if (type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple) {
|
||||
return emptyArray;
|
||||
}
|
||||
return getVariancesWorker(type.typeParameters, type, getMarkerTypeReference);
|
||||
}
|
||||
|
||||
// Return true if the given type reference has a 'void' type argument for a covariant type parameter.
|
||||
// See comment at call in recursiveTypeRelatedTo for when this case matters.
|
||||
function hasCovariantVoidArgument(typeArguments: readonly Type[], variances: VarianceFlags[]): boolean {
|
||||
|
||||
@@ -4271,7 +4271,6 @@ namespace ts {
|
||||
pattern?: DestructuringPattern; // Destructuring pattern represented by type (if any)
|
||||
aliasSymbol?: Symbol; // Alias associated with type
|
||||
aliasTypeArguments?: readonly Type[]; // Alias type arguments (if any)
|
||||
/* @internal */ aliasTypeArgumentsContainsMarker?: boolean; // Alias type arguments (if any)
|
||||
/* @internal */
|
||||
permissiveInstantiation?: Type; // Instantiation with type parameters mapped to wildcard type
|
||||
/* @internal */
|
||||
@@ -4348,19 +4347,18 @@ namespace ts {
|
||||
ContainsSpread = 1 << 10, // Object literal contains spread operation
|
||||
ReverseMapped = 1 << 11, // Object contains a property from a reverse-mapped type
|
||||
JsxAttributes = 1 << 12, // Jsx attributes type
|
||||
MarkerType = 1 << 13, // Marker type used for variance probing
|
||||
JSLiteral = 1 << 14, // Object type declared in JS - disables errors on read/write of nonexisting members
|
||||
FreshLiteral = 1 << 15, // Fresh object literal
|
||||
ArrayLiteral = 1 << 16, // Originates in an array literal
|
||||
ObjectRestType = 1 << 17, // Originates in object rest declaration
|
||||
JSLiteral = 1 << 13, // Object type declared in JS - disables errors on read/write of nonexisting members
|
||||
FreshLiteral = 1 << 14, // Fresh object literal
|
||||
ArrayLiteral = 1 << 15, // Originates in an array literal
|
||||
ObjectRestType = 1 << 16, // Originates in object rest declaration
|
||||
/* @internal */
|
||||
PrimitiveUnion = 1 << 18, // Union of only primitive types
|
||||
PrimitiveUnion = 1 << 17, // Union of only primitive types
|
||||
/* @internal */
|
||||
ContainsWideningType = 1 << 19, // Type is or contains undefined or null widening type
|
||||
ContainsWideningType = 1 << 18, // Type is or contains undefined or null widening type
|
||||
/* @internal */
|
||||
ContainsObjectOrArrayLiteral = 1 << 20, // Type is or contains object literal type
|
||||
ContainsObjectOrArrayLiteral = 1 << 19, // Type is or contains object literal type
|
||||
/* @internal */
|
||||
NonInferrableType = 1 << 21, // Type is or contains anyFunctionType or silentNeverType
|
||||
NonInferrableType = 1 << 20, // Type is or contains anyFunctionType or silentNeverType
|
||||
ClassOrInterface = Class | Interface,
|
||||
/* @internal */
|
||||
RequiresWidening = ContainsWideningType | ContainsObjectOrArrayLiteral,
|
||||
|
||||
Reference in New Issue
Block a user