@@ -444,10 +444,10 @@ namespace ts {
444444 const circularConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
445445 const resolvingDefaultType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
446446
447- const markerSuperType = <TypeParameter>createType(TypeFlags.TypeParameter );
448- const markerSubType = <TypeParameter>createType(TypeFlags.TypeParameter );
447+ const markerSuperType = createTypeParameter( );
448+ const markerSubType = createTypeParameter( );
449449 markerSubType.constraint = markerSuperType;
450- const markerOtherType = <TypeParameter>createType(TypeFlags.TypeParameter );
450+ const markerOtherType = createTypeParameter( );
451451
452452 const noTypePredicate = createIdentifierTypePredicate("<<unresolved>>", 0, anyType);
453453
@@ -663,7 +663,6 @@ namespace ts {
663663
664664 const subtypeRelation = createMap<RelationComparisonResult>();
665665 const assignableRelation = createMap<RelationComparisonResult>();
666- const definitelyAssignableRelation = createMap<RelationComparisonResult>();
667666 const comparableRelation = createMap<RelationComparisonResult>();
668667 const identityRelation = createMap<RelationComparisonResult>();
669668 const enumRelation = createMap<RelationComparisonResult>();
@@ -2745,6 +2744,12 @@ namespace ts {
27452744 return getUnionType(arrayFrom(typeofEQFacts.keys(), getLiteralType));
27462745 }
27472746
2747+ function createTypeParameter(symbol?: Symbol) {
2748+ const type = <TypeParameter>createType(TypeFlags.TypeParameter);
2749+ if (symbol) type.symbol = symbol;
2750+ return type;
2751+ }
2752+
27482753 // A reserved member name starts with two underscores, but the third character cannot be an underscore
27492754 // or the @ symbol. A third underscore indicates an escaped form of an identifer that started
27502755 // with at least two underscores. The @ character indicates that the name is denoted by a well known ES
@@ -6085,9 +6090,8 @@ namespace ts {
60856090 (<GenericType>type).instantiations.set(getTypeListId(type.typeParameters), <GenericType>type);
60866091 (<GenericType>type).target = <GenericType>type;
60876092 (<GenericType>type).typeArguments = type.typeParameters;
6088- type.thisType = <TypeParameter>createType(TypeFlags.TypeParameter );
6093+ type.thisType = createTypeParameter(symbol );
60896094 type.thisType.isThisType = true;
6090- type.thisType.symbol = symbol;
60916095 type.thisType.constraint = type;
60926096 }
60936097 }
@@ -6228,20 +6232,12 @@ namespace ts {
62286232
62296233 function getDeclaredTypeOfTypeParameter(symbol: Symbol): TypeParameter {
62306234 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));
62376236 }
62386237
62396238 function getDeclaredTypeOfAlias(symbol: Symbol): Type {
62406239 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)));
62456241 }
62466242
62476243 function getDeclaredTypeOfSymbol(symbol: Symbol): Type {
@@ -7413,7 +7409,7 @@ namespace ts {
74137409 if (type.root.isDistributive) {
74147410 const simplified = getSimplifiedType(type.checkType);
74157411 const constraint = simplified === type.checkType ? getConstraintOfType(simplified) : simplified;
7416- if (constraint) {
7412+ if (constraint && constraint !== type.checkType ) {
74177413 const mapper = makeUnaryTypeMapper(type.root.checkType, constraint);
74187414 const instantiated = getConditionalTypeInstantiation(type, combineTypeMappers(mapper, type.mapper));
74197415 if (!(instantiated.flags & TypeFlags.Never)) {
@@ -9049,7 +9045,7 @@ namespace ts {
90499045 if (arity) {
90509046 typeParameters = new Array(arity);
90519047 for (let i = 0; i < arity; i++) {
9052- const typeParameter = typeParameters[i] = <TypeParameter>createType(TypeFlags.TypeParameter );
9048+ const typeParameter = typeParameters[i] = createTypeParameter( );
90539049 if (i < maxLength) {
90549050 const property = createSymbol(SymbolFlags.Property | (i >= minLength ? SymbolFlags.Optional : 0), "" + i as __String);
90559051 property.type = typeParameter;
@@ -9070,7 +9066,7 @@ namespace ts {
90709066 type.instantiations.set(getTypeListId(type.typeParameters), <GenericType>type);
90719067 type.target = <GenericType>type;
90729068 type.typeArguments = type.typeParameters;
9073- type.thisType = <TypeParameter>createType(TypeFlags.TypeParameter );
9069+ type.thisType = createTypeParameter( );
90749070 type.thisType.isThisType = true;
90759071 type.thisType.constraint = type;
90769072 type.declaredProperties = properties;
@@ -9971,7 +9967,7 @@ namespace ts {
99719967 if (checkType === wildcardType || extendsType === wildcardType) {
99729968 return wildcardType;
99739969 }
9974- const checkTypeInstantiable = maybeTypeOfKind(checkType, TypeFlags.Instantiable);
9970+ const checkTypeInstantiable = maybeTypeOfKind(checkType, TypeFlags.Instantiable | TypeFlags.GenericMappedType );
99759971 let combinedMapper: TypeMapper | undefined;
99769972 if (root.inferTypeParameters) {
99779973 const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None);
@@ -9986,7 +9982,7 @@ namespace ts {
99869982 // Instantiate the extends type including inferences for 'infer T' type parameters
99879983 const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType;
99889984 // 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 )) {
99909986 if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) {
99919987 return instantiateType(root.trueType, mapper);
99929988 }
@@ -9998,14 +9994,15 @@ namespace ts {
99989994 // types with type parameters mapped to the wildcard type, the most permissive instantiations
99999995 // possible (the wildcard type is assignable to and from all types). If those are not related,
100009996 // 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))) {
100029998 return instantiateType(root.falseType, mapper);
100039999 }
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
1000610003 // 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) )) {
1000910006 return instantiateType(root.trueType, combinedMapper || mapper);
1001010007 }
1001110008 }
@@ -10611,13 +10608,20 @@ namespace ts {
1061110608 return t => t === source ? target : baseMapper(t);
1061210609 }
1061310610
10614- function wildcardMapper (type: Type) {
10611+ function permissiveMapper (type: Type) {
1061510612 return type.flags & TypeFlags.TypeParameter ? wildcardType : type;
1061610613 }
1061710614
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+
1061810623 function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
10619- const result = <TypeParameter>createType(TypeFlags.TypeParameter);
10620- result.symbol = typeParameter.symbol;
10624+ const result = createTypeParameter(typeParameter.symbol);
1062110625 result.target = typeParameter;
1062210626 return result;
1062310627 }
@@ -10969,9 +10973,14 @@ namespace ts {
1096910973 return type;
1097010974 }
1097110975
10972- function getWildcardInstantiation (type: Type) {
10976+ function getPermissiveInstantiation (type: Type) {
1097310977 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));
1097510984 }
1097610985
1097710986 function instantiateIndexInfo(info: IndexInfo | undefined, mapper: TypeMapper): IndexInfo | undefined {
@@ -11644,7 +11653,7 @@ namespace ts {
1164411653 if (s & TypeFlags.Null && (!strictNullChecks || t & TypeFlags.Null)) return true;
1164511654 if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive) return true;
1164611655 if (s & TypeFlags.UniqueESSymbol || t & TypeFlags.UniqueESSymbol) return false;
11647- if (relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) {
11656+ if (relation === assignableRelation || relation === comparableRelation) {
1164811657 if (s & TypeFlags.Any) return true;
1164911658 // Type number or any numeric literal type is assignable to any numeric enum type or any
1165011659 // numeric enum literal type. This rule exists for backwards compatibility reasons because
@@ -11836,7 +11845,7 @@ namespace ts {
1183611845 target = (<FreshableType>target).regularType;
1183711846 }
1183811847 if (source.flags & TypeFlags.Substitution) {
11839- source = relation === definitelyAssignableRelation ? (<SubstitutionType>source).typeVariable : (<SubstitutionType>source).substitute;
11848+ source = (<SubstitutionType>source).substitute;
1184011849 }
1184111850 if (target.flags & TypeFlags.Substitution) {
1184211851 target = (<SubstitutionType>target).typeVariable;
@@ -12022,7 +12031,7 @@ namespace ts {
1202212031 }
1202312032 if (isExcessPropertyCheckTarget(target)) {
1202412033 const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
12025- if ((relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) &&
12034+ if ((relation === assignableRelation || relation === comparableRelation) &&
1202612035 (isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) {
1202712036 return false;
1202812037 }
@@ -12425,24 +12434,22 @@ namespace ts {
1242512434 }
1242612435 // A type S is assignable to keyof T if S is assignable to keyof C, where C is the
1242712436 // 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;
1243912446 }
1244012447 }
1244112448 }
1244212449 else if (target.flags & TypeFlags.IndexedAccess) {
1244312450 // 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,
1244412451 // where C is the base constraint of T[K]
12445- if (relation !== identityRelation && relation !== definitelyAssignableRelation &&
12452+ if (relation !== identityRelation &&
1244612453 !(isGenericObjectType((<IndexedAccessType>target).objectType) && isGenericIndexType((<IndexedAccessType>target).indexType))) {
1244712454 const constraint = getBaseConstraintOfType(target);
1244812455 if (constraint && constraint !== target) {
@@ -12485,26 +12492,24 @@ namespace ts {
1248512492 return result;
1248612493 }
1248712494 }
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))) {
1250412499 errorInfo = saveErrorInfo;
1250512500 return result;
1250612501 }
1250712502 }
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+ }
1250812513 }
1250912514 else if (source.flags & TypeFlags.Index) {
1251012515 if (result = isRelatedTo(keyofConstraintType, target, reportErrors)) {
@@ -12528,7 +12533,7 @@ namespace ts {
1252812533 }
1252912534 }
1253012535 }
12531- else if (relation !== definitelyAssignableRelation) {
12536+ else {
1253212537 const distributiveConstraint = getConstraintOfDistributiveConditionalType(<ConditionalType>source);
1253312538 if (distributiveConstraint) {
1253412539 if (result = isRelatedTo(distributiveConstraint, target, reportErrors)) {
@@ -12559,9 +12564,6 @@ namespace ts {
1255912564 }
1256012565 return Ternary.False;
1256112566 }
12562- if (relation === definitelyAssignableRelation && isGenericMappedType(source)) {
12563- return Ternary.False;
12564- }
1256512567 const sourceIsPrimitive = !!(source.flags & TypeFlags.Primitive);
1256612568 if (relation !== identityRelation) {
1256712569 source = getApparentType(source);
0 commit comments