Skip to content

Commit e7547a1

Browse files
committed
Do the same, but with only string manipulations
1 parent b3856bd commit e7547a1

File tree

1 file changed

+9
-70
lines changed

1 file changed

+9
-70
lines changed

src/compiler/checker.ts

Lines changed: 9 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -17699,9 +17699,16 @@ namespace ts {
1769917699
targetStack = [];
1770017700
}
1770117701
else {
17702+
// generate a key where all type parameter id positions are replaced with unconstrained type parameter ids
17703+
// this isn't perfect - nested type references passed as type arguments will muck up the indexes and thus
17704+
// prevent finding matches- but it should hit up the common cases
17705+
const broadestEquivalentId = id.split(",").map(i => i.replace(/-\d+/g, (_match, offset: number) => {
17706+
const index = length(id.slice(0, offset).match(/[-=]/g) || undefined);
17707+
return `=${index}`;
17708+
})).join(",");
1770217709
for (let i = 0; i < maybeCount; i++) {
1770317710
// If source and target are already being compared, consider them related with assumptions
17704-
if (id === maybeKeys[i]) {
17711+
if (id === maybeKeys[i] || broadestEquivalentId === maybeKeys[i]) {
1770517712
return Ternary.Maybe;
1770617713
}
1770717714
}
@@ -17773,13 +17780,6 @@ namespace ts {
1777317780
return result;
1777417781
}
1777517782

17776-
function getInstanceOfAliasOrReferenceWithMarker(input: Type, typeArguments: readonly Type[]) {
17777-
const s = input.aliasSymbol ? getTypeAliasInstantiation(input.aliasSymbol, typeArguments) : createTypeReference((<TypeReference>input).target, typeArguments);
17778-
if (s.aliasSymbol) s.aliasTypeArgumentsContainsMarker = true;
17779-
else (<TypeReference>s).objectFlags |= ObjectFlags.MarkerType;
17780-
return s;
17781-
}
17782-
1778317783
function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
1778417784
if (intersectionState & IntersectionState.PropertyCheck) {
1778517785
return propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, IntersectionState.None);
@@ -17868,67 +17868,6 @@ namespace ts {
1786817868
}
1786917869
}
1787017870

17871-
// If a more _general_ version of the source and target are being compared, consider them related with assumptions
17872-
// eg, if { x: Q } and { x: Q, y: A } are being compared and we're about to look at { x: Q' } and { x: Q', y: A } where Q'
17873-
// is some specialization or subtype of Q
17874-
// This is difficult to detect generally, so we scan for prior comparisons of the same instantiated type, and match up matching
17875-
// type arguments into sets to create a canonicalization based on those matches
17876-
if (relation !== identityRelation && ((source.aliasSymbol && !source.aliasTypeArgumentsContainsMarker && source.aliasTypeArguments) || (getObjectFlags(source) & ObjectFlags.Reference && !!getTypeArguments(<TypeReference>source).length && !(getObjectFlags(source) & ObjectFlags.MarkerType))) &&
17877-
((target.aliasSymbol && !target.aliasTypeArgumentsContainsMarker && target.aliasTypeArguments) || (getObjectFlags(target) & ObjectFlags.Reference && !!getTypeArguments(<TypeReference>target).length && !(getObjectFlags(target) & ObjectFlags.MarkerType)))) {
17878-
if (source.aliasSymbol || target.aliasSymbol || (<TypeReference>source).target !== (<TypeReference>target).target) { // ensure like symbols are just handled by standard variance analysis
17879-
const sourceTypeArguments = source.aliasTypeArguments || getTypeArguments(<TypeReference>source);
17880-
const sourceHasMarker = some(sourceTypeArguments, a => a === markerOtherType);
17881-
const targetTypeArguments = target.aliasTypeArguments || getTypeArguments(<TypeReference>target);
17882-
const targetHasMarker = some(targetTypeArguments, a => a === markerOtherType);
17883-
// We're using `markerOtherType` as an existential, so we can't use it again if it's already in use,
17884-
// as we'd get spurious equivalencies - we'd need to use a second existential type, and once we're doing
17885-
// that we lose a lot of the benefit of canonicalizing back to a single-existential comparison, since then
17886-
// we'd need to manufacture new type identities for every new existential we make
17887-
// The above checks don't catch all cases this can occur, as they can only detect when the containing type
17888-
// was flagged during construction as containing a marker; however if a marker enters a type through instantiation
17889-
// we need to catch that here.
17890-
// We only do this when there's a handful of possible ways to match the type parameters up, as otherwise we manufacture
17891-
// an inordinate quantity of types just to calculate their IDs!
17892-
if (!sourceHasMarker && !targetHasMarker && sourceTypeArguments.length * targetTypeArguments.length < 10) {
17893-
const originalKey = getRelationKey(source, target, intersectionState, relation);
17894-
for (let i = 0; i < sourceTypeArguments.length; i++) {
17895-
for (let j = 0; j < targetTypeArguments.length; j++) {
17896-
if ((!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && !isTypeAny(sourceTypeArguments[i]) && sourceTypeArguments[i] === targetTypeArguments[j]) ||
17897-
// Similarly, if we're comparing X<Q> to Z<any>, X<Q> is assignable to Z<any> trivially if X<?> is assignable to Z<?>
17898-
(!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && isTypeAny(targetTypeArguments[j])) ||
17899-
// Again, but for `X<any>` vs `Z<Q>`
17900-
(isTypeAny(sourceTypeArguments[i]) && !(targetTypeArguments[j].flags & TypeFlags.TypeParameter)) ||
17901-
// Likewise, if we're comparing X<U> to Z<U> and are already comparing X<T> to Z<T>, we can assume it to be true
17902-
!!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && sourceTypeArguments[i] === targetTypeArguments[j]) {
17903-
const sourceClone = sourceTypeArguments.slice();
17904-
sourceClone[i] = markerOtherType;
17905-
const s = getInstanceOfAliasOrReferenceWithMarker(source, sourceClone);
17906-
const targetClone = targetTypeArguments.slice();
17907-
targetClone[j] = markerOtherType;
17908-
const t = getInstanceOfAliasOrReferenceWithMarker(target, targetClone);
17909-
// If the marker-instantiated form looks "the same" as the type we already have (eg,
17910-
// because we replace unconstrained generics with unconstrained generics), skip the check
17911-
// since we'll otherwise deliver a spurious `Maybe` result from the key _just_ set upon
17912-
// entry into `recursiveTypeRelatedTo`
17913-
const existentialKey = getRelationKey(s, t, intersectionState, relation);
17914-
if (existentialKey !== originalKey) {
17915-
// We don't actually trigger the comparison, since we'd rather not do an extra comparison
17916-
// if we haven't already started that more general comparison; instead we just look for the
17917-
// key in the maybeKeys stack
17918-
for (let i = 0; i < maybeCount; i++) {
17919-
// If source and target are already being compared, consider them related with assumptions
17920-
if (existentialKey === maybeKeys[i]) {
17921-
return Ternary.Maybe;
17922-
}
17923-
}
17924-
}
17925-
}
17926-
}
17927-
}
17928-
}
17929-
}
17930-
}
17931-
1793217871
// For a generic type T and a type U that is assignable to T, [...U] is assignable to T, U is assignable to readonly [...T],
1793317872
// and U is assignable to [...T] when U is constrained to a mutable array or tuple type.
1793417873
if (isSingleElementGenericTupleType(source) && !source.target.readonly && (result = isRelatedTo(getTypeArguments(source)[0], target)) ||
@@ -19209,7 +19148,7 @@ namespace ts {
1920919148
}
1921019149

1921119150
function isTypeReferenceWithGenericArguments(type: Type): boolean {
19212-
return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t));
19151+
return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => !!(t.flags & TypeFlags.TypeParameter) || isTypeReferenceWithGenericArguments(t));
1921319152
}
1921419153

1921519154
/**

0 commit comments

Comments
 (0)