diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index de7c5145764..9c55f0cf8ea 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14902,40 +14902,35 @@ namespace ts { return !!(type.flags & TypeFlags.TemplateLiteral) && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType); } + function isGenericType(type: Type): boolean { + return !!getGenericObjectFlags(type); + } + function isGenericObjectType(type: Type): boolean { - if (type.flags & TypeFlags.UnionOrIntersection) { - if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericObjectTypeComputed)) { - (type as UnionOrIntersectionType).objectFlags |= ObjectFlags.IsGenericObjectTypeComputed | - (some((type as UnionOrIntersectionType).types, isGenericObjectType) ? ObjectFlags.IsGenericObjectType : 0); - } - return !!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericObjectType); - } - if (type.flags & TypeFlags.Substitution) { - if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericObjectTypeComputed)) { - (type as SubstitutionType).objectFlags |= ObjectFlags.IsGenericObjectTypeComputed | - (isGenericObjectType((type as SubstitutionType).substitute) || isGenericObjectType((type as SubstitutionType).baseType) ? ObjectFlags.IsGenericObjectType : 0); - } - return !!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericObjectType); - } - return !!(type.flags & TypeFlags.InstantiableNonPrimitive) || isGenericMappedType(type) || isGenericTupleType(type); + return !!(getGenericObjectFlags(type) & ObjectFlags.IsGenericObjectType); } function isGenericIndexType(type: Type): boolean { + return !!(getGenericObjectFlags(type) & ObjectFlags.IsGenericIndexType); + } + + function getGenericObjectFlags(type: Type): ObjectFlags { if (type.flags & TypeFlags.UnionOrIntersection) { - if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericIndexTypeComputed)) { - (type as UnionOrIntersectionType).objectFlags |= ObjectFlags.IsGenericIndexTypeComputed | - (some((type as UnionOrIntersectionType).types, isGenericIndexType) ? ObjectFlags.IsGenericIndexType : 0); + if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { + (type as UnionOrIntersectionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | + reduceLeft((type as UnionOrIntersectionType).types, (flags, t) => flags | getGenericObjectFlags(t), 0); } - return !!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericIndexType); + return (type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericType; } if (type.flags & TypeFlags.Substitution) { - if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericIndexTypeComputed)) { - (type as SubstitutionType).objectFlags |= ObjectFlags.IsGenericIndexTypeComputed | - (isGenericIndexType((type as SubstitutionType).substitute) || isGenericIndexType((type as SubstitutionType).baseType) ? ObjectFlags.IsGenericIndexType : 0); + if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { + (type as SubstitutionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | + getGenericObjectFlags((type as SubstitutionType).substitute) | getGenericObjectFlags((type as SubstitutionType).baseType); } - return !!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericIndexType); + return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType; } - return !!(type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping)) && !isPatternLiteralType(type); + return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) | + (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0); } function isThisTypeParameter(type: Type): boolean { @@ -15212,7 +15207,7 @@ namespace ts { while (true) { const isUnwrapped = isTypicalNondistributiveConditional(root); const checkType = instantiateType(unwrapNondistributiveConditionalTuple(root, getActualTypeVariable(root.checkType)), mapper); - const checkTypeInstantiable = isGenericObjectType(checkType) || isGenericIndexType(checkType); + const checkTypeInstantiable = isGenericType(checkType); const extendsType = instantiateType(unwrapNondistributiveConditionalTuple(root, root.extendsType), mapper); if (checkType === wildcardType || extendsType === wildcardType) { return wildcardType; @@ -15234,7 +15229,7 @@ namespace ts { // Instantiate the extends type including inferences for 'infer T' type parameters const inferredExtendsType = combinedMapper ? instantiateType(unwrapNondistributiveConditionalTuple(root, root.extendsType), combinedMapper) : extendsType; // We attempt to resolve the conditional type only when the check and extends types are non-generic - if (!checkTypeInstantiable && !isGenericObjectType(inferredExtendsType) && !isGenericIndexType(inferredExtendsType)) { + if (!checkTypeInstantiable && !isGenericType(inferredExtendsType)) { // Return falseType for a definitely false extends check. We check an instantiations of the two // types with type parameters mapped to the wildcard type, the most permissive instantiations // possible (the wildcard type is assignable to and from all types). If those are not related, @@ -24269,17 +24264,13 @@ namespace ts { return !!(type.flags & TypeFlags.Instantiable && !maybeTypeOfKind(getBaseConstraintOrType(type), TypeFlags.Nullable)); } - function containsGenericType(type: Type): boolean { - return !!(type.flags & TypeFlags.Instantiable || type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, containsGenericType)); - } - function hasNonBindingPatternContextualTypeWithNoGenericTypes(node: Node) { // Computing the contextual type for a child of a JSX element involves resolving the type of the // element's tag name, so we exclude that here to avoid circularities. const contextualType = (isIdentifier(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node)) && !((isJsxOpeningElement(node.parent) || isJsxSelfClosingElement(node.parent)) && node.parent.tagName === node) && getContextualType(node, ContextFlags.SkipBindingPatterns); - return contextualType && !someType(contextualType, containsGenericType); + return contextualType && !isGenericType(contextualType); } function getNarrowableTypeForReference(type: Type, reference: Node, checkMode?: CheckMode) { @@ -41659,7 +41650,7 @@ namespace ts { return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_must_have_a_type_annotation); } const type = getTypeFromTypeNode(parameter.type); - if (someType(type, t => !!(t.flags & TypeFlags.StringOrNumberLiteralOrUnique)) || isGenericIndexType(type) || isGenericObjectType(type)) { + if (someType(type, t => !!(t.flags & TypeFlags.StringOrNumberLiteralOrUnique)) || isGenericType(type)) { return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead); } if (!everyType(type, isValidIndexKeyType)) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index bf507176907..4d13e803fb9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5266,23 +5266,23 @@ namespace ts { // Flags that require TypeFlags.UnionOrIntersection or TypeFlags.Substitution /* @internal */ - IsGenericObjectTypeComputed = 1 << 22, // IsGenericObjectType flag has been computed + IsGenericTypeComputed = 1 << 22, // IsGenericObjectType flag has been computed /* @internal */ IsGenericObjectType = 1 << 23, // Union or intersection contains generic object type /* @internal */ - IsGenericIndexTypeComputed = 1 << 24, // IsGenericIndexType flag has been computed + IsGenericIndexType = 1 << 24, // Union or intersection contains generic index type /* @internal */ - IsGenericIndexType = 1 << 25, // Union or intersection contains generic index type + IsGenericType = IsGenericObjectType | IsGenericIndexType, // Flags that require TypeFlags.Union /* @internal */ - ContainsIntersections = 1 << 26, // Union contains intersections + ContainsIntersections = 1 << 25, // Union contains intersections // Flags that require TypeFlags.Intersection /* @internal */ - IsNeverIntersectionComputed = 1 << 26, // IsNeverLike flag has been computed + IsNeverIntersectionComputed = 1 << 25, // IsNeverLike flag has been computed /* @internal */ - IsNeverIntersection = 1 << 27, // Intersection reduces to never + IsNeverIntersection = 1 << 26, // Intersection reduces to never } /* @internal */ diff --git a/tests/baselines/reference/controlFlowGenericTypes.errors.txt b/tests/baselines/reference/controlFlowGenericTypes.errors.txt index d6bd2aba7be..620c3ebb6d5 100644 --- a/tests/baselines/reference/controlFlowGenericTypes.errors.txt +++ b/tests/baselines/reference/controlFlowGenericTypes.errors.txt @@ -204,4 +204,20 @@ tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts(168,9): error TS2 iSpec[null! as keyof PublicSpec]; } } + + // Repros from #45145 + + function f10(x: T, y: Partial) { + y = x; + } + + type SqlInsertSet = T extends undefined ? object : { [P in keyof T]: unknown }; + + class SqlTable { + protected validateRow(_row: Partial>): void { + } + public insertRow(row: SqlInsertSet) { + this.validateRow(row); + } + } \ No newline at end of file diff --git a/tests/baselines/reference/controlFlowGenericTypes.js b/tests/baselines/reference/controlFlowGenericTypes.js index d6acd179b69..d080434b17c 100644 --- a/tests/baselines/reference/controlFlowGenericTypes.js +++ b/tests/baselines/reference/controlFlowGenericTypes.js @@ -174,6 +174,22 @@ class TableBaseEnum< iSpec[null! as keyof PublicSpec]; } } + +// Repros from #45145 + +function f10(x: T, y: Partial) { + y = x; +} + +type SqlInsertSet = T extends undefined ? object : { [P in keyof T]: unknown }; + +class SqlTable { + protected validateRow(_row: Partial>): void { + } + public insertRow(row: SqlInsertSet) { + this.validateRow(row); + } +} //// [controlFlowGenericTypes.js] @@ -313,3 +329,17 @@ var TableBaseEnum = /** @class */ (function () { }; return TableBaseEnum; }()); +// Repros from #45145 +function f10(x, y) { + y = x; +} +var SqlTable = /** @class */ (function () { + function SqlTable() { + } + SqlTable.prototype.validateRow = function (_row) { + }; + SqlTable.prototype.insertRow = function (row) { + this.validateRow(row); + }; + return SqlTable; +}()); diff --git a/tests/baselines/reference/controlFlowGenericTypes.symbols b/tests/baselines/reference/controlFlowGenericTypes.symbols index 0ea62c53221..c940c7983d6 100644 --- a/tests/baselines/reference/controlFlowGenericTypes.symbols +++ b/tests/baselines/reference/controlFlowGenericTypes.symbols @@ -525,3 +525,52 @@ class TableBaseEnum< } } +// Repros from #45145 + +function f10(x: T, y: Partial) { +>f10 : Symbol(f10, Decl(controlFlowGenericTypes.ts, 174, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 178, 13)) +>a : Symbol(a, Decl(controlFlowGenericTypes.ts, 178, 24)) +>x : Symbol(x, Decl(controlFlowGenericTypes.ts, 178, 50)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 178, 13)) +>y : Symbol(y, Decl(controlFlowGenericTypes.ts, 178, 55)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 178, 13)) + + y = x; +>y : Symbol(y, Decl(controlFlowGenericTypes.ts, 178, 55)) +>x : Symbol(x, Decl(controlFlowGenericTypes.ts, 178, 50)) +} + +type SqlInsertSet = T extends undefined ? object : { [P in keyof T]: unknown }; +>SqlInsertSet : Symbol(SqlInsertSet, Decl(controlFlowGenericTypes.ts, 180, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 182, 18)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 182, 18)) +>P : Symbol(P, Decl(controlFlowGenericTypes.ts, 182, 57)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 182, 18)) + +class SqlTable { +>SqlTable : Symbol(SqlTable, Decl(controlFlowGenericTypes.ts, 182, 82)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 184, 15)) + + protected validateRow(_row: Partial>): void { +>validateRow : Symbol(SqlTable.validateRow, Decl(controlFlowGenericTypes.ts, 184, 19)) +>_row : Symbol(_row, Decl(controlFlowGenericTypes.ts, 185, 26)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>SqlInsertSet : Symbol(SqlInsertSet, Decl(controlFlowGenericTypes.ts, 180, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 184, 15)) + } + public insertRow(row: SqlInsertSet) { +>insertRow : Symbol(SqlTable.insertRow, Decl(controlFlowGenericTypes.ts, 186, 5)) +>row : Symbol(row, Decl(controlFlowGenericTypes.ts, 187, 21)) +>SqlInsertSet : Symbol(SqlInsertSet, Decl(controlFlowGenericTypes.ts, 180, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 184, 15)) + + this.validateRow(row); +>this.validateRow : Symbol(SqlTable.validateRow, Decl(controlFlowGenericTypes.ts, 184, 19)) +>this : Symbol(SqlTable, Decl(controlFlowGenericTypes.ts, 182, 82)) +>validateRow : Symbol(SqlTable.validateRow, Decl(controlFlowGenericTypes.ts, 184, 19)) +>row : Symbol(row, Decl(controlFlowGenericTypes.ts, 187, 21)) + } +} + diff --git a/tests/baselines/reference/controlFlowGenericTypes.types b/tests/baselines/reference/controlFlowGenericTypes.types index 69b5854360d..5bf18f4e37a 100644 --- a/tests/baselines/reference/controlFlowGenericTypes.types +++ b/tests/baselines/reference/controlFlowGenericTypes.types @@ -505,3 +505,40 @@ class TableBaseEnum< } } +// Repros from #45145 + +function f10(x: T, y: Partial) { +>f10 : (x: T, y: Partial) => void +>a : string +>x : T +>y : Partial + + y = x; +>y = x : T +>y : Partial +>x : T +} + +type SqlInsertSet = T extends undefined ? object : { [P in keyof T]: unknown }; +>SqlInsertSet : SqlInsertSet + +class SqlTable { +>SqlTable : SqlTable + + protected validateRow(_row: Partial>): void { +>validateRow : (_row: Partial>) => void +>_row : Partial> + } + public insertRow(row: SqlInsertSet) { +>insertRow : (row: SqlInsertSet) => void +>row : SqlInsertSet + + this.validateRow(row); +>this.validateRow(row) : void +>this.validateRow : (_row: Partial>) => void +>this : this +>validateRow : (_row: Partial>) => void +>row : SqlInsertSet + } +} + diff --git a/tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts b/tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts index 7c38ee8c671..f2cac082f5e 100644 --- a/tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts +++ b/tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts @@ -175,3 +175,19 @@ class TableBaseEnum< iSpec[null! as keyof PublicSpec]; } } + +// Repros from #45145 + +function f10(x: T, y: Partial) { + y = x; +} + +type SqlInsertSet = T extends undefined ? object : { [P in keyof T]: unknown }; + +class SqlTable { + protected validateRow(_row: Partial>): void { + } + public insertRow(row: SqlInsertSet) { + this.validateRow(row); + } +}