diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 170364db3fe17..3ac1101c0000d 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1434,6 +1434,8 @@ namespace ts { return ContainerFlags.IsContainer | ContainerFlags.HasLocals; case SyntaxKind.ConditionalType: + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: return ContainerFlags.IsInferenceContainer; case SyntaxKind.SourceFile: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2d9d0d189449d..d7a46b7b2eb48 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3021,6 +3021,11 @@ namespace ts { if (type.flags & TypeFlags.Substitution) { return typeToTypeNodeHelper((type).typeParameter, context); } + if (type.flags & TypeFlags.InferType) { + // Infer types only parse as identifiers, so the target should always be a TypeParameter that becomes a TypeReferenceNode + const ref = typeToTypeNodeHelper((type).target, context) as TypeReferenceNode; + return createInferTypeNode(createTypeParameterDeclaration(ref.typeName as Identifier)); + } Debug.fail("Should be unreachable."); @@ -3517,7 +3522,7 @@ namespace ts { const params = getTypeParametersOfClassOrInterface( parentSymbol.flags & SymbolFlags.Alias ? resolveAlias(parentSymbol) : parentSymbol ); - typeParameterNodes = mapToTypeNodes(map(params, (nextSymbol as TransientSymbol).mapper), context); + typeParameterNodes = mapToTypeNodes(mapIndexless(params, (nextSymbol as TransientSymbol).mapper), context); } else { typeParameterNodes = typeParametersToTypeParameterDeclarations(symbol, context); @@ -4736,12 +4741,14 @@ namespace ts { case SyntaxKind.JSDocTemplateTag: case SyntaxKind.MappedType: case SyntaxKind.ConditionalType: + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes); if (node.kind === SyntaxKind.MappedType) { return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode((node).typeParameter))); } - else if (node.kind === SyntaxKind.ConditionalType) { - return concatenate(outerTypeParameters, getInferTypeParameters(node)); + else if (node.kind === SyntaxKind.ConditionalType || node.kind === SyntaxKind.NewExpression || node.kind === SyntaxKind.CallExpression) { + return concatenate(outerTypeParameters, getInferTypeParameters(node)); } const outerAndOwnTypeParameters = appendTypeParameters(outerTypeParameters, getEffectiveTypeParameterDeclarations(node) || emptyArray); const thisType = includeThisTypes && @@ -8334,7 +8341,7 @@ namespace ts { return type.resolvedFalseType || (type.resolvedFalseType = instantiateType(type.root.falseType, type.mapper)); } - function getInferTypeParameters(node: ConditionalTypeNode): TypeParameter[] { + function getInferTypeParameters(node: ConditionalTypeNode | CallLikeExpression): TypeParameter[] { let result: TypeParameter[]; if (node.locals) { node.locals.forEach(symbol => { @@ -8375,10 +8382,16 @@ namespace ts { return links.resolvedType; } + function createInferType(target: TypeParameter): InferType { + const type = createType(TypeFlags.InferType) as InferType; + type.target = target; + return type; + } + function getTypeFromInferTypeNode(node: InferTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - links.resolvedType = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node.typeParameter)); + links.resolvedType = createInferType(getDeclaredTypeOfTypeParameter(getSymbolOfNode(node.typeParameter))); } return links.resolvedType; } @@ -8882,7 +8895,7 @@ namespace ts { // mapper to the type parameters to produce the effective list of type arguments, and compute the // instantiation cache key from the type IDs of the type arguments. const combinedMapper = type.objectFlags & ObjectFlags.Instantiated ? combineTypeMappers(type.mapper, mapper) : mapper; - const typeArguments = map(typeParameters, combinedMapper); + const typeArguments = mapIndexless(typeParameters, combinedMapper); const id = getTypeListId(typeArguments); let result = links.instantiations.get(id); if (!result) { @@ -8965,7 +8978,7 @@ namespace ts { // We are instantiating a conditional type that has one or more type parameters in scope. Apply the // mapper to the type parameters to produce the effective list of type arguments, and compute the // instantiation cache key from the type IDs of the type arguments. - const typeArguments = map(root.outerTypeParameters, mapper); + const typeArguments = mapIndexless(root.outerTypeParameters, mapper); const id = getTypeListId(typeArguments); let result = root.instantiations.get(id); if (!result) { @@ -9036,6 +9049,15 @@ namespace ts { if (type.flags & TypeFlags.Substitution) { return mapper((type).typeParameter); } + if (type.flags & TypeFlags.InferType) { + // Fresh infer types are not *actually* type parameters, but look like one; this gives mappers the opportunity + // to handle one directly (as is done for partial inference), before it gets mapped to its target. + const result = mapper(type); + if (result !== type) { + return result; + } + return instantiateType((type).target, mapper); + } } return type; } @@ -9642,9 +9664,15 @@ namespace ts { if (source.flags & TypeFlags.Substitution) { source = relation === definitelyAssignableRelation ? (source).typeParameter : (source).substitute; } + if (source.flags & TypeFlags.InferType) { + source = (source).target; + } if (target.flags & TypeFlags.Substitution) { target = (target).typeParameter; } + if (target.flags & TypeFlags.InferType) { + target = (target).target; + } // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases if (source === target) return Ternary.True; @@ -11587,6 +11615,12 @@ namespace ts { if (!couldContainTypeVariables(target)) { return; } + if (source.flags & TypeFlags.InferType) { + source = (source as InferType).target; + } + if (target.flags & TypeFlags.InferType) { + target = (target as InferType).target; + } if (source.flags & TypeFlags.Any) { // We are inferring from an 'any' type. We want to infer this type for every type parameter // referenced in the target type, so we record it as the propagation type and infer from the @@ -17529,10 +17563,35 @@ namespace ts { candidate = originalCandidate; if (candidate.typeParameters) { let typeArgumentTypes: Type[]; + const isJavascript = isInJavaScriptFile(candidate.declaration); if (typeArguments) { const typeArgumentResult = checkTypeArguments(candidate, typeArguments, /*reportErrors*/ false); if (typeArgumentResult) { - typeArgumentTypes = typeArgumentResult; + if (node.locals) { + // Call has `infer` arguments that still need to be inferred and instantiated + const inferParams = getInferTypeParameters(node); + // Mapper replaces references to infered type parameters with emptyObjectType + // Causing the original location to be the _only_ inference site + const preprocessMapper = (p: TypeParameter) => { + // Fresh infer types are not *actually* type parameters, but look like one + if (p.flags & TypeFlags.InferType) { + return p.target; // By doing the replacement here, we cause this mapper to be not-called with the target + } + if (contains(inferParams, p)) { + return emptyObjectType; + } + return p; + }; + const resultsWithNonInferInferredVarsDefaulted = map(typeArgumentResult, t => instantiateType(t, preprocessMapper)); + const partialCandidate = getSignatureInstantiation(candidate, resultsWithNonInferInferredVarsDefaulted, isJavascript); + const context = createInferenceContext(inferParams, partialCandidate, InferenceFlags.None); + const inferences = inferTypeArguments(node, partialCandidate, args, excludeArgument, context); + const mapper = createTypeMapper(inferParams, inferences); + typeArgumentTypes = map(typeArgumentResult, t => instantiateType(t, mapper)); + } + else { + typeArgumentTypes = typeArgumentResult; + } } else { candidateForTypeArgumentError = originalCandidate; @@ -17542,7 +17601,6 @@ namespace ts { else { typeArgumentTypes = inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext); } - const isJavascript = isInJavaScriptFile(candidate.declaration); candidate = getSignatureInstantiation(candidate, typeArgumentTypes, isJavascript); } if (!checkApplicableSignature(node, args, candidate, relation, excludeArgument, /*reportErrors*/ false)) { @@ -20544,9 +20602,18 @@ namespace ts { forEachChild(node, checkSourceElement); } + function isConditionalTypeExtendsClause(n: Node) { + return n.parent && n.parent.kind === SyntaxKind.ConditionalType && (n.parent).extendsType === n; + } + + function isCallOrNewExpressionTypeArgument(n: Node) { + return n.parent && (n.parent.kind === SyntaxKind.CallExpression || n.parent.kind === SyntaxKind.NewExpression) + && contains((n.parent).typeArguments, n); + } + function checkInferType(node: InferTypeNode) { - if (!findAncestor(node, n => n.parent && n.parent.kind === SyntaxKind.ConditionalType && (n.parent).extendsType === n)) { - grammarErrorOnNode(node, Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type); + if (!findAncestor(node, n => isConditionalTypeExtendsClause(n) || isCallOrNewExpressionTypeArgument(n))) { + grammarErrorOnNode(node, Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type_or_in_call_or_new_expression_type_argument_lists); } checkSourceElement(node.typeParameter); } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index d44cbf4a72de4..bdca9d3d80e32 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -414,6 +414,17 @@ namespace ts { array.length = 0; } + export function mapIndexless(array: ReadonlyArray, f: (x: T) => U): U[] { + let result: U[]; + if (array) { + result = []; + for (const elem of array) { + result.push(f(elem)); + } + } + return result; + } + export function map(array: ReadonlyArray, f: (x: T, i: number) => U): U[] { let result: U[]; if (array) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index d8545e015290d..5dd7522501d4d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -947,7 +947,7 @@ "category": "Error", "code": 1337 }, - "'infer' declarations are only permitted in the 'extends' clause of a conditional type.": { + "'infer' declarations are only permitted in the 'extends' clause of a conditional type or in call or new expression type argument lists.": { "category": "Error", "code": 1338 }, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7d6e58ad9a4a4..fa49875a5d33a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3538,6 +3538,7 @@ namespace ts { /* @internal */ ContainsAnyFunctionType = 1 << 26, // Type is or contains the anyFunctionType NonPrimitive = 1 << 27, // intrinsic object type + InferType = 1 << 28, // A type whose concrete value upon instantiation will be inferred at a given site /* @internal */ GenericMappedType = 1 << 29, // Flag used by maybeTypeOfKind @@ -3562,7 +3563,7 @@ namespace ts { ESSymbolLike = ESSymbol | UniqueESSymbol, UnionOrIntersection = Union | Intersection, StructuredType = Object | Union | Intersection, - TypeVariable = TypeParameter | IndexedAccess, + TypeVariable = TypeParameter | IndexedAccess | InferType, InstantiableNonPrimitive = TypeVariable | Conditional | Substitution, InstantiablePrimitive = Index, Instantiable = InstantiableNonPrimitive | InstantiablePrimitive, @@ -3817,6 +3818,11 @@ namespace ts { resolvedDefaultType?: Type; } + // Infer Types (TypeFlags.InferType) + export interface InferType extends Type { + target: TypeParameter; + } + // Indexed access types (TypeFlags.IndexedAccess) // Possible forms are T[xxx], xxx[T], or xxx[keyof T], where T is a type variable export interface IndexedAccessType extends InstantiableType { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 6763e768cda98..c36ad647530c7 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2074,6 +2074,7 @@ declare namespace ts { Conditional = 2097152, Substitution = 4194304, NonPrimitive = 134217728, + InferType = 268435456, Literal = 224, Unit = 13536, StringOrNumberLiteral = 96, @@ -2085,12 +2086,12 @@ declare namespace ts { ESSymbolLike = 1536, UnionOrIntersection = 393216, StructuredType = 458752, - TypeVariable = 1081344, - InstantiableNonPrimitive = 7372800, + TypeVariable = 269516800, + InstantiableNonPrimitive = 275808256, InstantiablePrimitive = 524288, - Instantiable = 7897088, - StructuredOrInstantiable = 8355840, - Narrowable = 142575359, + Instantiable = 276332544, + StructuredOrInstantiable = 276791296, + Narrowable = 411010815, NotUnionOrUnit = 134283777, } type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; @@ -2184,6 +2185,9 @@ declare namespace ts { } interface TypeParameter extends InstantiableType { } + interface InferType extends Type { + target: TypeParameter; + } interface IndexedAccessType extends InstantiableType { objectType: Type; indexType: Type; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 2f467c9ffb07f..36200cc579402 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2074,6 +2074,7 @@ declare namespace ts { Conditional = 2097152, Substitution = 4194304, NonPrimitive = 134217728, + InferType = 268435456, Literal = 224, Unit = 13536, StringOrNumberLiteral = 96, @@ -2085,12 +2086,12 @@ declare namespace ts { ESSymbolLike = 1536, UnionOrIntersection = 393216, StructuredType = 458752, - TypeVariable = 1081344, - InstantiableNonPrimitive = 7372800, + TypeVariable = 269516800, + InstantiableNonPrimitive = 275808256, InstantiablePrimitive = 524288, - Instantiable = 7897088, - StructuredOrInstantiable = 8355840, - Narrowable = 142575359, + Instantiable = 276332544, + StructuredOrInstantiable = 276791296, + Narrowable = 411010815, NotUnionOrUnit = 134283777, } type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; @@ -2184,6 +2185,9 @@ declare namespace ts { } interface TypeParameter extends InstantiableType { } + interface InferType extends Type { + target: TypeParameter; + } interface IndexedAccessType extends InstantiableType { objectType: Type; indexType: Type; diff --git a/tests/baselines/reference/inferTypeArgumentKeyword.errors.txt b/tests/baselines/reference/inferTypeArgumentKeyword.errors.txt new file mode 100644 index 0000000000000..52707919db7c3 --- /dev/null +++ b/tests/baselines/reference/inferTypeArgumentKeyword.errors.txt @@ -0,0 +1,50 @@ +tests/cases/conformance/types/typeParameters/typeArgumentLists/inferTypeArgumentKeyword.ts(7,59): error TS2345: Argument of type '{ z: number; }' is not assignable to parameter of type '{ z: { y: number; }; }'. + Types of property 'z' are incompatible. + Type 'number' is not assignable to type '{ y: number; }'. +tests/cases/conformance/types/typeParameters/typeArgumentLists/inferTypeArgumentKeyword.ts(10,38): error TS2345: Argument of type '{ y: number; }' is not assignable to parameter of type 'number'. +tests/cases/conformance/types/typeParameters/typeArgumentLists/inferTypeArgumentKeyword.ts(17,63): error TS2345: Argument of type '{ z: string; }' is not assignable to parameter of type '{ z: number; }'. + Types of property 'z' are incompatible. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/types/typeParameters/typeArgumentLists/inferTypeArgumentKeyword.ts(23,47): error TS2345: Argument of type '{ y: string; }' is not assignable to parameter of type '{ y: number; }'. + Types of property 'y' are incompatible. + Type 'string' is not assignable to type 'number'. + + +==== tests/cases/conformance/types/typeParameters/typeArgumentLists/inferTypeArgumentKeyword.ts (4 errors) ==== + declare function foo(x: A, y: B, z: { z: C }): A & B & C; + + // good + var a = foo({y: 12}, {x: "yes"}, {z: {y: 12}}); + + // error on 3rd arg + var b = foo({y: 12}, {x: "yes"}, {z: 12}); + ~~~~~~~ +!!! error TS2345: Argument of type '{ z: number; }' is not assignable to parameter of type '{ z: { y: number; }; }'. +!!! error TS2345: Types of property 'z' are incompatible. +!!! error TS2345: Type 'number' is not assignable to type '{ y: number; }'. + + // error on first arg + var c = foo({y: 12}, {x: "yes"}, {z: 12}); + ~~~~~~~ +!!! error TS2345: Argument of type '{ y: number; }' is not assignable to parameter of type 'number'. + + type Ob = {y: T}; + // good + var d = foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: 12}); + + // error on 3rd arg + var e = foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: "no"}); + ~~~~~~~~~ +!!! error TS2345: Argument of type '{ z: string; }' is not assignable to parameter of type '{ z: number; }'. +!!! error TS2345: Types of property 'z' are incompatible. +!!! error TS2345: Type 'string' is not assignable to type 'number'. + + // good + var e = foo<{y: A}, {x: string}, Ob>({y: 12}, {x: "yes"}, {z: { y: 12 }}); + + // error on 1st arg + var f = foo<{y: A}, {x: string}, Ob>({y: "no"}, {x: "yes"}, {z: { y: 12 }}); + ~~~~~~~~~ +!!! error TS2345: Argument of type '{ y: string; }' is not assignable to parameter of type '{ y: number; }'. +!!! error TS2345: Types of property 'y' are incompatible. +!!! error TS2345: Type 'string' is not assignable to type 'number'. \ No newline at end of file diff --git a/tests/baselines/reference/inferTypeArgumentKeyword.js b/tests/baselines/reference/inferTypeArgumentKeyword.js new file mode 100644 index 0000000000000..d03e929371a92 --- /dev/null +++ b/tests/baselines/reference/inferTypeArgumentKeyword.js @@ -0,0 +1,40 @@ +//// [inferTypeArgumentKeyword.ts] +declare function foo(x: A, y: B, z: { z: C }): A & B & C; + +// good +var a = foo({y: 12}, {x: "yes"}, {z: {y: 12}}); + +// error on 3rd arg +var b = foo({y: 12}, {x: "yes"}, {z: 12}); + +// error on first arg +var c = foo({y: 12}, {x: "yes"}, {z: 12}); + +type Ob = {y: T}; +// good +var d = foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: 12}); + +// error on 3rd arg +var e = foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: "no"}); + +// good +var e = foo<{y: A}, {x: string}, Ob>({y: 12}, {x: "yes"}, {z: { y: 12 }}); + +// error on 1st arg +var f = foo<{y: A}, {x: string}, Ob>({y: "no"}, {x: "yes"}, {z: { y: 12 }}); + +//// [inferTypeArgumentKeyword.js] +// good +var a = foo({ y: 12 }, { x: "yes" }, { z: { y: 12 } }); +// error on 3rd arg +var b = foo({ y: 12 }, { x: "yes" }, { z: 12 }); +// error on first arg +var c = foo({ y: 12 }, { x: "yes" }, { z: 12 }); +// good +var d = foo({ y: 12 }, { x: "yes" }, { z: 12 }); +// error on 3rd arg +var e = foo({ y: 12 }, { x: "yes" }, { z: "no" }); +// good +var e = foo({ y: 12 }, { x: "yes" }, { z: { y: 12 } }); +// error on 1st arg +var f = foo({ y: "no" }, { x: "yes" }, { z: { y: 12 } }); diff --git a/tests/baselines/reference/inferTypeArgumentKeyword.symbols b/tests/baselines/reference/inferTypeArgumentKeyword.symbols new file mode 100644 index 0000000000000..3ff0d201bd0f9 --- /dev/null +++ b/tests/baselines/reference/inferTypeArgumentKeyword.symbols @@ -0,0 +1,109 @@ +=== tests/cases/conformance/types/typeParameters/typeArgumentLists/inferTypeArgumentKeyword.ts === +declare function foo(x: A, y: B, z: { z: C }): A & B & C; +>foo : Symbol(foo, Decl(inferTypeArgumentKeyword.ts, 0, 0)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 0, 21)) +>B : Symbol(B, Decl(inferTypeArgumentKeyword.ts, 0, 23)) +>C : Symbol(C, Decl(inferTypeArgumentKeyword.ts, 0, 26)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 0, 30)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 0, 21)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 0, 35)) +>B : Symbol(B, Decl(inferTypeArgumentKeyword.ts, 0, 23)) +>z : Symbol(z, Decl(inferTypeArgumentKeyword.ts, 0, 41)) +>z : Symbol(z, Decl(inferTypeArgumentKeyword.ts, 0, 46)) +>C : Symbol(C, Decl(inferTypeArgumentKeyword.ts, 0, 26)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 0, 21)) +>B : Symbol(B, Decl(inferTypeArgumentKeyword.ts, 0, 23)) +>C : Symbol(C, Decl(inferTypeArgumentKeyword.ts, 0, 26)) + +// good +var a = foo({y: 12}, {x: "yes"}, {z: {y: 12}}); +>a : Symbol(a, Decl(inferTypeArgumentKeyword.ts, 3, 3)) +>foo : Symbol(foo, Decl(inferTypeArgumentKeyword.ts, 0, 0)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 3, 17)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 3, 22)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 3, 17)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 3, 38)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 3, 47)) +>z : Symbol(z, Decl(inferTypeArgumentKeyword.ts, 3, 59)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 3, 63)) + +// error on 3rd arg +var b = foo({y: 12}, {x: "yes"}, {z: 12}); +>b : Symbol(b, Decl(inferTypeArgumentKeyword.ts, 6, 3)) +>foo : Symbol(foo, Decl(inferTypeArgumentKeyword.ts, 0, 0)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 6, 17)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 6, 22)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 6, 17)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 6, 38)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 6, 47)) +>z : Symbol(z, Decl(inferTypeArgumentKeyword.ts, 6, 59)) + +// error on first arg +var c = foo({y: 12}, {x: "yes"}, {z: 12}); +>c : Symbol(c, Decl(inferTypeArgumentKeyword.ts, 9, 3)) +>foo : Symbol(foo, Decl(inferTypeArgumentKeyword.ts, 0, 0)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 9, 33)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 9, 16)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 9, 33)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 9, 38)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 9, 47)) +>z : Symbol(z, Decl(inferTypeArgumentKeyword.ts, 9, 59)) + +type Ob = {y: T}; +>Ob : Symbol(Ob, Decl(inferTypeArgumentKeyword.ts, 9, 67)) +>T : Symbol(T, Decl(inferTypeArgumentKeyword.ts, 11, 8)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 11, 14)) +>T : Symbol(T, Decl(inferTypeArgumentKeyword.ts, 11, 8)) + +// good +var d = foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: 12}); +>d : Symbol(d, Decl(inferTypeArgumentKeyword.ts, 13, 3)) +>foo : Symbol(foo, Decl(inferTypeArgumentKeyword.ts, 0, 0)) +>Ob : Symbol(Ob, Decl(inferTypeArgumentKeyword.ts, 9, 67)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 13, 20)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 13, 26)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 13, 20)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 13, 42)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 13, 51)) +>z : Symbol(z, Decl(inferTypeArgumentKeyword.ts, 13, 63)) + +// error on 3rd arg +var e = foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: "no"}); +>e : Symbol(e, Decl(inferTypeArgumentKeyword.ts, 16, 3), Decl(inferTypeArgumentKeyword.ts, 19, 3)) +>foo : Symbol(foo, Decl(inferTypeArgumentKeyword.ts, 0, 0)) +>Ob : Symbol(Ob, Decl(inferTypeArgumentKeyword.ts, 9, 67)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 16, 20)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 16, 26)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 16, 20)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 16, 42)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 16, 51)) +>z : Symbol(z, Decl(inferTypeArgumentKeyword.ts, 16, 63)) + +// good +var e = foo<{y: A}, {x: string}, Ob>({y: 12}, {x: "yes"}, {z: { y: 12 }}); +>e : Symbol(e, Decl(inferTypeArgumentKeyword.ts, 16, 3), Decl(inferTypeArgumentKeyword.ts, 19, 3)) +>foo : Symbol(foo, Decl(inferTypeArgumentKeyword.ts, 0, 0)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 19, 13)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 19, 41)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 19, 21)) +>Ob : Symbol(Ob, Decl(inferTypeArgumentKeyword.ts, 9, 67)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 19, 41)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 19, 47)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 19, 56)) +>z : Symbol(z, Decl(inferTypeArgumentKeyword.ts, 19, 68)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 19, 72)) + +// error on 1st arg +var f = foo<{y: A}, {x: string}, Ob>({y: "no"}, {x: "yes"}, {z: { y: 12 }}); +>f : Symbol(f, Decl(inferTypeArgumentKeyword.ts, 22, 3)) +>foo : Symbol(foo, Decl(inferTypeArgumentKeyword.ts, 0, 0)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 22, 13)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 22, 41)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 22, 21)) +>Ob : Symbol(Ob, Decl(inferTypeArgumentKeyword.ts, 9, 67)) +>A : Symbol(A, Decl(inferTypeArgumentKeyword.ts, 22, 41)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 22, 47)) +>x : Symbol(x, Decl(inferTypeArgumentKeyword.ts, 22, 58)) +>z : Symbol(z, Decl(inferTypeArgumentKeyword.ts, 22, 70)) +>y : Symbol(y, Decl(inferTypeArgumentKeyword.ts, 22, 74)) + diff --git a/tests/baselines/reference/inferTypeArgumentKeyword.types b/tests/baselines/reference/inferTypeArgumentKeyword.types new file mode 100644 index 0000000000000..577afb2b7e1cf --- /dev/null +++ b/tests/baselines/reference/inferTypeArgumentKeyword.types @@ -0,0 +1,161 @@ +=== tests/cases/conformance/types/typeParameters/typeArgumentLists/inferTypeArgumentKeyword.ts === +declare function foo(x: A, y: B, z: { z: C }): A & B & C; +>foo : (x: A, y: B, z: { z: C; }) => A & B & C +>A : A +>B : B +>C : C +>x : A +>A : A +>y : B +>B : B +>z : { z: C; } +>z : C +>C : C +>A : A +>B : B +>C : C + +// good +var a = foo({y: 12}, {x: "yes"}, {z: {y: 12}}); +>a : { y: number; } & { x: string; } +>foo({y: 12}, {x: "yes"}, {z: {y: 12}}) : { y: number; } & { x: string; } +>foo : (x: A, y: B, z: { z: C; }) => A & B & C +>A : A +>x : string +>A : A +>{y: 12} : { y: number; } +>y : number +>12 : 12 +>{x: "yes"} : { x: string; } +>x : string +>"yes" : "yes" +>{z: {y: 12}} : { z: { y: number; }; } +>z : { y: number; } +>{y: 12} : { y: number; } +>y : number +>12 : 12 + +// error on 3rd arg +var b = foo({y: 12}, {x: "yes"}, {z: 12}); +>b : any +>foo({y: 12}, {x: "yes"}, {z: 12}) : any +>foo : (x: A, y: B, z: { z: C; }) => A & B & C +>A : A +>x : string +>A : A +>{y: 12} : { y: number; } +>y : number +>12 : 12 +>{x: "yes"} : { x: string; } +>x : string +>"yes" : "yes" +>{z: 12} : { z: number; } +>z : number +>12 : 12 + +// error on first arg +var c = foo({y: 12}, {x: "yes"}, {z: 12}); +>c : any +>foo({y: 12}, {x: "yes"}, {z: 12}) : any +>foo : (x: A, y: B, z: { z: C; }) => A & B & C +>A : A +>x : string +>A : A +>{y: 12} : { y: number; } +>y : number +>12 : 12 +>{x: "yes"} : { x: string; } +>x : string +>"yes" : "yes" +>{z: 12} : { z: number; } +>z : number +>12 : 12 + +type Ob = {y: T}; +>Ob : Ob +>T : T +>y : T +>T : T + +// good +var d = foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: 12}); +>d : Ob & { x: string; } & number +>foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: 12}) : Ob & { x: string; } & number +>foo : (x: A, y: B, z: { z: C; }) => A & B & C +>Ob : Ob +>A : A +>x : string +>A : A +>{y: 12} : { y: number; } +>y : number +>12 : 12 +>{x: "yes"} : { x: string; } +>x : string +>"yes" : "yes" +>{z: 12} : { z: number; } +>z : number +>12 : 12 + +// error on 3rd arg +var e = foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: "no"}); +>e : any +>foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: "no"}) : any +>foo : (x: A, y: B, z: { z: C; }) => A & B & C +>Ob : Ob +>A : A +>x : string +>A : A +>{y: 12} : { y: number; } +>y : number +>12 : 12 +>{x: "yes"} : { x: string; } +>x : string +>"yes" : "yes" +>{z: "no"} : { z: string; } +>z : string +>"no" : "no" + +// good +var e = foo<{y: A}, {x: string}, Ob>({y: 12}, {x: "yes"}, {z: { y: 12 }}); +>e : any +>foo<{y: A}, {x: string}, Ob>({y: 12}, {x: "yes"}, {z: { y: 12 }}) : { y: number; } & { x: string; } & Ob +>foo : (x: A, y: B, z: { z: C; }) => A & B & C +>y : A +>A : A +>x : string +>Ob : Ob +>A : A +>{y: 12} : { y: number; } +>y : number +>12 : 12 +>{x: "yes"} : { x: string; } +>x : string +>"yes" : "yes" +>{z: { y: 12 }} : { z: { y: number; }; } +>z : { y: number; } +>{ y: 12 } : { y: number; } +>y : number +>12 : 12 + +// error on 1st arg +var f = foo<{y: A}, {x: string}, Ob>({y: "no"}, {x: "yes"}, {z: { y: 12 }}); +>f : any +>foo<{y: A}, {x: string}, Ob>({y: "no"}, {x: "yes"}, {z: { y: 12 }}) : any +>foo : (x: A, y: B, z: { z: C; }) => A & B & C +>y : A +>A : A +>x : string +>Ob : Ob +>A : A +>{y: "no"} : { y: string; } +>y : string +>"no" : "no" +>{x: "yes"} : { x: string; } +>x : string +>"yes" : "yes" +>{z: { y: 12 }} : { z: { y: number; }; } +>z : { y: number; } +>{ y: 12 } : { y: number; } +>y : number +>12 : 12 + diff --git a/tests/baselines/reference/inferTypes1.errors.txt b/tests/baselines/reference/inferTypes1.errors.txt index 3b627a0557f25..04a70349948ca 100644 --- a/tests/baselines/reference/inferTypes1.errors.txt +++ b/tests/baselines/reference/inferTypes1.errors.txt @@ -7,10 +7,10 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(38,25): error TS2344: T tests/cases/conformance/types/conditional/inferTypes1.ts(46,25): error TS2344: Type '(x: string, y: string) => number' does not satisfy the constraint '(x: any) => any'. tests/cases/conformance/types/conditional/inferTypes1.ts(47,25): error TS2344: Type 'Function' does not satisfy the constraint '(x: any) => any'. Type 'Function' provides no match for the signature '(x: any): any'. -tests/cases/conformance/types/conditional/inferTypes1.ts(73,12): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. -tests/cases/conformance/types/conditional/inferTypes1.ts(74,15): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. -tests/cases/conformance/types/conditional/inferTypes1.ts(74,41): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. -tests/cases/conformance/types/conditional/inferTypes1.ts(74,51): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. +tests/cases/conformance/types/conditional/inferTypes1.ts(73,12): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type or in call or new expression type argument lists. +tests/cases/conformance/types/conditional/inferTypes1.ts(74,15): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type or in call or new expression type argument lists. +tests/cases/conformance/types/conditional/inferTypes1.ts(74,41): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type or in call or new expression type argument lists. +tests/cases/conformance/types/conditional/inferTypes1.ts(74,51): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type or in call or new expression type argument lists. tests/cases/conformance/types/conditional/inferTypes1.ts(75,15): error TS2304: Cannot find name 'U'. tests/cases/conformance/types/conditional/inferTypes1.ts(75,15): error TS4081: Exported type alias 'T62' has or is using private name 'U'. tests/cases/conformance/types/conditional/inferTypes1.ts(75,43): error TS2304: Cannot find name 'U'. @@ -110,14 +110,14 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(143,40): error TS2322: type T60 = infer U; // Error ~~~~~~~ -!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. +!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type or in call or new expression type argument lists. type T61 = infer A extends infer B ? infer C : infer D; // Error ~~~~~~~ -!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. +!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type or in call or new expression type argument lists. ~~~~~~~ -!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. +!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type or in call or new expression type argument lists. ~~~~~~~ -!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. +!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type or in call or new expression type argument lists. type T62 = U extends (infer U)[] ? U : U; // Error ~ !!! error TS2304: Cannot find name 'U'. diff --git a/tests/baselines/reference/inferTypes1.types b/tests/baselines/reference/inferTypes1.types index 1d0a48c5169a3..f91d6aa83d018 100644 --- a/tests/baselines/reference/inferTypes1.types +++ b/tests/baselines/reference/inferTypes1.types @@ -150,7 +150,7 @@ type ArgumentType any> = T extends (a: infer A) => any ? A >T : T >x : any >T : T ->a : A +>a : infer A >A : A >A : A @@ -198,9 +198,9 @@ type X1 = T extends { x: infer X, y: infer Y } ? [ >x : any >y : any >T : T ->x : X +>x : infer X >X : X ->y : Y +>y : infer Y >Y : Y >X : X >Y : Y @@ -228,9 +228,9 @@ type X2 = T extends { a: infer U, b: infer U } ? U : never; >X2 : X2 >T : T >T : T ->a : U +>a : infer U >U : U ->b : U +>b : infer U >U : U >U : U @@ -266,11 +266,11 @@ type X3 = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U >X3 : X3 >T : T >T : T ->a : (x: U) => void ->x : U +>a : (x: infer U) => void +>x : infer U >U : U ->b : (x: U) => void ->x : U +>b : (x: infer U) => void +>x : infer U >U : U >U : U @@ -308,11 +308,11 @@ type T54 = X3<{ a: (x: number) => void, b: () => void }>; // number >b : () => void type T60 = infer U; // Error ->T60 : U +>T60 : infer U >U : U type T61 = infer A extends infer B ? infer C : infer D; // Error ->T61 : T61 +>T61 : {} >T : T >A : A >B : B @@ -478,7 +478,7 @@ type Jsonified = : T extends { toJSON(): infer R } ? R // toJSON is called if it exists (e.g. Date) >T : T ->toJSON : () => R +>toJSON : () => infer R >R : R >R : R diff --git a/tests/cases/conformance/types/typeParameters/typeArgumentLists/inferTypeArgumentKeyword.ts b/tests/cases/conformance/types/typeParameters/typeArgumentLists/inferTypeArgumentKeyword.ts new file mode 100644 index 0000000000000..46724e5a3d516 --- /dev/null +++ b/tests/cases/conformance/types/typeParameters/typeArgumentLists/inferTypeArgumentKeyword.ts @@ -0,0 +1,23 @@ +declare function foo(x: A, y: B, z: { z: C }): A & B & C; + +// good +var a = foo({y: 12}, {x: "yes"}, {z: {y: 12}}); + +// error on 3rd arg +var b = foo({y: 12}, {x: "yes"}, {z: 12}); + +// error on first arg +var c = foo({y: 12}, {x: "yes"}, {z: 12}); + +type Ob = {y: T}; +// good +var d = foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: 12}); + +// error on 3rd arg +var e = foo, {x: string}, A>({y: 12}, {x: "yes"}, {z: "no"}); + +// good +var e = foo<{y: A}, {x: string}, Ob>({y: 12}, {x: "yes"}, {z: { y: 12 }}); + +// error on 1st arg +var f = foo<{y: A}, {x: string}, Ob>({y: "no"}, {x: "yes"}, {z: { y: 12 }}); \ No newline at end of file