diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a21ea466825e1..abc65c55334ec 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28807,7 +28807,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const iife = getImmediatelyInvokedFunctionExpression(func); if (iife && iife.arguments) { - const args = getEffectiveCallArguments(iife); + const [args,] = getEffectiveCallArguments(iife); const indexOfParameter = func.parameters.indexOf(parameter); if (parameter.dotDotDotToken) { return getSpreadArgumentType(args, indexOfParameter, args.length, anyType, /*context*/ undefined, CheckMode.Normal); @@ -29002,7 +29002,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In a typed function call, an argument or substitution expression is contextually typed by the type of the corresponding parameter. function getContextualTypeForArgument(callTarget: CallLikeExpression, arg: Expression): Type | undefined { - const args = getEffectiveCallArguments(callTarget); + const [args,] = getEffectiveCallArguments(callTarget); const argIndex = args.indexOf(arg); // -1 for e.g. the expression of a CallExpression, or the tag of a TaggedTemplateExpression return argIndex === -1 ? undefined : getContextualTypeForArgumentAtIndex(callTarget, argIndex); } @@ -32335,14 +32335,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!(t.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Unknown | TypeFlags.Any)); } - function hasCorrectArity(node: CallLikeExpression, args: readonly Expression[], signature: Signature, signatureHelpTrailingComma = false) { - let argCount: number; + function hasCorrectArity(node: CallLikeExpression, args: readonly Expression[], shortestTupleArgs: number, signature: Signature, signatureHelpTrailingComma = false) { + let maxArgCount: number; + let minArgCount = shortestTupleArgs; let callIsIncomplete = false; // In incomplete call we want to be lenient when we have too few arguments - let effectiveParameterCount = getParameterCount(signature); - let effectiveMinimumArguments = getMinArgumentCount(signature); + let effectiveMaxParameters = getParameterCount(signature); + let effectiveMinParameters = getMinArgumentCount(signature); if (node.kind === SyntaxKind.TaggedTemplateExpression) { - argCount = args.length; + maxArgCount = args.length; if (node.template.kind === SyntaxKind.TemplateExpression) { // If a tagged template expression lacks a tail literal, the call is incomplete. // Specifically, a template only can end in a TemplateTail or a Missing literal. @@ -32359,16 +32360,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else if (node.kind === SyntaxKind.Decorator) { - argCount = getDecoratorArgumentCount(node, signature); + minArgCount = maxArgCount = getDecoratorArgumentCount(node, signature); } else if (isJsxOpeningLikeElement(node)) { callIsIncomplete = node.attributes.end === node.end; if (callIsIncomplete) { return true; } - argCount = effectiveMinimumArguments === 0 ? args.length : 1; - effectiveParameterCount = args.length === 0 ? effectiveParameterCount : 1; // class may have argumentless ctor functions - still resolve ctor and compare vs props member type - effectiveMinimumArguments = Math.min(effectiveMinimumArguments, 1); // sfc may specify context argument - handled by framework and not typechecked + minArgCount = maxArgCount = effectiveMinParameters === 0 ? args.length : 1; + effectiveMaxParameters = args.length === 0 ? effectiveMaxParameters : 1; // class may have argumentless ctor functions - still resolve ctor and compare vs props member type + effectiveMinParameters = Math.min(effectiveMinParameters, 1); // sfc may specify context argument - handled by framework and not typechecked } else if (!node.arguments) { // This only happens when we have something of the form: 'new C' @@ -32376,7 +32377,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getMinArgumentCount(signature) === 0; } else { - argCount = signatureHelpTrailingComma ? args.length + 1 : args.length; + maxArgCount = signatureHelpTrailingComma ? args.length + 1 : args.length; // If we are missing the close parenthesis, the call is incomplete. callIsIncomplete = node.arguments.end === node.end; @@ -32389,16 +32390,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Too many arguments implies incorrect arity. - if (!hasEffectiveRestParameter(signature) && argCount > effectiveParameterCount) { + if (!hasEffectiveRestParameter(signature) && maxArgCount > effectiveMaxParameters) { return false; } // If the call is incomplete, we should skip the lower bound check. // JSX signatures can have extra parameters provided by the library which we don't check - if (callIsIncomplete || argCount >= effectiveMinimumArguments) { + if (callIsIncomplete || minArgCount >= effectiveMinParameters) { return true; } - for (let i = argCount; i < effectiveMinimumArguments; i++) { + for (let i = maxArgCount; i < effectiveMinParameters; i++) { const type = getTypeAtPosition(signature, i); if (filterType(type, isInJSFile(node) && !strictNullChecks ? acceptsVoidUndefinedUnknownOrAny : acceptsVoid).flags & TypeFlags.Never) { return false; @@ -32883,7 +32884,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Returns the effective arguments for an expression that works like a function invocation. */ - function getEffectiveCallArguments(node: CallLikeExpression): readonly Expression[] { + function getEffectiveCallArguments(node: CallLikeExpression, signatures?: readonly Signature[]): [args: readonly Expression[], shortest: number] { if (node.kind === SyntaxKind.TaggedTemplateExpression) { const template = node.template; const args: Expression[] = [createSyntheticExpression(template, getGlobalTemplateStringsArrayType())]; @@ -32892,38 +32893,79 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { args.push(span.expression); }); } - return args; + return [args, args.length]; } if (node.kind === SyntaxKind.Decorator) { - return getEffectiveDecoratorArguments(node); + const args = getEffectiveDecoratorArguments(node); + return [args, args.length]; } if (isJsxOpeningLikeElement(node)) { - return node.attributes.properties.length > 0 || (isJsxOpeningElement(node) && node.parent.children.length > 0) ? [node.attributes] : emptyArray; + return node.attributes.properties.length > 0 || (isJsxOpeningElement(node) && node.parent.children.length > 0) ? [[node.attributes], 1] : [emptyArray, 0]; } const args = node.arguments || emptyArray; const spreadIndex = getSpreadArgumentIndex(args); if (spreadIndex >= 0) { + // TODO: Better variable names + let shortest = 0; // Create synthetic arguments from spreads of tuple types. const effectiveArgs = args.slice(0, spreadIndex); for (let i = spreadIndex; i < args.length; i++) { const arg = args[i]; // We can call checkExpressionCached because spread expressions never have a contextual type. - const spreadType = arg.kind === SyntaxKind.SpreadElement && (flowLoopCount ? checkExpression((arg as SpreadElement).expression) : checkExpressionCached((arg as SpreadElement).expression)); - if (spreadType && isTupleType(spreadType)) { - forEach(getElementTypes(spreadType), (t, i) => { - const flags = spreadType.target.elementFlags[i]; - const syntheticArg = createSyntheticExpression(arg, flags & ElementFlags.Rest ? createArrayType(t) : t, - !!(flags & ElementFlags.Variable), spreadType.target.labeledElementDeclarations?.[i]); - effectiveArgs.push(syntheticArg); - }); + const spreadType = arg.kind === SyntaxKind.SpreadElement + && (flowLoopCount ? checkExpression((arg as SpreadElement).expression) : checkExpressionCached((arg as SpreadElement).expression)); + if (spreadType && everyType(spreadType, isTupleType)) { + if (spreadType.flags & TypeFlags.Union) { + if (i !== args.length - 1 + || !signatures + || signatures.some(s => signatureHasRestParameter(s) && i === s.parameters.length - 1)) { + effectiveArgs.push(arg); + shortest++; + } + else { + let tmp = []; + const types = (spreadType as UnionType).types; + const typess = (types as TupleTypeReference[]).map(getElementTypes); + const short = Math.min(...typess.map(ts => ts.length)); + shortest += short; + const length = Math.min(...typess.map(ts => ts.length)); + for (let j = 0; j < length; j++) { + // TODO: need to handle non-Fixed by filling in with the trailing rest type instead of undefinedType + const t = getUnionType(typess.map(ts => ts[j] || undefinedType)); + const flags: ElementFlags = types + .map(t => (t as TupleTypeReference).target.elementFlags[j] || ElementFlags.Optional) + .reduce((total: number,f) => f | total, 0); + // TODO: bail if flags aren't ElementFlags.Fixed (it might be OK to allow a rest at the end, but still need tests for it) + if (flags & ~ElementFlags.Fixed) { + tmp = [arg]; + break; + + } + // TODO: Not sure at all what to do with labels, but there might be some utilities for this already + const syntheticArg = createSyntheticExpression(arg, t); + tmp.push(syntheticArg); + } + effectiveArgs.push(...tmp); + } + } + else { + forEach(getElementTypes(spreadType as TupleTypeReference), (t, i) => { + const flags = (spreadType as TupleTypeReference).target.elementFlags[i]; + const syntheticArg = createSyntheticExpression(arg, flags & ElementFlags.Rest ? createArrayType(t) : t, + !!(flags & ElementFlags.Variable), (spreadType as TupleTypeReference).target.labeledElementDeclarations?.[i]); + effectiveArgs.push(syntheticArg); + shortest++; + }); + } } else { effectiveArgs.push(arg); + shortest++; } } - return effectiveArgs; + return [effectiveArgs, shortest || effectiveArgs.length]; } - return args; + return [args, args.length]; } /** @@ -33024,8 +33066,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return constructorSymbol === globalPromiseSymbol; } - function getArgumentArityError(node: CallLikeExpression, signatures: readonly Signature[], args: readonly Expression[], headMessage?: DiagnosticMessage) { + function getArgumentArityError(node: CallLikeExpression, signatures: readonly Signature[], args: readonly Expression[], shortestTupleArgs: number, headMessage?: DiagnosticMessage) { const spreadIndex = getSpreadArgumentIndex(args); + const minArgLength = shortestTupleArgs; + const maxArgLength = args.length; if (spreadIndex > -1) { return createDiagnosticForNode(args[spreadIndex], Diagnostics.A_spread_argument_must_either_have_a_tuple_type_or_be_passed_to_a_rest_parameter); } @@ -33045,14 +33089,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } max = Math.max(max, maxParameter); // shortest parameter count *longer than the call*/longest parameter count *shorter than the call* - if (minParameter < args.length && minParameter > maxBelow) maxBelow = minParameter; - if (args.length < maxParameter && maxParameter < minAbove) minAbove = maxParameter; + if (minParameter < minArgLength && minParameter > maxBelow) maxBelow = minParameter; + if (maxArgLength < maxParameter && maxParameter < minAbove) minAbove = maxParameter; } const hasRestParameter = some(signatures, hasEffectiveRestParameter); const parameterRange = hasRestParameter ? min : min < max ? min + "-" + max : min; - const isVoidPromiseError = !hasRestParameter && parameterRange === 1 && args.length === 0 && isPromiseResolveArityError(node); + const isVoidPromiseError = !hasRestParameter && parameterRange === 1 && minArgLength === 0 && isPromiseResolveArityError(node); if (isVoidPromiseError && isInJSFile(node)) { return getDiagnosticForCallNode(node, Diagnostics.Expected_1_argument_but_got_0_new_Promise_needs_a_JSDoc_hint_to_produce_a_resolve_that_can_be_called_without_arguments); } @@ -33063,33 +33107,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { hasRestParameter ? Diagnostics.Expected_at_least_0_arguments_but_got_1 : isVoidPromiseError ? Diagnostics.Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise : Diagnostics.Expected_0_arguments_but_got_1; - - if (min < args.length && args.length < max) { + // TODO: (sigh) better error messages when minArgLength < maxArgLength, because it means that "expected 4, got 3" should be "expected 4, got *a minimum* of 3" + if (min < minArgLength && maxArgLength < max) { // between min and max, but with no matching overload if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, args.length, maxBelow, minAbove); + let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, maxArgLength, maxBelow, minAbove); chain = chainDiagnosticMessages(chain, headMessage); return getDiagnosticForCallNode(node, chain); } - return getDiagnosticForCallNode(node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, args.length, maxBelow, minAbove); + return getDiagnosticForCallNode(node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, maxArgLength, maxBelow, minAbove); } - else if (args.length < min) { + else if (maxArgLength < min) { // too short: put the error span on the call expression, not any of the args let diagnostic: Diagnostic; if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, error, parameterRange, args.length); + let chain = chainDiagnosticMessages(/*details*/ undefined, error, parameterRange, maxArgLength); chain = chainDiagnosticMessages(chain, headMessage); diagnostic = getDiagnosticForCallNode(node, chain); } else { - diagnostic = getDiagnosticForCallNode(node, error, parameterRange, args.length); + diagnostic = getDiagnosticForCallNode(node, error, parameterRange, maxArgLength); } - const parameter = closestSignature?.declaration?.parameters[closestSignature.thisParameter ? args.length + 1 : args.length]; + const parameter = closestSignature?.declaration?.parameters[closestSignature.thisParameter ? maxArgLength + 1 : maxArgLength]; if (parameter) { const messageAndArgs: DiagnosticAndArguments = isBindingPattern(parameter.name) ? [Diagnostics.An_argument_matching_this_binding_pattern_was_not_provided] : isRestParameter(parameter) ? [Diagnostics.Arguments_for_the_rest_parameter_0_were_not_provided, idText(getFirstIdentifier(parameter.name))] - : [Diagnostics.An_argument_for_0_was_not_provided, !parameter.name ? args.length : idText(getFirstIdentifier(parameter.name))]; + : [Diagnostics.An_argument_for_0_was_not_provided, !parameter.name ? maxArgLength : idText(getFirstIdentifier(parameter.name))]; const parameterError = createDiagnosticForNode(parameter, ...messageAndArgs); return addRelatedInfo(diagnostic, parameterError); } @@ -33105,11 +33149,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } setTextRangePosEnd(errorSpan, pos, end); if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, error, parameterRange, args.length); + let chain = chainDiagnosticMessages(/*details*/ undefined, error, parameterRange, maxArgLength); chain = chainDiagnosticMessages(chain, headMessage); return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), errorSpan, chain); } - return createDiagnosticForNodeArray(getSourceFileOfNode(node), errorSpan, error, parameterRange, args.length); + return createDiagnosticForNodeArray(getSourceFileOfNode(node), errorSpan, error, parameterRange, maxArgLength); } } @@ -33178,7 +33222,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reorderCandidates(signatures, candidates, callChainFlags); Debug.assert(candidates.length, "Revert #54442 and add a testcase with whatever triggered this"); - const args = getEffectiveCallArguments(node); + const [args, shortestTupleArgs] = getEffectiveCallArguments(node, signatures); // The excludeArgument array contains true for each context sensitive argument (an argument // is context sensitive it is susceptible to a one-time permanent contextual typing). @@ -33333,7 +33377,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else if (candidateForArgumentArityError) { - diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args, headMessage)); + diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args, shortestTupleArgs, headMessage)); } else if (candidateForTypeArgumentError) { checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, /*reportErrors*/ true, headMessage); @@ -33344,7 +33388,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments!, headMessage)); } else { - diagnostics.add(getArgumentArityError(node, signaturesWithCorrectTypeArgumentArity, args, headMessage)); + diagnostics.add(getArgumentArityError(node, signaturesWithCorrectTypeArgumentArity, args, shortestTupleArgs, headMessage)); } } } @@ -33379,7 +33423,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isSingleNonGenericCandidate) { const candidate = candidates[0]; - if (some(typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { + if (some(typeArguments) || !hasCorrectArity(node, args, shortestTupleArgs, candidate, signatureHelpTrailingComma)) { return undefined; } if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { @@ -33391,7 +33435,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) { const candidate = candidates[candidateIndex]; - if (!hasCorrectTypeArgumentArity(candidate, typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { + if (!hasCorrectTypeArgumentArity(candidate, typeArguments) || !hasCorrectArity(node, args, shortestTupleArgs, candidate, signatureHelpTrailingComma)) { continue; } @@ -33415,7 +33459,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters); // If the original signature has a generic rest type, instantiation may produce a // signature with different arity and we need to perform another arity check. - if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { + if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, shortestTupleArgs, checkCandidate, signatureHelpTrailingComma)) { candidateForArgumentArityError = checkCandidate; continue; } @@ -33438,7 +33482,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext.inferredTypeParameters); // If the original signature has a generic rest type, instantiation may produce a // signature with different arity and we need to perform another arity check. - if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { + if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, shortestTupleArgs, checkCandidate, signatureHelpTrailingComma)) { candidateForArgumentArityError = checkCandidate; continue; } diff --git a/tests/baselines/reference/callWithSpread6.errors.txt b/tests/baselines/reference/callWithSpread6.errors.txt new file mode 100644 index 0000000000000..5ba3cc62df2db --- /dev/null +++ b/tests/baselines/reference/callWithSpread6.errors.txt @@ -0,0 +1,53 @@ +callWithSpread6.ts(15,1): error TS2554: Expected 4 arguments, but got 3. +callWithSpread6.ts(17,19): error TS2554: Expected 1-4 arguments, but got 5. +callWithSpread6.ts(18,10): error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter. +callWithSpread6.ts(20,1): error TS2555: Expected at least 2 arguments, but got 1. +callWithSpread6.ts(22,3): error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter. +callWithSpread6.ts(23,1): error TS2555: Expected at least 3 arguments, but got 1. +callWithSpread6.ts(24,1): error TS2555: Expected at least 3 arguments, but got 2. + + +==== callWithSpread6.ts (7 errors) ==== + declare const n: number + declare const nntnnnt: [number, number] | [number, number, number] + declare const ntnnnt: [number] | [number, number, number] + declare const ntnnnut: [number] | [number, number, number?] + declare function setHours(a: number, b?: number, c?: number, d?: number): number + declare function setHoursStrict(a: number, b: number, c: number, d: number): number + declare function f(a: number, b: number, ...c: number[]): number + declare function g(a: number, b?: number, ...c: number[]): number + declare function h(a: number, b: number, c: number, ...d: number[]): number + + setHours(...nntnnnt) + setHours(...ntnnnt) + setHours(...ntnnnut) + setHours(n, n, ...nntnnnt) + setHoursStrict(n, ...nntnnnt) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2554: Expected 4 arguments, but got 3. +!!! related TS6210 callWithSpread6.ts:6:66: An argument for 'd' was not provided. + setHoursStrict(n, n, ...nntnnnt) + setHours(n, n, n, ...nntnnnt) + ~~~~~~~~~~ +!!! error TS2554: Expected 1-4 arguments, but got 5. + setHours(...nntnnnt, n) + ~~~~~~~~~~ +!!! error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter. + + f(...ntnnnt) + ~~~~~~~~~~~~ +!!! error TS2555: Expected at least 2 arguments, but got 1. +!!! related TS6210 callWithSpread6.ts:7:31: An argument for 'b' was not provided. + f(...nntnnnt) + f(...nntnnnt, n) + ~~~~~~~~~~ +!!! error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter. + h(...ntnnnt) + ~~~~~~~~~~~~ +!!! error TS2555: Expected at least 3 arguments, but got 1. +!!! related TS6210 callWithSpread6.ts:9:31: An argument for 'b' was not provided. + h(...nntnnnt) + ~~~~~~~~~~~~~ +!!! error TS2555: Expected at least 3 arguments, but got 2. +!!! related TS6210 callWithSpread6.ts:9:42: An argument for 'c' was not provided. + \ No newline at end of file diff --git a/tests/baselines/reference/callWithSpread6.js b/tests/baselines/reference/callWithSpread6.js new file mode 100644 index 0000000000000..df0cf347f7e3f --- /dev/null +++ b/tests/baselines/reference/callWithSpread6.js @@ -0,0 +1,44 @@ +//// [tests/cases/conformance/expressions/functionCalls/callWithSpread6.ts] //// + +//// [callWithSpread6.ts] +declare const n: number +declare const nntnnnt: [number, number] | [number, number, number] +declare const ntnnnt: [number] | [number, number, number] +declare const ntnnnut: [number] | [number, number, number?] +declare function setHours(a: number, b?: number, c?: number, d?: number): number +declare function setHoursStrict(a: number, b: number, c: number, d: number): number +declare function f(a: number, b: number, ...c: number[]): number +declare function g(a: number, b?: number, ...c: number[]): number +declare function h(a: number, b: number, c: number, ...d: number[]): number + +setHours(...nntnnnt) +setHours(...ntnnnt) +setHours(...ntnnnut) +setHours(n, n, ...nntnnnt) +setHoursStrict(n, ...nntnnnt) +setHoursStrict(n, n, ...nntnnnt) +setHours(n, n, n, ...nntnnnt) +setHours(...nntnnnt, n) + +f(...ntnnnt) +f(...nntnnnt) +f(...nntnnnt, n) +h(...ntnnnt) +h(...nntnnnt) + + +//// [callWithSpread6.js] +"use strict"; +setHours(...nntnnnt); +setHours(...ntnnnt); +setHours(...ntnnnut); +setHours(n, n, ...nntnnnt); +setHoursStrict(n, ...nntnnnt); +setHoursStrict(n, n, ...nntnnnt); +setHours(n, n, n, ...nntnnnt); +setHours(...nntnnnt, n); +f(...ntnnnt); +f(...nntnnnt); +f(...nntnnnt, n); +h(...ntnnnt); +h(...nntnnnt); diff --git a/tests/baselines/reference/callWithSpread6.symbols b/tests/baselines/reference/callWithSpread6.symbols new file mode 100644 index 0000000000000..92a59f1e744ce --- /dev/null +++ b/tests/baselines/reference/callWithSpread6.symbols @@ -0,0 +1,110 @@ +//// [tests/cases/conformance/expressions/functionCalls/callWithSpread6.ts] //// + +=== callWithSpread6.ts === +declare const n: number +>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13)) + +declare const nntnnnt: [number, number] | [number, number, number] +>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13)) + +declare const ntnnnt: [number] | [number, number, number] +>ntnnnt : Symbol(ntnnnt, Decl(callWithSpread6.ts, 2, 13)) + +declare const ntnnnut: [number] | [number, number, number?] +>ntnnnut : Symbol(ntnnnut, Decl(callWithSpread6.ts, 3, 13)) + +declare function setHours(a: number, b?: number, c?: number, d?: number): number +>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59)) +>a : Symbol(a, Decl(callWithSpread6.ts, 4, 26)) +>b : Symbol(b, Decl(callWithSpread6.ts, 4, 36)) +>c : Symbol(c, Decl(callWithSpread6.ts, 4, 48)) +>d : Symbol(d, Decl(callWithSpread6.ts, 4, 60)) + +declare function setHoursStrict(a: number, b: number, c: number, d: number): number +>setHoursStrict : Symbol(setHoursStrict, Decl(callWithSpread6.ts, 4, 80)) +>a : Symbol(a, Decl(callWithSpread6.ts, 5, 32)) +>b : Symbol(b, Decl(callWithSpread6.ts, 5, 42)) +>c : Symbol(c, Decl(callWithSpread6.ts, 5, 53)) +>d : Symbol(d, Decl(callWithSpread6.ts, 5, 64)) + +declare function f(a: number, b: number, ...c: number[]): number +>f : Symbol(f, Decl(callWithSpread6.ts, 5, 83)) +>a : Symbol(a, Decl(callWithSpread6.ts, 6, 19)) +>b : Symbol(b, Decl(callWithSpread6.ts, 6, 29)) +>c : Symbol(c, Decl(callWithSpread6.ts, 6, 40)) + +declare function g(a: number, b?: number, ...c: number[]): number +>g : Symbol(g, Decl(callWithSpread6.ts, 6, 64)) +>a : Symbol(a, Decl(callWithSpread6.ts, 7, 19)) +>b : Symbol(b, Decl(callWithSpread6.ts, 7, 29)) +>c : Symbol(c, Decl(callWithSpread6.ts, 7, 41)) + +declare function h(a: number, b: number, c: number, ...d: number[]): number +>h : Symbol(h, Decl(callWithSpread6.ts, 7, 65)) +>a : Symbol(a, Decl(callWithSpread6.ts, 8, 19)) +>b : Symbol(b, Decl(callWithSpread6.ts, 8, 29)) +>c : Symbol(c, Decl(callWithSpread6.ts, 8, 40)) +>d : Symbol(d, Decl(callWithSpread6.ts, 8, 51)) + +setHours(...nntnnnt) +>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59)) +>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13)) + +setHours(...ntnnnt) +>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59)) +>ntnnnt : Symbol(ntnnnt, Decl(callWithSpread6.ts, 2, 13)) + +setHours(...ntnnnut) +>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59)) +>ntnnnut : Symbol(ntnnnut, Decl(callWithSpread6.ts, 3, 13)) + +setHours(n, n, ...nntnnnt) +>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59)) +>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13)) +>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13)) +>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13)) + +setHoursStrict(n, ...nntnnnt) +>setHoursStrict : Symbol(setHoursStrict, Decl(callWithSpread6.ts, 4, 80)) +>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13)) +>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13)) + +setHoursStrict(n, n, ...nntnnnt) +>setHoursStrict : Symbol(setHoursStrict, Decl(callWithSpread6.ts, 4, 80)) +>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13)) +>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13)) +>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13)) + +setHours(n, n, n, ...nntnnnt) +>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59)) +>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13)) +>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13)) +>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13)) +>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13)) + +setHours(...nntnnnt, n) +>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59)) +>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13)) +>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13)) + +f(...ntnnnt) +>f : Symbol(f, Decl(callWithSpread6.ts, 5, 83)) +>ntnnnt : Symbol(ntnnnt, Decl(callWithSpread6.ts, 2, 13)) + +f(...nntnnnt) +>f : Symbol(f, Decl(callWithSpread6.ts, 5, 83)) +>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13)) + +f(...nntnnnt, n) +>f : Symbol(f, Decl(callWithSpread6.ts, 5, 83)) +>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13)) +>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13)) + +h(...ntnnnt) +>h : Symbol(h, Decl(callWithSpread6.ts, 7, 65)) +>ntnnnt : Symbol(ntnnnt, Decl(callWithSpread6.ts, 2, 13)) + +h(...nntnnnt) +>h : Symbol(h, Decl(callWithSpread6.ts, 7, 65)) +>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13)) + diff --git a/tests/baselines/reference/callWithSpread6.types b/tests/baselines/reference/callWithSpread6.types new file mode 100644 index 0000000000000..850504e71374a --- /dev/null +++ b/tests/baselines/reference/callWithSpread6.types @@ -0,0 +1,136 @@ +//// [tests/cases/conformance/expressions/functionCalls/callWithSpread6.ts] //// + +=== callWithSpread6.ts === +declare const n: number +>n : number + +declare const nntnnnt: [number, number] | [number, number, number] +>nntnnnt : [number, number] | [number, number, number] + +declare const ntnnnt: [number] | [number, number, number] +>ntnnnt : [number, number, number] | [number] + +declare const ntnnnut: [number] | [number, number, number?] +>ntnnnut : [number] | [number, number, (number | undefined)?] + +declare function setHours(a: number, b?: number, c?: number, d?: number): number +>setHours : (a: number, b?: number, c?: number, d?: number) => number +>a : number +>b : number | undefined +>c : number | undefined +>d : number | undefined + +declare function setHoursStrict(a: number, b: number, c: number, d: number): number +>setHoursStrict : (a: number, b: number, c: number, d: number) => number +>a : number +>b : number +>c : number +>d : number + +declare function f(a: number, b: number, ...c: number[]): number +>f : (a: number, b: number, ...c: number[]) => number +>a : number +>b : number +>c : number[] + +declare function g(a: number, b?: number, ...c: number[]): number +>g : (a: number, b?: number, ...c: number[]) => number +>a : number +>b : number | undefined +>c : number[] + +declare function h(a: number, b: number, c: number, ...d: number[]): number +>h : (a: number, b: number, c: number, ...d: number[]) => number +>a : number +>b : number +>c : number +>d : number[] + +setHours(...nntnnnt) +>setHours(...nntnnnt) : number +>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number +>...nntnnnt : number +>nntnnnt : [number, number] | [number, number, number] + +setHours(...ntnnnt) +>setHours(...ntnnnt) : number +>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number +>...ntnnnt : number +>ntnnnt : [number, number, number] | [number] + +setHours(...ntnnnut) +>setHours(...ntnnnut) : number +>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number +>...ntnnnut : number | undefined +>ntnnnut : [number] | [number, number, (number | undefined)?] + +setHours(n, n, ...nntnnnt) +>setHours(n, n, ...nntnnnt) : number +>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number +>n : number +>n : number +>...nntnnnt : number +>nntnnnt : [number, number] | [number, number, number] + +setHoursStrict(n, ...nntnnnt) +>setHoursStrict(n, ...nntnnnt) : number +>setHoursStrict : (a: number, b: number, c: number, d: number) => number +>n : number +>...nntnnnt : number +>nntnnnt : [number, number] | [number, number, number] + +setHoursStrict(n, n, ...nntnnnt) +>setHoursStrict(n, n, ...nntnnnt) : number +>setHoursStrict : (a: number, b: number, c: number, d: number) => number +>n : number +>n : number +>...nntnnnt : number +>nntnnnt : [number, number] | [number, number, number] + +setHours(n, n, n, ...nntnnnt) +>setHours(n, n, n, ...nntnnnt) : number +>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number +>n : number +>n : number +>n : number +>...nntnnnt : number +>nntnnnt : [number, number] | [number, number, number] + +setHours(...nntnnnt, n) +>setHours(...nntnnnt, n) : number +>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number +>...nntnnnt : number +>nntnnnt : [number, number] | [number, number, number] +>n : number + +f(...ntnnnt) +>f(...ntnnnt) : number +>f : (a: number, b: number, ...c: number[]) => number +>...ntnnnt : number +>ntnnnt : [number, number, number] | [number] + +f(...nntnnnt) +>f(...nntnnnt) : number +>f : (a: number, b: number, ...c: number[]) => number +>...nntnnnt : number +>nntnnnt : [number, number] | [number, number, number] + +f(...nntnnnt, n) +>f(...nntnnnt, n) : number +>f : (a: number, b: number, ...c: number[]) => number +>...nntnnnt : number +>nntnnnt : [number, number] | [number, number, number] +>n : number + +h(...ntnnnt) +>h(...ntnnnt) : number +>h : (a: number, b: number, c: number, ...d: number[]) => number +>...ntnnnt : number +>ntnnnt : [number, number, number] | [number] + +h(...nntnnnt) +>h(...nntnnnt) : number +>h : (a: number, b: number, c: number, ...d: number[]) => number +>...nntnnnt : number +>nntnnnt : [number, number] | [number, number, number] + diff --git a/tests/cases/conformance/expressions/functionCalls/callWithSpread6.ts b/tests/cases/conformance/expressions/functionCalls/callWithSpread6.ts new file mode 100644 index 0000000000000..e10c121d481e8 --- /dev/null +++ b/tests/cases/conformance/expressions/functionCalls/callWithSpread6.ts @@ -0,0 +1,26 @@ +// @strict: true +// @target: esnext +declare const n: number +declare const nntnnnt: [number, number] | [number, number, number] +declare const ntnnnt: [number] | [number, number, number] +declare const ntnnnut: [number] | [number, number, number?] +declare function setHours(a: number, b?: number, c?: number, d?: number): number +declare function setHoursStrict(a: number, b: number, c: number, d: number): number +declare function f(a: number, b: number, ...c: number[]): number +declare function g(a: number, b?: number, ...c: number[]): number +declare function h(a: number, b: number, c: number, ...d: number[]): number + +setHours(...nntnnnt) +setHours(...ntnnnt) +setHours(...ntnnnut) +setHours(n, n, ...nntnnnt) +setHoursStrict(n, ...nntnnnt) +setHoursStrict(n, n, ...nntnnnt) +setHours(n, n, n, ...nntnnnt) +setHours(...nntnnnt, n) + +f(...ntnnnt) +f(...nntnnnt) +f(...nntnnnt, n) +h(...ntnnnt) +h(...nntnnnt)