@@ -444,10 +444,10 @@ namespace ts {
444
444
const circularConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
445
445
const resolvingDefaultType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
446
446
447
- const markerSuperType = <TypeParameter>createType(TypeFlags.TypeParameter );
448
- const markerSubType = <TypeParameter>createType(TypeFlags.TypeParameter );
447
+ const markerSuperType = createTypeParameter( );
448
+ const markerSubType = createTypeParameter( );
449
449
markerSubType.constraint = markerSuperType;
450
- const markerOtherType = <TypeParameter>createType(TypeFlags.TypeParameter );
450
+ const markerOtherType = createTypeParameter( );
451
451
452
452
const noTypePredicate = createIdentifierTypePredicate("<<unresolved>>", 0, anyType);
453
453
@@ -663,7 +663,6 @@ namespace ts {
663
663
664
664
const subtypeRelation = createMap<RelationComparisonResult>();
665
665
const assignableRelation = createMap<RelationComparisonResult>();
666
- const definitelyAssignableRelation = createMap<RelationComparisonResult>();
667
666
const comparableRelation = createMap<RelationComparisonResult>();
668
667
const identityRelation = createMap<RelationComparisonResult>();
669
668
const enumRelation = createMap<RelationComparisonResult>();
@@ -2745,6 +2744,12 @@ namespace ts {
2745
2744
return getUnionType(arrayFrom(typeofEQFacts.keys(), getLiteralType));
2746
2745
}
2747
2746
2747
+ function createTypeParameter(symbol?: Symbol) {
2748
+ const type = <TypeParameter>createType(TypeFlags.TypeParameter);
2749
+ if (symbol) type.symbol = symbol;
2750
+ return type;
2751
+ }
2752
+
2748
2753
// A reserved member name starts with two underscores, but the third character cannot be an underscore
2749
2754
// or the @ symbol. A third underscore indicates an escaped form of an identifer that started
2750
2755
// with at least two underscores. The @ character indicates that the name is denoted by a well known ES
@@ -6085,9 +6090,8 @@ namespace ts {
6085
6090
(<GenericType>type).instantiations.set(getTypeListId(type.typeParameters), <GenericType>type);
6086
6091
(<GenericType>type).target = <GenericType>type;
6087
6092
(<GenericType>type).typeArguments = type.typeParameters;
6088
- type.thisType = <TypeParameter>createType(TypeFlags.TypeParameter );
6093
+ type.thisType = createTypeParameter(symbol );
6089
6094
type.thisType.isThisType = true;
6090
- type.thisType.symbol = symbol;
6091
6095
type.thisType.constraint = type;
6092
6096
}
6093
6097
}
@@ -6228,20 +6232,12 @@ namespace ts {
6228
6232
6229
6233
function getDeclaredTypeOfTypeParameter(symbol: Symbol): TypeParameter {
6230
6234
const links = getSymbolLinks(symbol);
6231
- if (!links.declaredType) {
6232
- const type = <TypeParameter>createType(TypeFlags.TypeParameter);
6233
- type.symbol = symbol;
6234
- links.declaredType = type;
6235
- }
6236
- return <TypeParameter>links.declaredType;
6235
+ return links.declaredType || (links.declaredType = createTypeParameter(symbol));
6237
6236
}
6238
6237
6239
6238
function getDeclaredTypeOfAlias(symbol: Symbol): Type {
6240
6239
const links = getSymbolLinks(symbol);
6241
- if (!links.declaredType) {
6242
- links.declaredType = getDeclaredTypeOfSymbol(resolveAlias(symbol));
6243
- }
6244
- return links.declaredType;
6240
+ return links.declaredType || (links.declaredType = getDeclaredTypeOfSymbol(resolveAlias(symbol)));
6245
6241
}
6246
6242
6247
6243
function getDeclaredTypeOfSymbol(symbol: Symbol): Type {
@@ -7413,7 +7409,7 @@ namespace ts {
7413
7409
if (type.root.isDistributive) {
7414
7410
const simplified = getSimplifiedType(type.checkType);
7415
7411
const constraint = simplified === type.checkType ? getConstraintOfType(simplified) : simplified;
7416
- if (constraint) {
7412
+ if (constraint && constraint !== type.checkType ) {
7417
7413
const mapper = makeUnaryTypeMapper(type.root.checkType, constraint);
7418
7414
const instantiated = getConditionalTypeInstantiation(type, combineTypeMappers(mapper, type.mapper));
7419
7415
if (!(instantiated.flags & TypeFlags.Never)) {
@@ -9049,7 +9045,7 @@ namespace ts {
9049
9045
if (arity) {
9050
9046
typeParameters = new Array(arity);
9051
9047
for (let i = 0; i < arity; i++) {
9052
- const typeParameter = typeParameters[i] = <TypeParameter>createType(TypeFlags.TypeParameter );
9048
+ const typeParameter = typeParameters[i] = createTypeParameter( );
9053
9049
if (i < maxLength) {
9054
9050
const property = createSymbol(SymbolFlags.Property | (i >= minLength ? SymbolFlags.Optional : 0), "" + i as __String);
9055
9051
property.type = typeParameter;
@@ -9070,7 +9066,7 @@ namespace ts {
9070
9066
type.instantiations.set(getTypeListId(type.typeParameters), <GenericType>type);
9071
9067
type.target = <GenericType>type;
9072
9068
type.typeArguments = type.typeParameters;
9073
- type.thisType = <TypeParameter>createType(TypeFlags.TypeParameter );
9069
+ type.thisType = createTypeParameter( );
9074
9070
type.thisType.isThisType = true;
9075
9071
type.thisType.constraint = type;
9076
9072
type.declaredProperties = properties;
@@ -9971,7 +9967,7 @@ namespace ts {
9971
9967
if (checkType === wildcardType || extendsType === wildcardType) {
9972
9968
return wildcardType;
9973
9969
}
9974
- const checkTypeInstantiable = maybeTypeOfKind(checkType, TypeFlags.Instantiable);
9970
+ const checkTypeInstantiable = maybeTypeOfKind(checkType, TypeFlags.Instantiable | TypeFlags.GenericMappedType );
9975
9971
let combinedMapper: TypeMapper | undefined;
9976
9972
if (root.inferTypeParameters) {
9977
9973
const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None);
@@ -9986,7 +9982,7 @@ namespace ts {
9986
9982
// Instantiate the extends type including inferences for 'infer T' type parameters
9987
9983
const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType;
9988
9984
// We attempt to resolve the conditional type only when the check and extends types are non-generic
9989
- if (!checkTypeInstantiable && !maybeTypeOfKind(inferredExtendsType, TypeFlags.Instantiable)) {
9985
+ if (!checkTypeInstantiable && !maybeTypeOfKind(inferredExtendsType, TypeFlags.Instantiable | TypeFlags.GenericMappedType )) {
9990
9986
if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) {
9991
9987
return instantiateType(root.trueType, mapper);
9992
9988
}
@@ -9998,14 +9994,15 @@ namespace ts {
9998
9994
// types with type parameters mapped to the wildcard type, the most permissive instantiations
9999
9995
// possible (the wildcard type is assignable to and from all types). If those are not related,
10000
9996
// then no instatiations will be and we can just return the false branch type.
10001
- if (!isTypeAssignableTo(getWildcardInstantiation (checkType), getWildcardInstantiation (inferredExtendsType))) {
9997
+ if (!isTypeAssignableTo(getPermissiveInstantiation (checkType), getPermissiveInstantiation (inferredExtendsType))) {
10002
9998
return instantiateType(root.falseType, mapper);
10003
9999
}
10004
- // Return trueType for a definitely true extends check. The definitely assignable relation excludes
10005
- // type variable constraints from consideration. Without the definitely assignable relation, the type
10000
+ // Return trueType for a definitely true extends check. We check instantiations of the two
10001
+ // types with type parameters mapped to their restrictive form, i.e. a form of the type parameter
10002
+ // that has no constraint. This ensures that, for example, the type
10006
10003
// type Foo<T extends { x: any }> = T extends { x: string } ? string : number
10007
- // would immediately resolve to 'string' instead of being deferred.
10008
- if (checkTypeRelatedTo( checkType, inferredExtendsType, definitelyAssignableRelation, /*errorNode*/ undefined )) {
10004
+ // doesn't immediately resolve to 'string' instead of being deferred.
10005
+ if (isTypeAssignableTo(getRestrictiveInstantiation( checkType), getRestrictiveInstantiation( inferredExtendsType) )) {
10009
10006
return instantiateType(root.trueType, combinedMapper || mapper);
10010
10007
}
10011
10008
}
@@ -10611,13 +10608,20 @@ namespace ts {
10611
10608
return t => t === source ? target : baseMapper(t);
10612
10609
}
10613
10610
10614
- function wildcardMapper (type: Type) {
10611
+ function permissiveMapper (type: Type) {
10615
10612
return type.flags & TypeFlags.TypeParameter ? wildcardType : type;
10616
10613
}
10617
10614
10615
+ function getRestrictiveTypeParameter(tp: TypeParameter) {
10616
+ return !tp.constraint ? tp : tp.restrictiveInstantiation || (tp.restrictiveInstantiation = createTypeParameter(tp.symbol));
10617
+ }
10618
+
10619
+ function restrictiveMapper(type: Type) {
10620
+ return type.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(<TypeParameter>type) : type;
10621
+ }
10622
+
10618
10623
function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
10619
- const result = <TypeParameter>createType(TypeFlags.TypeParameter);
10620
- result.symbol = typeParameter.symbol;
10624
+ const result = createTypeParameter(typeParameter.symbol);
10621
10625
result.target = typeParameter;
10622
10626
return result;
10623
10627
}
@@ -10969,9 +10973,14 @@ namespace ts {
10969
10973
return type;
10970
10974
}
10971
10975
10972
- function getWildcardInstantiation (type: Type) {
10976
+ function getPermissiveInstantiation (type: Type) {
10973
10977
return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type :
10974
- type.wildcardInstantiation || (type.wildcardInstantiation = instantiateType(type, wildcardMapper));
10978
+ type.permissiveInstantiation || (type.permissiveInstantiation = instantiateType(type, permissiveMapper));
10979
+ }
10980
+
10981
+ function getRestrictiveInstantiation(type: Type) {
10982
+ return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type :
10983
+ type.restrictiveInstantiation || (type.restrictiveInstantiation = instantiateType(type, restrictiveMapper));
10975
10984
}
10976
10985
10977
10986
function instantiateIndexInfo(info: IndexInfo | undefined, mapper: TypeMapper): IndexInfo | undefined {
@@ -11644,7 +11653,7 @@ namespace ts {
11644
11653
if (s & TypeFlags.Null && (!strictNullChecks || t & TypeFlags.Null)) return true;
11645
11654
if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive) return true;
11646
11655
if (s & TypeFlags.UniqueESSymbol || t & TypeFlags.UniqueESSymbol) return false;
11647
- if (relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) {
11656
+ if (relation === assignableRelation || relation === comparableRelation) {
11648
11657
if (s & TypeFlags.Any) return true;
11649
11658
// Type number or any numeric literal type is assignable to any numeric enum type or any
11650
11659
// numeric enum literal type. This rule exists for backwards compatibility reasons because
@@ -11836,7 +11845,7 @@ namespace ts {
11836
11845
target = (<FreshableType>target).regularType;
11837
11846
}
11838
11847
if (source.flags & TypeFlags.Substitution) {
11839
- source = relation === definitelyAssignableRelation ? (<SubstitutionType>source).typeVariable : (<SubstitutionType>source).substitute;
11848
+ source = (<SubstitutionType>source).substitute;
11840
11849
}
11841
11850
if (target.flags & TypeFlags.Substitution) {
11842
11851
target = (<SubstitutionType>target).typeVariable;
@@ -12022,7 +12031,7 @@ namespace ts {
12022
12031
}
12023
12032
if (isExcessPropertyCheckTarget(target)) {
12024
12033
const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
12025
- if ((relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) &&
12034
+ if ((relation === assignableRelation || relation === comparableRelation) &&
12026
12035
(isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) {
12027
12036
return false;
12028
12037
}
@@ -12425,24 +12434,22 @@ namespace ts {
12425
12434
}
12426
12435
// A type S is assignable to keyof T if S is assignable to keyof C, where C is the
12427
12436
// simplified form of T or, if T doesn't simplify, the constraint of T.
12428
- if (relation !== definitelyAssignableRelation) {
12429
- const simplified = getSimplifiedType((<IndexType>target).type);
12430
- const constraint = simplified !== (<IndexType>target).type ? simplified : getConstraintOfType((<IndexType>target).type);
12431
- if (constraint) {
12432
- // We require Ternary.True here such that circular constraints don't cause
12433
- // false positives. For example, given 'T extends { [K in keyof T]: string }',
12434
- // 'keyof T' has itself as its constraint and produces a Ternary.Maybe when
12435
- // related to other types.
12436
- if (isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors) === Ternary.True) {
12437
- return Ternary.True;
12438
- }
12437
+ const simplified = getSimplifiedType((<IndexType>target).type);
12438
+ const constraint = simplified !== (<IndexType>target).type ? simplified : getConstraintOfType((<IndexType>target).type);
12439
+ if (constraint) {
12440
+ // We require Ternary.True here such that circular constraints don't cause
12441
+ // false positives. For example, given 'T extends { [K in keyof T]: string }',
12442
+ // 'keyof T' has itself as its constraint and produces a Ternary.Maybe when
12443
+ // related to other types.
12444
+ if (isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors) === Ternary.True) {
12445
+ return Ternary.True;
12439
12446
}
12440
12447
}
12441
12448
}
12442
12449
else if (target.flags & TypeFlags.IndexedAccess) {
12443
12450
// A type S is related to a type T[K], where T and K aren't both type variables, if S is related to C,
12444
12451
// where C is the base constraint of T[K]
12445
- if (relation !== identityRelation && relation !== definitelyAssignableRelation &&
12452
+ if (relation !== identityRelation &&
12446
12453
!(isGenericObjectType((<IndexedAccessType>target).objectType) && isGenericIndexType((<IndexedAccessType>target).indexType))) {
12447
12454
const constraint = getBaseConstraintOfType(target);
12448
12455
if (constraint && constraint !== target) {
@@ -12485,26 +12492,24 @@ namespace ts {
12485
12492
return result;
12486
12493
}
12487
12494
}
12488
- if (relation !== definitelyAssignableRelation) {
12489
- const constraint = getConstraintOfType(<TypeParameter>source);
12490
- if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
12491
- // A type variable with no constraint is not related to the non-primitive object type.
12492
- if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
12493
- errorInfo = saveErrorInfo;
12494
- return result;
12495
- }
12496
- }
12497
- // hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed
12498
- else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
12499
- errorInfo = saveErrorInfo;
12500
- return result;
12501
- }
12502
- // slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
12503
- else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
12495
+ const constraint = getConstraintOfType(<TypeParameter>source);
12496
+ if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
12497
+ // A type variable with no constraint is not related to the non-primitive object type.
12498
+ if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
12504
12499
errorInfo = saveErrorInfo;
12505
12500
return result;
12506
12501
}
12507
12502
}
12503
+ // hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed
12504
+ else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
12505
+ errorInfo = saveErrorInfo;
12506
+ return result;
12507
+ }
12508
+ // slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
12509
+ else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
12510
+ errorInfo = saveErrorInfo;
12511
+ return result;
12512
+ }
12508
12513
}
12509
12514
else if (source.flags & TypeFlags.Index) {
12510
12515
if (result = isRelatedTo(keyofConstraintType, target, reportErrors)) {
@@ -12528,7 +12533,7 @@ namespace ts {
12528
12533
}
12529
12534
}
12530
12535
}
12531
- else if (relation !== definitelyAssignableRelation) {
12536
+ else {
12532
12537
const distributiveConstraint = getConstraintOfDistributiveConditionalType(<ConditionalType>source);
12533
12538
if (distributiveConstraint) {
12534
12539
if (result = isRelatedTo(distributiveConstraint, target, reportErrors)) {
@@ -12559,9 +12564,6 @@ namespace ts {
12559
12564
}
12560
12565
return Ternary.False;
12561
12566
}
12562
- if (relation === definitelyAssignableRelation && isGenericMappedType(source)) {
12563
- return Ternary.False;
12564
- }
12565
12567
const sourceIsPrimitive = !!(source.flags & TypeFlags.Primitive);
12566
12568
if (relation !== identityRelation) {
12567
12569
source = getApparentType(source);
0 commit comments