From 9ef65ef3a4cf550d7231fb55a508f09fb7bfff1d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 24 Aug 2018 13:29:28 -0700 Subject: [PATCH 1/7] Use getSpreadArgumentType when relating to complex rest parameter types --- src/compiler/checker.ts | 198 ++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 97 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 36cf9aa947..0a32874e52 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7789,8 +7789,12 @@ namespace ts { } function tryGetRestTypeOfSignature(signature: Signature): Type | undefined { - const type = getTypeOfRestParameter(signature); - return type && getIndexTypeOfType(type, IndexKind.Number); + if (signature.hasRestParameter) { + const sigRestType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); + const restType = isTupleType(sigRestType) ? getRestTypeOfTupleType(sigRestType) : sigRestType; + return restType && getIndexTypeOfType(restType, IndexKind.Number); + } + return undefined; } function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean): Signature { @@ -10718,9 +10722,9 @@ namespace ts { } const sourceCount = getParameterCount(source); - const sourceGenericRestType = getGenericRestType(source); - const targetGenericRestType = sourceGenericRestType ? getGenericRestType(target) : undefined; - if (sourceGenericRestType && !(targetGenericRestType && sourceCount === targetCount)) { + const sourceRestType = getNonArrayRestType(source); + const targetRestType = sourceRestType ? getNonArrayRestType(target) : undefined; + if (sourceRestType && !(targetRestType && sourceCount === targetCount)) { return Ternary.False; } @@ -10749,8 +10753,8 @@ namespace ts { const paramCount = Math.max(sourceCount, targetCount); const lastIndex = paramCount - 1; for (let i = 0; i < paramCount; i++) { - const sourceType = i === lastIndex && sourceGenericRestType || getTypeAtPosition(source, i); - const targetType = i === lastIndex && targetGenericRestType || getTypeAtPosition(target, i); + const sourceType = i === lastIndex && sourceRestType || getTypeAtPosition(source, i); + const targetType = i === lastIndex && targetRestType || getTypeAtPosition(target, i); // In order to ensure that any generic type Foo is at least co-variant with respect to T no matter // how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions, // they naturally relate only contra-variantly). However, if the source and target parameters both have @@ -12693,6 +12697,11 @@ namespace ts { return type.target.hasRestElement ? type.typeArguments![type.target.typeParameters!.length - 1] : undefined; } + function getRestArrayTypeOfTupleType(type: TupleTypeReference) { + const restType = getRestTypeOfTupleType(type); + return restType && createArrayType(restType); + } + function getLengthOfTupleType(type: TupleTypeReference) { return getTypeReferenceArity(type) - (type.target.hasRestElement ? 1 : 0); } @@ -13038,19 +13047,18 @@ namespace ts { function forEachMatchingParameterType(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) { const sourceCount = getParameterCount(source); const targetCount = getParameterCount(target); - const sourceHasRest = hasEffectiveRestParameter(source); - const targetHasRest = hasEffectiveRestParameter(target); - const maxCount = sourceHasRest && targetHasRest ? Math.max(sourceCount, targetCount) : - sourceHasRest ? targetCount : - targetHasRest ? sourceCount : + const sourceRestType = getEffectiveRestType(source); + const targetRestType = getEffectiveRestType(target); + const maxCount = sourceRestType && targetRestType ? Math.max(sourceCount, targetCount) : + sourceRestType ? targetCount : + targetRestType ? sourceCount : Math.min(sourceCount, targetCount); - const targetGenericRestType = getGenericRestType(target); - const paramCount = targetGenericRestType ? Math.min(targetCount - 1, maxCount) : maxCount; + const paramCount = targetRestType ? Math.min(targetCount - 1, maxCount) : maxCount; for (let i = 0; i < paramCount; i++) { callback(getTypeAtPosition(source, i), getTypeAtPosition(target, i)); } - if (targetGenericRestType) { - callback(getRestTypeAtPosition(source, paramCount), targetGenericRestType); + if (targetRestType) { + callback(getRestTypeAtPosition(source, paramCount), targetRestType); } } @@ -13510,32 +13518,37 @@ namespace ts { } function inferFromProperties(source: Type, target: Type) { - if (isTupleType(source) && isTupleType(target)) { - const sourceLength = getLengthOfTupleType(source); - const targetLength = getLengthOfTupleType(target); - const sourceRestType = getRestTypeOfTupleType(source); - const targetRestType = getRestTypeOfTupleType(target); - const fixedLength = targetLength < sourceLength || sourceRestType ? targetLength : sourceLength; - for (let i = 0; i < fixedLength; i++) { - inferFromTypes(i < sourceLength ? source.typeArguments![i] : sourceRestType!, target.typeArguments![i]); + if (isTupleType(source)) { + if (isTupleType(target)) { + const sourceLength = getLengthOfTupleType(source); + const targetLength = getLengthOfTupleType(target); + const sourceRestType = getRestTypeOfTupleType(source); + const targetRestType = getRestTypeOfTupleType(target); + const fixedLength = targetLength < sourceLength || sourceRestType ? targetLength : sourceLength; + for (let i = 0; i < fixedLength; i++) { + inferFromTypes(i < sourceLength ? source.typeArguments![i] : sourceRestType!, target.typeArguments![i]); + } + if (targetRestType) { + const types = fixedLength < sourceLength ? source.typeArguments!.slice(fixedLength, sourceLength) : []; + if (sourceRestType) { + types.push(sourceRestType); + } + if (types.length) { + inferFromTypes(getUnionType(types), targetRestType); + } + } + return; } - if (targetRestType) { - const types = fixedLength < sourceLength ? source.typeArguments!.slice(fixedLength, sourceLength) : []; - if (sourceRestType) { - types.push(sourceRestType); - } - if (types.length) { - inferFromTypes(getUnionType(types), targetRestType); - } + if (isArrayType(target)) { + inferFromIndexTypes(source, target); + return; } } - else { - const properties = getPropertiesOfObjectType(target); - for (const targetProp of properties) { - const sourceProp = getPropertyOfType(source, targetProp.escapedName); - if (sourceProp) { - inferFromTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); - } + const properties = getPropertiesOfObjectType(target); + for (const targetProp of properties) { + const sourceProp = getPropertyOfType(source, targetProp.escapedName); + if (sourceProp) { + inferFromTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); } } } @@ -18679,8 +18692,8 @@ namespace ts { inferTypes(context.inferences, thisArgumentType, thisType); } - const genericRestType = getGenericRestType(signature); - const argCount = genericRestType ? Math.min(getParameterCount(signature) - 1, args.length) : args.length; + const restType = getNonArrayRestType(signature); + const argCount = restType ? Math.min(getParameterCount(signature) - 1, args.length) : args.length; for (let i = 0; i < argCount; i++) { const arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression) { @@ -18693,14 +18706,21 @@ namespace ts { } } - if (genericRestType) { - const spreadType = getSpreadArgumentType(args, argCount, args.length, genericRestType, context); - inferTypes(context.inferences, spreadType, genericRestType); + if (restType) { + const spreadType = getSpreadArgumentType(args, argCount, args.length, restType, context); + inferTypes(context.inferences, spreadType, restType); } return getInferredTypes(context); } + function getArrayifiedType(type: Type) { + if (forEachType(type, t => !(t.flags & (TypeFlags.Any | TypeFlags.Instantiable) || isArrayType(t) || isTupleType(t)))) { + return createArrayType(getIndexTypeOfType(type, IndexKind.Number) || errorType); + } + return type; + } + function getSpreadArgumentType(args: ReadonlyArray, index: number, argCount: number, restType: TypeParameter, context: InferenceContext | undefined) { if (index >= argCount - 1) { const arg = args[argCount - 1]; @@ -18709,7 +18729,7 @@ namespace ts { // and the argument are ...x forms. return arg.kind === SyntaxKind.SyntheticExpression ? createArrayType((arg).type) : - checkExpressionWithContextualType((arg).expression, restType, context); + getArrayifiedType(checkExpressionWithContextualType((arg).expression, restType, context)); } } const contextualType = getIndexTypeOfType(restType, IndexKind.Number) || anyType; @@ -18814,28 +18834,27 @@ namespace ts { } } const headMessage = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1; - const restIndex = signature.hasRestParameter ? signature.parameters.length - 1 : -1; - const restType = restIndex >= 0 ? getTypeOfSymbol(signature.parameters[restIndex]) : anyType; - for (let i = 0; i < args.length; i++) { + const restType = getNonArrayRestType(signature); + const argCount = restType ? Math.min(getParameterCount(signature) - 1, args.length) : args.length; + for (let i = 0; i < argCount; i++) { const arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression) { - if (i === restIndex && (restType.flags & TypeFlags.TypeParameter || isSpreadArgument(arg) && !isArrayType(restType))) { - const spreadType = getSpreadArgumentType(args, i, args.length, restType, /*context*/ undefined); - return checkTypeRelatedTo(spreadType, restType, relation, arg, headMessage); - } - else { - const paramType = getTypeAtPosition(signature, i); - const argType = checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); - // If one or more arguments are still excluded (as indicated by a non-null excludeArgument parameter), - // we obtain the regular type of any object literal arguments because we may not have inferred complete - // parameter types yet and therefore excess property checks may yield false positives (see #17041). - const checkArgType = excludeArgument ? getRegularTypeOfObjectLiteral(argType) : argType; - if (!checkTypeRelatedTo(checkArgType, paramType, relation, reportErrors ? arg : undefined, headMessage)) { - return false; - } + const paramType = getTypeAtPosition(signature, i); + const argType = checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); + // If one or more arguments are still excluded (as indicated by a non-null excludeArgument parameter), + // we obtain the regular type of any object literal arguments because we may not have inferred complete + // parameter types yet and therefore excess property checks may yield false positives (see #17041). + const checkArgType = excludeArgument ? getRegularTypeOfObjectLiteral(argType) : argType; + if (!checkTypeRelatedTo(checkArgType, paramType, relation, reportErrors ? arg : undefined, headMessage)) { + return false; } } } + if (restType) { + const spreadType = getSpreadArgumentType(args, argCount, args.length, restType, /*context*/ undefined); + const errorNode = reportErrors ? argCount < args.length ? args[argCount] : node : undefined; + return checkTypeRelatedTo(spreadType, restType, relation, errorNode, headMessage); + } return true; } @@ -19187,7 +19206,7 @@ namespace ts { checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJavaScriptFile(candidate.declaration)); // 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 (getGenericRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { + if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { candidateForArgumentArityError = checkCandidate; continue; } @@ -20138,14 +20157,11 @@ namespace ts { function getRestTypeAtPosition(source: Signature, pos: number): Type { const paramCount = getParameterCount(source); - const hasRest = hasEffectiveRestParameter(source); - if (hasRest && pos === paramCount - 1) { - const genericRestType = getGenericRestType(source); - if (genericRestType) { - return genericRestType; - } + const restType = getEffectiveRestType(source); + if (restType && pos === paramCount - 1) { + return restType; } - const start = hasRest ? Math.min(pos, paramCount - 1) : pos; + const start = restType ? Math.min(pos, paramCount - 1) : pos; const types = []; const names = []; for (let i = start; i < paramCount; i++) { @@ -20154,18 +20170,7 @@ namespace ts { } const minArgumentCount = getMinArgumentCount(source); const minLength = minArgumentCount < start ? 0 : minArgumentCount - start; - return createTupleType(types, minLength, hasRest, names); - } - - function getTypeOfRestParameter(signature: Signature) { - if (signature.hasRestParameter) { - const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); - if (isTupleType(restType)) { - return getRestTypeOfTupleType(restType); - } - return restType; - } - return undefined; + return createTupleType(types, minLength, !!restType, names); } function getParameterCount(signature: Signature) { @@ -20192,16 +20197,6 @@ namespace ts { return signature.minArgumentCount; } - function getGenericRestType(signature: Signature) { - if (signature.hasRestParameter) { - const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); - if (restType.flags & TypeFlags.Instantiable) { - return restType; - } - } - return undefined; - } - function hasEffectiveRestParameter(signature: Signature) { if (signature.hasRestParameter) { const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); @@ -20210,6 +20205,19 @@ namespace ts { return false; } + function getEffectiveRestType(signature: Signature) { + if (signature.hasRestParameter) { + const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); + return isTupleType(restType) ? getRestArrayTypeOfTupleType(restType) : restType; + } + return undefined; + } + + function getNonArrayRestType(signature: Signature) { + const restType = getEffectiveRestType(signature); + return restType && !isArrayType(restType) && !isTypeAny(restType) ? restType : undefined; + } + function getTypeOfFirstParameterOfSignature(signature: Signature) { return getTypeOfFirstParameterOfSignatureWithFallback(signature, neverType); } @@ -21889,10 +21897,6 @@ namespace ts { } } - function isRestParameterType(type: Type) { - return isArrayType(type) || isTupleType(type) || type.flags & TypeFlags.Instantiable && isTypeAssignableTo(type, anyArrayType); - } - function checkParameter(node: ParameterDeclaration) { // Grammar checking // It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the @@ -21924,7 +21928,7 @@ namespace ts { // Only check rest parameter type if it's not a binding pattern. Since binding patterns are // not allowed in a rest parameter, we already have an error from checkGrammarParameterList. - if (node.dotDotDotToken && !isBindingPattern(node.name) && !isRestParameterType(getTypeOfSymbol(node.symbol))) { + if (node.dotDotDotToken && !isBindingPattern(node.name) && !isTypeAssignableTo(getTypeOfSymbol(node.symbol), anyArrayType)) { error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type); } } From 4e44b080200ec47ea5accaf51331a0ae73629740 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 24 Aug 2018 13:30:05 -0700 Subject: [PATCH 2/7] Accept new baselines --- ...tructuringParameterDeclaration4.errors.txt | 5 +- .../restParametersOfNonArrayTypes2.errors.txt | 86 +------------------ 2 files changed, 2 insertions(+), 89 deletions(-) diff --git a/tests/baselines/reference/destructuringParameterDeclaration4.errors.txt b/tests/baselines/reference/destructuringParameterDeclaration4.errors.txt index d5a0d34e1a..2af931d352 100644 --- a/tests/baselines/reference/destructuringParameterDeclaration4.errors.txt +++ b/tests/baselines/reference/destructuringParameterDeclaration4.errors.txt @@ -1,4 +1,3 @@ -tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts(13,13): error TS2370: A rest parameter must be of an array type. tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts(14,17): error TS1047: A rest parameter cannot be optional. tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts(15,16): error TS1048: A rest parameter cannot have an initializer. tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts(20,19): error TS2345: Argument of type 'true' is not assignable to parameter of type 'string | number'. @@ -16,7 +15,7 @@ tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts( tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts(34,28): error TS2304: Cannot find name 'E'. -==== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts (11 errors) ==== +==== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts (10 errors) ==== // If the parameter is a rest parameter, the parameter type is any[] // A type annotation for a rest parameter must denote an array type. @@ -30,8 +29,6 @@ tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts( function a0(...x: [number, number, string]) { } // Error, rest parameter must be array type function a1(...x: (number|string)[]) { } function a2(...a: someArray) { } // Error, rest parameter must be array type - ~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. function a3(...b?) { } // Error, can't be optional ~ !!! error TS1047: A rest parameter cannot be optional. diff --git a/tests/baselines/reference/restParametersOfNonArrayTypes2.errors.txt b/tests/baselines/reference/restParametersOfNonArrayTypes2.errors.txt index 654f053e8b..5c31031cba 100644 --- a/tests/baselines/reference/restParametersOfNonArrayTypes2.errors.txt +++ b/tests/baselines/reference/restParametersOfNonArrayTypes2.errors.txt @@ -1,40 +1,12 @@ -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(7,14): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(8,22): error TS2370: A rest parameter must be of an array type. tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(9,11): error TS1014: A rest parameter must be last in a parameter list. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(9,11): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(9,26): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(12,9): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(16,6): error TS2370: A rest parameter must be of an array type. tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(17,9): error TS1014: A rest parameter must be last in a parameter list. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(17,9): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(17,24): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(21,6): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(22,9): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(26,9): error TS2370: A rest parameter must be of an array type. tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(27,21): error TS1014: A rest parameter must be last in a parameter list. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(27,21): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(27,36): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(28,9): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(34,15): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(35,23): error TS2370: A rest parameter must be of an array type. tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(36,11): error TS1014: A rest parameter must be last in a parameter list. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(36,11): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(36,35): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(39,9): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(43,6): error TS2370: A rest parameter must be of an array type. tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(44,9): error TS1014: A rest parameter must be last in a parameter list. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(44,9): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(44,33): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(48,6): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(49,9): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(53,9): error TS2370: A rest parameter must be of an array type. tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(54,21): error TS1014: A rest parameter must be last in a parameter list. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(54,21): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(54,45): error TS2370: A rest parameter must be of an array type. -tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts(55,9): error TS2370: A rest parameter must be of an array type. -==== tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts (34 errors) ==== +==== tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfNonArrayTypes2.ts (6 errors) ==== // Rest parameters must be an array type if they have a type annotation, // user defined subtypes of array do not count, all of these are errors @@ -42,120 +14,64 @@ tests/cases/conformance/types/objectTypeLiteral/callSignatures/restParametersOfN interface MyThing2 extends Array { } function foo(...x: MyThing) { } - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. var f = function foo(...x: MyThing) { } - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. var f2 = (...x: MyThing, ...y: MyThing) => { } ~~~ !!! error TS1014: A rest parameter must be last in a parameter list. - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. class C { foo(...x: MyThing) { } - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. } interface I { (...x: MyThing); - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. foo(...x: MyThing, ...y: MyThing); ~~~ !!! error TS1014: A rest parameter must be last in a parameter list. - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. } var a: { (...x: MyThing); - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. foo(...x: MyThing); - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. } var b = { foo(...x: MyThing) { }, - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. a: function foo(...x: MyThing, ...y: MyThing) { }, ~~~ !!! error TS1014: A rest parameter must be last in a parameter list. - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. b: (...x: MyThing) => { } - ~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. } function foo2(...x: MyThing2) { } - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. var f3 = function foo(...x: MyThing2) { } - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. var f4 = (...x: MyThing2, ...y: MyThing2) => { } ~~~ !!! error TS1014: A rest parameter must be last in a parameter list. - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. class C2 { foo(...x: MyThing2) { } - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. } interface I2 { (...x: MyThing2); - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. foo(...x: MyThing2, ...y: MyThing2); ~~~ !!! error TS1014: A rest parameter must be last in a parameter list. - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. } var a2: { (...x: MyThing2); - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. foo(...x: MyThing2); - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. } var b2 = { foo(...x: MyThing2) { }, - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. a: function foo(...x: MyThing2, ...y: MyThing2) { }, ~~~ !!! error TS1014: A rest parameter must be last in a parameter list. - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. b: (...x: MyThing2) => { } - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2370: A rest parameter must be of an array type. } \ No newline at end of file From f5f61335ee655675f33e6b7238f9c160036d0eb6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 25 Aug 2018 07:29:15 -0700 Subject: [PATCH 3/7] Revise complex rest parameter handling in relations and inference --- src/compiler/checker.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0a32874e52..39e1ab5e52 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10723,8 +10723,9 @@ namespace ts { const sourceCount = getParameterCount(source); const sourceRestType = getNonArrayRestType(source); - const targetRestType = sourceRestType ? getNonArrayRestType(target) : undefined; - if (sourceRestType && !(targetRestType && sourceCount === targetCount)) { + const targetRestType = getNonArrayRestType(target); + if (sourceRestType && targetRestType && sourceCount !== targetCount) { + // We're not able to relate misaliged complex rest parameters return Ternary.False; } @@ -10750,11 +10751,12 @@ namespace ts { } } - const paramCount = Math.max(sourceCount, targetCount); - const lastIndex = paramCount - 1; + const paramCount = sourceRestType || targetRestType ? Math.min(sourceCount, targetCount) : Math.max(sourceCount, targetCount); + const restIndex = sourceRestType || targetRestType ? paramCount - 1 : -1; + for (let i = 0; i < paramCount; i++) { - const sourceType = i === lastIndex && sourceRestType || getTypeAtPosition(source, i); - const targetType = i === lastIndex && targetRestType || getTypeAtPosition(target, i); + const sourceType = i === restIndex ? getRestTypeAtPosition(source, i) : getTypeAtPosition(source, i); + const targetType = i === restIndex ? getRestTypeAtPosition(target, i) : getTypeAtPosition(target, i); // In order to ensure that any generic type Foo is at least co-variant with respect to T no matter // how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions, // they naturally relate only contra-variantly). However, if the source and target parameters both have @@ -13049,11 +13051,9 @@ namespace ts { const targetCount = getParameterCount(target); const sourceRestType = getEffectiveRestType(source); const targetRestType = getEffectiveRestType(target); - const maxCount = sourceRestType && targetRestType ? Math.max(sourceCount, targetCount) : + const paramCount = targetRestType ? Math.min(targetCount - 1, sourceCount) : sourceRestType ? targetCount : - targetRestType ? sourceCount : Math.min(sourceCount, targetCount); - const paramCount = targetRestType ? Math.min(targetCount - 1, maxCount) : maxCount; for (let i = 0; i < paramCount; i++) { callback(getTypeAtPosition(source, i), getTypeAtPosition(target, i)); } From 0e1b99842c3a35e6e113253e2e3cfe9ce6ee60bc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 25 Aug 2018 07:29:34 -0700 Subject: [PATCH 4/7] Accept new baselines --- .../restTuplesFromContextualTypes.errors.txt | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 tests/baselines/reference/restTuplesFromContextualTypes.errors.txt diff --git a/tests/baselines/reference/restTuplesFromContextualTypes.errors.txt b/tests/baselines/reference/restTuplesFromContextualTypes.errors.txt new file mode 100644 index 0000000000..7495095d07 --- /dev/null +++ b/tests/baselines/reference/restTuplesFromContextualTypes.errors.txt @@ -0,0 +1,84 @@ +tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error TS2345: Argument of type '(a: number, b: any, ...x: any[]) => void' is not assignable to parameter of type '(x: number, ...args: T) => void'. + Types of parameters 'b' and 'args' are incompatible. + Type 'T' is not assignable to type '[any, ...any[]]'. + Type 'any[]' is not assignable to type '[any, ...any[]]'. + Property '0' is missing in type 'any[]'. + + +==== tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts (1 errors) ==== + declare const t1: [number, boolean, string]; + + (function (a, b, c){})(...t1); + (function (...x){})(...t1); + (function (a, ...x){})(...t1); + (function (a, b, ...x){})(...t1); + (function (a, b, c, ...x){})(...t1); + + declare function f1(cb: (...args: typeof t1) => void): void; + + f1((a, b, c) => {}) + f1((...x) => {}) + f1((a, ...x) => {}) + f1((a, b, ...x) => {}) + f1((a, b, c, ...x) => {}) + + declare const t2: [number, boolean, ...string[]]; + + (function (a, b, c){})(...t2); + (function (...x){})(...t2); + (function (a, ...x){})(...t2); + (function (a, b, ...x){})(...t2); + (function (a, b, c, ...x){})(...t2); + + declare function f2(cb: (...args: typeof t2) => void): void; + + f2((a, b, c) => {}) + f2((...x) => {}) + f2((a, ...x) => {}) + f2((a, b, ...x) => {}) + f2((a, b, c, ...x) => {}) + + declare const t3: [boolean, ...string[]]; + + (function (a, b, c){})(1, ...t3); + (function (...x){})(1, ...t3); + (function (a, ...x){})(1, ...t3); + (function (a, b, ...x){})(1, ...t3); + (function (a, b, c, ...x){})(1, ...t3); + + declare function f3(cb: (x: number, ...args: typeof t3) => void): void; + + f3((a, b, c) => {}) + f3((...x) => {}) + f3((a, ...x) => {}) + f3((a, b, ...x) => {}) + f3((a, b, c, ...x) => {}) + + function f4(t: T) { + (function(...x){})(...t); + (function(a, ...x){})(1, ...t); + (function(a, ...x){})(1, 2, ...t); + function f(cb: (x: number, ...args: T) => void) {} + f((...x) => {}); + f((a, ...x) => {}); + f((a, b, ...x) => {}); + ~~~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '(a: number, b: any, ...x: any[]) => void' is not assignable to parameter of type '(x: number, ...args: T) => void'. +!!! error TS2345: Types of parameters 'b' and 'args' are incompatible. +!!! error TS2345: Type 'T' is not assignable to type '[any, ...any[]]'. +!!! error TS2345: Type 'any[]' is not assignable to type '[any, ...any[]]'. +!!! error TS2345: Property '0' is missing in type 'any[]'. + } + + // Repro from #25288 + + declare var tuple: [number, string]; + (function foo(a, b){}(...tuple)); + + // Repro from #25289 + + declare function take(cb: (a: number, b: string) => void): void; + + (function foo(...rest){}(1, '')); + take(function(...rest){}); + \ No newline at end of file From 676892ee56ef5804ea018ab217f1d4d1399bf4ef Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 25 Aug 2018 07:55:13 -0700 Subject: [PATCH 5/7] Add tests --- .../types/rest/genericRestParameters3.ts | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/cases/conformance/types/rest/genericRestParameters3.ts diff --git a/tests/cases/conformance/types/rest/genericRestParameters3.ts b/tests/cases/conformance/types/rest/genericRestParameters3.ts new file mode 100644 index 0000000000..e2e2a3a3fb --- /dev/null +++ b/tests/cases/conformance/types/rest/genericRestParameters3.ts @@ -0,0 +1,56 @@ +// @strict: true +// @declaration: true + +declare let f1: (x: string, ...args: [string] | [number, boolean]) => void; +declare let f2: (x: string, y: string) => void; +declare let f3: (x: string, y: number, z: boolean) => void; +declare let f4: (...args: [string, string] | [string, number, boolean]) => void; + +declare const tt: [string] | [number, boolean]; + +f1("foo", "abc"); +f1("foo", 10, true); +f1("foo", ...tt); +f1("foo", 10); // Error +f1("foo"); // Error + +f2 = f1; +f3 = f1; +f4 = f1; // Error, misaligned complex rest types +f1 = f2; // Error +f1 = f3; // Error +f1 = f4; // Error, misaligned complex rest types + +// Repro from #26110 + +interface CoolArray extends Array { + hello: number; +} + +declare function foo(cb: (...args: T) => void): void; + +foo>(); // Error +foo>(100); // Error +foo>(foo); // Error + +function bar(...args: T): T { + return args; +} + +let a = bar(10, 20); +let b = bar>(10, 20); // Error + +declare function baz(...args: CoolArray): void; +declare const ca: CoolArray; + +baz(); // Error +baz(1); // Error +baz(1, 2); // Error +baz(...ca); // Error + +// Repro from #26491 + +declare function hmm(...args: A): void; +hmm(); // okay, A = [] +hmm(1, "s"); // okay, A = [1, "s"] +hmm("what"); // no error? A = [] | [number, string] ? From 349bee92a34cf3550ae594213ad1eefabfb2f3df Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 25 Aug 2018 07:55:21 -0700 Subject: [PATCH 6/7] Accept new baselines --- .../genericRestParameters3.errors.txt | 148 ++++++++++++++ .../reference/genericRestParameters3.js | 106 ++++++++++ .../reference/genericRestParameters3.symbols | 157 +++++++++++++++ .../reference/genericRestParameters3.types | 182 ++++++++++++++++++ 4 files changed, 593 insertions(+) create mode 100644 tests/baselines/reference/genericRestParameters3.errors.txt create mode 100644 tests/baselines/reference/genericRestParameters3.js create mode 100644 tests/baselines/reference/genericRestParameters3.symbols create mode 100644 tests/baselines/reference/genericRestParameters3.types diff --git a/tests/baselines/reference/genericRestParameters3.errors.txt b/tests/baselines/reference/genericRestParameters3.errors.txt new file mode 100644 index 0000000000..1f02815339 --- /dev/null +++ b/tests/baselines/reference/genericRestParameters3.errors.txt @@ -0,0 +1,148 @@ +tests/cases/conformance/types/rest/genericRestParameters3.ts(11,11): error TS2345: Argument of type '[10]' is not assignable to parameter of type '[string] | [number, boolean]'. + Type '[10]' is not assignable to type '[string]'. + Type '10' is not assignable to type 'string'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(12,1): error TS2345: Argument of type '[]' is not assignable to parameter of type '[string] | [number, boolean]'. + Type '[]' is not assignable to type '[number, boolean]'. + Property '0' is missing in type '[]'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(16,1): error TS2322: Type '(x: string, ...args: [string] | [number, boolean]) => void' is not assignable to type '(...args: [string, string] | [string, number, boolean]) => void'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(17,1): error TS2322: Type '(x: string, y: string) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. + Types of parameters 'y' and 'args' are incompatible. + Type '[string] | [number, boolean]' is not assignable to type '[string]'. + Type '[number, boolean]' is not assignable to type '[string]'. + Types of property '0' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(18,1): error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. + Types of parameters 'y' and 'args' are incompatible. + Type '[string] | [number, boolean]' is not assignable to type '[number, boolean]'. + Type '[string]' is not assignable to type '[number, boolean]'. + Property '1' is missing in type '[string]'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(19,1): error TS2322: Type '(...args: [string, string] | [string, number, boolean]) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(29,1): error TS2554: Expected 1 arguments, but got 0. +tests/cases/conformance/types/rest/genericRestParameters3.ts(30,21): error TS2345: Argument of type '100' is not assignable to parameter of type '(...args: CoolArray) => void'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(31,21): error TS2345: Argument of type '(cb: (...args: T) => void) => void' is not assignable to parameter of type '(...args: CoolArray) => void'. + Types of parameters 'cb' and 'args' are incompatible. + Type 'CoolArray' is not assignable to type '[(...args: any[]) => void]'. + Property '0' is missing in type 'CoolArray'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(38,32): error TS2345: Argument of type '[10, 20]' is not assignable to parameter of type 'CoolArray'. + Property 'hello' is missing in type '[10, 20]'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(43,1): error TS2345: Argument of type '[]' is not assignable to parameter of type 'CoolArray'. + Property 'hello' is missing in type '[]'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(44,5): error TS2345: Argument of type '[number]' is not assignable to parameter of type 'CoolArray<{}>'. + Property 'hello' is missing in type '[number]'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(45,5): error TS2345: Argument of type '[number, number]' is not assignable to parameter of type 'CoolArray<{}>'. + Property 'hello' is missing in type '[number, number]'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(46,5): error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'CoolArray'. + Property 'hello' is missing in type 'number[]'. +tests/cases/conformance/types/rest/genericRestParameters3.ts(53,5): error TS2345: Argument of type '["what"]' is not assignable to parameter of type '[] | [number, string]'. + Type '["what"]' is not assignable to type '[number, string]'. + Property '1' is missing in type '["what"]'. + + +==== tests/cases/conformance/types/rest/genericRestParameters3.ts (15 errors) ==== + declare let f1: (x: string, ...args: [string] | [number, boolean]) => void; + declare let f2: (x: string, y: string) => void; + declare let f3: (x: string, y: number, z: boolean) => void; + declare let f4: (...args: [string, string] | [string, number, boolean]) => void; + + declare const tt: [string] | [number, boolean]; + + f1("foo", "abc"); + f1("foo", 10, true); + f1("foo", ...tt); + f1("foo", 10); // Error + ~~ +!!! error TS2345: Argument of type '[10]' is not assignable to parameter of type '[string] | [number, boolean]'. +!!! error TS2345: Type '[10]' is not assignable to type '[string]'. +!!! error TS2345: Type '10' is not assignable to type 'string'. + f1("foo"); // Error + ~~~~~~~~~ +!!! error TS2345: Argument of type '[]' is not assignable to parameter of type '[string] | [number, boolean]'. +!!! error TS2345: Type '[]' is not assignable to type '[number, boolean]'. +!!! error TS2345: Property '0' is missing in type '[]'. + + f2 = f1; + f3 = f1; + f4 = f1; // Error, misaligned complex rest types + ~~ +!!! error TS2322: Type '(x: string, ...args: [string] | [number, boolean]) => void' is not assignable to type '(...args: [string, string] | [string, number, boolean]) => void'. + f1 = f2; // Error + ~~ +!!! error TS2322: Type '(x: string, y: string) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. +!!! error TS2322: Types of parameters 'y' and 'args' are incompatible. +!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type '[string]'. +!!! error TS2322: Type '[number, boolean]' is not assignable to type '[string]'. +!!! error TS2322: Types of property '0' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + f1 = f3; // Error + ~~ +!!! error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. +!!! error TS2322: Types of parameters 'y' and 'args' are incompatible. +!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type '[number, boolean]'. +!!! error TS2322: Type '[string]' is not assignable to type '[number, boolean]'. +!!! error TS2322: Property '1' is missing in type '[string]'. + f1 = f4; // Error, misaligned complex rest types + ~~ +!!! error TS2322: Type '(...args: [string, string] | [string, number, boolean]) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. + + // Repro from #26110 + + interface CoolArray extends Array { + hello: number; + } + + declare function foo(cb: (...args: T) => void): void; + + foo>(); // Error + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2554: Expected 1 arguments, but got 0. + foo>(100); // Error + ~~~ +!!! error TS2345: Argument of type '100' is not assignable to parameter of type '(...args: CoolArray) => void'. + foo>(foo); // Error + ~~~ +!!! error TS2345: Argument of type '(cb: (...args: T) => void) => void' is not assignable to parameter of type '(...args: CoolArray) => void'. +!!! error TS2345: Types of parameters 'cb' and 'args' are incompatible. +!!! error TS2345: Type 'CoolArray' is not assignable to type '[(...args: any[]) => void]'. +!!! error TS2345: Property '0' is missing in type 'CoolArray'. + + function bar(...args: T): T { + return args; + } + + let a = bar(10, 20); + let b = bar>(10, 20); // Error + ~~ +!!! error TS2345: Argument of type '[10, 20]' is not assignable to parameter of type 'CoolArray'. +!!! error TS2345: Property 'hello' is missing in type '[10, 20]'. + + declare function baz(...args: CoolArray): void; + declare const ca: CoolArray; + + baz(); // Error + ~~~~~ +!!! error TS2345: Argument of type '[]' is not assignable to parameter of type 'CoolArray'. +!!! error TS2345: Property 'hello' is missing in type '[]'. + baz(1); // Error + ~ +!!! error TS2345: Argument of type '[number]' is not assignable to parameter of type 'CoolArray<{}>'. +!!! error TS2345: Property 'hello' is missing in type '[number]'. + baz(1, 2); // Error + ~ +!!! error TS2345: Argument of type '[number, number]' is not assignable to parameter of type 'CoolArray<{}>'. +!!! error TS2345: Property 'hello' is missing in type '[number, number]'. + baz(...ca); // Error + ~~~~~ +!!! error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'CoolArray'. +!!! error TS2345: Property 'hello' is missing in type 'number[]'. + + // Repro from #26491 + + declare function hmm(...args: A): void; + hmm(); // okay, A = [] + hmm(1, "s"); // okay, A = [1, "s"] + hmm("what"); // no error? A = [] | [number, string] ? + ~~~~~~ +!!! error TS2345: Argument of type '["what"]' is not assignable to parameter of type '[] | [number, string]'. +!!! error TS2345: Type '["what"]' is not assignable to type '[number, string]'. +!!! error TS2345: Property '1' is missing in type '["what"]'. + \ No newline at end of file diff --git a/tests/baselines/reference/genericRestParameters3.js b/tests/baselines/reference/genericRestParameters3.js new file mode 100644 index 0000000000..132edcbefb --- /dev/null +++ b/tests/baselines/reference/genericRestParameters3.js @@ -0,0 +1,106 @@ +//// [genericRestParameters3.ts] +declare let f1: (x: string, ...args: [string] | [number, boolean]) => void; +declare let f2: (x: string, y: string) => void; +declare let f3: (x: string, y: number, z: boolean) => void; +declare let f4: (...args: [string, string] | [string, number, boolean]) => void; + +declare const tt: [string] | [number, boolean]; + +f1("foo", "abc"); +f1("foo", 10, true); +f1("foo", ...tt); +f1("foo", 10); // Error +f1("foo"); // Error + +f2 = f1; +f3 = f1; +f4 = f1; // Error, misaligned complex rest types +f1 = f2; // Error +f1 = f3; // Error +f1 = f4; // Error, misaligned complex rest types + +// Repro from #26110 + +interface CoolArray extends Array { + hello: number; +} + +declare function foo(cb: (...args: T) => void): void; + +foo>(); // Error +foo>(100); // Error +foo>(foo); // Error + +function bar(...args: T): T { + return args; +} + +let a = bar(10, 20); +let b = bar>(10, 20); // Error + +declare function baz(...args: CoolArray): void; +declare const ca: CoolArray; + +baz(); // Error +baz(1); // Error +baz(1, 2); // Error +baz(...ca); // Error + +// Repro from #26491 + +declare function hmm(...args: A): void; +hmm(); // okay, A = [] +hmm(1, "s"); // okay, A = [1, "s"] +hmm("what"); // no error? A = [] | [number, string] ? + + +//// [genericRestParameters3.js] +"use strict"; +f1("foo", "abc"); +f1("foo", 10, true); +f1.apply(void 0, ["foo"].concat(tt)); +f1("foo", 10); // Error +f1("foo"); // Error +f2 = f1; +f3 = f1; +f4 = f1; // Error, misaligned complex rest types +f1 = f2; // Error +f1 = f3; // Error +f1 = f4; // Error, misaligned complex rest types +foo(); // Error +foo(100); // Error +foo(foo); // Error +function bar() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return args; +} +var a = bar(10, 20); +var b = bar(10, 20); // Error +baz(); // Error +baz(1); // Error +baz(1, 2); // Error +baz.apply(void 0, ca); // Error +hmm(); // okay, A = [] +hmm(1, "s"); // okay, A = [1, "s"] +hmm("what"); // no error? A = [] | [number, string] ? + + +//// [genericRestParameters3.d.ts] +declare let f1: (x: string, ...args: [string] | [number, boolean]) => void; +declare let f2: (x: string, y: string) => void; +declare let f3: (x: string, y: number, z: boolean) => void; +declare let f4: (...args: [string, string] | [string, number, boolean]) => void; +declare const tt: [string] | [number, boolean]; +interface CoolArray extends Array { + hello: number; +} +declare function foo(cb: (...args: T) => void): void; +declare function bar(...args: T): T; +declare let a: [number, number]; +declare let b: any; +declare function baz(...args: CoolArray): void; +declare const ca: CoolArray; +declare function hmm(...args: A): void; diff --git a/tests/baselines/reference/genericRestParameters3.symbols b/tests/baselines/reference/genericRestParameters3.symbols new file mode 100644 index 0000000000..a768f205b5 --- /dev/null +++ b/tests/baselines/reference/genericRestParameters3.symbols @@ -0,0 +1,157 @@ +=== tests/cases/conformance/types/rest/genericRestParameters3.ts === +declare let f1: (x: string, ...args: [string] | [number, boolean]) => void; +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) +>x : Symbol(x, Decl(genericRestParameters3.ts, 0, 17)) +>args : Symbol(args, Decl(genericRestParameters3.ts, 0, 27)) + +declare let f2: (x: string, y: string) => void; +>f2 : Symbol(f2, Decl(genericRestParameters3.ts, 1, 11)) +>x : Symbol(x, Decl(genericRestParameters3.ts, 1, 17)) +>y : Symbol(y, Decl(genericRestParameters3.ts, 1, 27)) + +declare let f3: (x: string, y: number, z: boolean) => void; +>f3 : Symbol(f3, Decl(genericRestParameters3.ts, 2, 11)) +>x : Symbol(x, Decl(genericRestParameters3.ts, 2, 17)) +>y : Symbol(y, Decl(genericRestParameters3.ts, 2, 27)) +>z : Symbol(z, Decl(genericRestParameters3.ts, 2, 38)) + +declare let f4: (...args: [string, string] | [string, number, boolean]) => void; +>f4 : Symbol(f4, Decl(genericRestParameters3.ts, 3, 11)) +>args : Symbol(args, Decl(genericRestParameters3.ts, 3, 17)) + +declare const tt: [string] | [number, boolean]; +>tt : Symbol(tt, Decl(genericRestParameters3.ts, 5, 13)) + +f1("foo", "abc"); +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) + +f1("foo", 10, true); +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) + +f1("foo", ...tt); +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) +>tt : Symbol(tt, Decl(genericRestParameters3.ts, 5, 13)) + +f1("foo", 10); // Error +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) + +f1("foo"); // Error +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) + +f2 = f1; +>f2 : Symbol(f2, Decl(genericRestParameters3.ts, 1, 11)) +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) + +f3 = f1; +>f3 : Symbol(f3, Decl(genericRestParameters3.ts, 2, 11)) +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) + +f4 = f1; // Error, misaligned complex rest types +>f4 : Symbol(f4, Decl(genericRestParameters3.ts, 3, 11)) +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) + +f1 = f2; // Error +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) +>f2 : Symbol(f2, Decl(genericRestParameters3.ts, 1, 11)) + +f1 = f3; // Error +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) +>f3 : Symbol(f3, Decl(genericRestParameters3.ts, 2, 11)) + +f1 = f4; // Error, misaligned complex rest types +>f1 : Symbol(f1, Decl(genericRestParameters3.ts, 0, 11)) +>f4 : Symbol(f4, Decl(genericRestParameters3.ts, 3, 11)) + +// Repro from #26110 + +interface CoolArray extends Array { +>CoolArray : Symbol(CoolArray, Decl(genericRestParameters3.ts, 18, 8)) +>E : Symbol(E, Decl(genericRestParameters3.ts, 22, 20)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>E : Symbol(E, Decl(genericRestParameters3.ts, 22, 20)) + + hello: number; +>hello : Symbol(CoolArray.hello, Decl(genericRestParameters3.ts, 22, 41)) +} + +declare function foo(cb: (...args: T) => void): void; +>foo : Symbol(foo, Decl(genericRestParameters3.ts, 24, 1)) +>T : Symbol(T, Decl(genericRestParameters3.ts, 26, 21)) +>cb : Symbol(cb, Decl(genericRestParameters3.ts, 26, 38)) +>args : Symbol(args, Decl(genericRestParameters3.ts, 26, 43)) +>T : Symbol(T, Decl(genericRestParameters3.ts, 26, 21)) + +foo>(); // Error +>foo : Symbol(foo, Decl(genericRestParameters3.ts, 24, 1)) +>CoolArray : Symbol(CoolArray, Decl(genericRestParameters3.ts, 18, 8)) + +foo>(100); // Error +>foo : Symbol(foo, Decl(genericRestParameters3.ts, 24, 1)) +>CoolArray : Symbol(CoolArray, Decl(genericRestParameters3.ts, 18, 8)) + +foo>(foo); // Error +>foo : Symbol(foo, Decl(genericRestParameters3.ts, 24, 1)) +>CoolArray : Symbol(CoolArray, Decl(genericRestParameters3.ts, 18, 8)) +>foo : Symbol(foo, Decl(genericRestParameters3.ts, 24, 1)) + +function bar(...args: T): T { +>bar : Symbol(bar, Decl(genericRestParameters3.ts, 30, 25)) +>T : Symbol(T, Decl(genericRestParameters3.ts, 32, 13)) +>args : Symbol(args, Decl(genericRestParameters3.ts, 32, 30)) +>T : Symbol(T, Decl(genericRestParameters3.ts, 32, 13)) +>T : Symbol(T, Decl(genericRestParameters3.ts, 32, 13)) + + return args; +>args : Symbol(args, Decl(genericRestParameters3.ts, 32, 30)) +} + +let a = bar(10, 20); +>a : Symbol(a, Decl(genericRestParameters3.ts, 36, 3)) +>bar : Symbol(bar, Decl(genericRestParameters3.ts, 30, 25)) + +let b = bar>(10, 20); // Error +>b : Symbol(b, Decl(genericRestParameters3.ts, 37, 3)) +>bar : Symbol(bar, Decl(genericRestParameters3.ts, 30, 25)) +>CoolArray : Symbol(CoolArray, Decl(genericRestParameters3.ts, 18, 8)) + +declare function baz(...args: CoolArray): void; +>baz : Symbol(baz, Decl(genericRestParameters3.ts, 37, 39)) +>T : Symbol(T, Decl(genericRestParameters3.ts, 39, 21)) +>args : Symbol(args, Decl(genericRestParameters3.ts, 39, 24)) +>CoolArray : Symbol(CoolArray, Decl(genericRestParameters3.ts, 18, 8)) +>T : Symbol(T, Decl(genericRestParameters3.ts, 39, 21)) + +declare const ca: CoolArray; +>ca : Symbol(ca, Decl(genericRestParameters3.ts, 40, 13)) +>CoolArray : Symbol(CoolArray, Decl(genericRestParameters3.ts, 18, 8)) + +baz(); // Error +>baz : Symbol(baz, Decl(genericRestParameters3.ts, 37, 39)) + +baz(1); // Error +>baz : Symbol(baz, Decl(genericRestParameters3.ts, 37, 39)) + +baz(1, 2); // Error +>baz : Symbol(baz, Decl(genericRestParameters3.ts, 37, 39)) + +baz(...ca); // Error +>baz : Symbol(baz, Decl(genericRestParameters3.ts, 37, 39)) +>ca : Symbol(ca, Decl(genericRestParameters3.ts, 40, 13)) + +// Repro from #26491 + +declare function hmm(...args: A): void; +>hmm : Symbol(hmm, Decl(genericRestParameters3.ts, 45, 11)) +>A : Symbol(A, Decl(genericRestParameters3.ts, 49, 21)) +>args : Symbol(args, Decl(genericRestParameters3.ts, 49, 54)) +>A : Symbol(A, Decl(genericRestParameters3.ts, 49, 21)) + +hmm(); // okay, A = [] +>hmm : Symbol(hmm, Decl(genericRestParameters3.ts, 45, 11)) + +hmm(1, "s"); // okay, A = [1, "s"] +>hmm : Symbol(hmm, Decl(genericRestParameters3.ts, 45, 11)) + +hmm("what"); // no error? A = [] | [number, string] ? +>hmm : Symbol(hmm, Decl(genericRestParameters3.ts, 45, 11)) + diff --git a/tests/baselines/reference/genericRestParameters3.types b/tests/baselines/reference/genericRestParameters3.types new file mode 100644 index 0000000000..8d8d145a44 --- /dev/null +++ b/tests/baselines/reference/genericRestParameters3.types @@ -0,0 +1,182 @@ +=== tests/cases/conformance/types/rest/genericRestParameters3.ts === +declare let f1: (x: string, ...args: [string] | [number, boolean]) => void; +>f1 : (x: string, ...args: [string] | [number, boolean]) => void +>x : string +>args : [string] | [number, boolean] + +declare let f2: (x: string, y: string) => void; +>f2 : (x: string, y: string) => void +>x : string +>y : string + +declare let f3: (x: string, y: number, z: boolean) => void; +>f3 : (x: string, y: number, z: boolean) => void +>x : string +>y : number +>z : boolean + +declare let f4: (...args: [string, string] | [string, number, boolean]) => void; +>f4 : (...args: [string, string] | [string, number, boolean]) => void +>args : [string, string] | [string, number, boolean] + +declare const tt: [string] | [number, boolean]; +>tt : [string] | [number, boolean] + +f1("foo", "abc"); +>f1("foo", "abc") : void +>f1 : (x: string, ...args: [string] | [number, boolean]) => void +>"foo" : "foo" +>"abc" : "abc" + +f1("foo", 10, true); +>f1("foo", 10, true) : void +>f1 : (x: string, ...args: [string] | [number, boolean]) => void +>"foo" : "foo" +>10 : 10 +>true : true + +f1("foo", ...tt); +>f1("foo", ...tt) : void +>f1 : (x: string, ...args: [string] | [number, boolean]) => void +>"foo" : "foo" +>...tt : string | number | boolean +>tt : [string] | [number, boolean] + +f1("foo", 10); // Error +>f1("foo", 10) : void +>f1 : (x: string, ...args: [string] | [number, boolean]) => void +>"foo" : "foo" +>10 : 10 + +f1("foo"); // Error +>f1("foo") : void +>f1 : (x: string, ...args: [string] | [number, boolean]) => void +>"foo" : "foo" + +f2 = f1; +>f2 = f1 : (x: string, ...args: [string] | [number, boolean]) => void +>f2 : (x: string, y: string) => void +>f1 : (x: string, ...args: [string] | [number, boolean]) => void + +f3 = f1; +>f3 = f1 : (x: string, ...args: [string] | [number, boolean]) => void +>f3 : (x: string, y: number, z: boolean) => void +>f1 : (x: string, ...args: [string] | [number, boolean]) => void + +f4 = f1; // Error, misaligned complex rest types +>f4 = f1 : (x: string, ...args: [string] | [number, boolean]) => void +>f4 : (...args: [string, string] | [string, number, boolean]) => void +>f1 : (x: string, ...args: [string] | [number, boolean]) => void + +f1 = f2; // Error +>f1 = f2 : (x: string, y: string) => void +>f1 : (x: string, ...args: [string] | [number, boolean]) => void +>f2 : (x: string, y: string) => void + +f1 = f3; // Error +>f1 = f3 : (x: string, y: number, z: boolean) => void +>f1 : (x: string, ...args: [string] | [number, boolean]) => void +>f3 : (x: string, y: number, z: boolean) => void + +f1 = f4; // Error, misaligned complex rest types +>f1 = f4 : (...args: [string, string] | [string, number, boolean]) => void +>f1 : (x: string, ...args: [string] | [number, boolean]) => void +>f4 : (...args: [string, string] | [string, number, boolean]) => void + +// Repro from #26110 + +interface CoolArray extends Array { + hello: number; +>hello : number +} + +declare function foo(cb: (...args: T) => void): void; +>foo : (cb: (...args: T) => void) => void +>cb : (...args: T) => void +>args : T + +foo>(); // Error +>foo>() : any +>foo : (cb: (...args: T) => void) => void + +foo>(100); // Error +>foo>(100) : any +>foo : (cb: (...args: T) => void) => void +>100 : 100 + +foo>(foo); // Error +>foo>(foo) : any +>foo : (cb: (...args: T) => void) => void +>foo : (cb: (...args: T) => void) => void + +function bar(...args: T): T { +>bar : (...args: T) => T +>args : T + + return args; +>args : T +} + +let a = bar(10, 20); +>a : [number, number] +>bar(10, 20) : [number, number] +>bar : (...args: T) => T +>10 : 10 +>20 : 20 + +let b = bar>(10, 20); // Error +>b : any +>bar>(10, 20) : any +>bar : (...args: T) => T +>10 : 10 +>20 : 20 + +declare function baz(...args: CoolArray): void; +>baz : (...args: CoolArray) => void +>args : CoolArray + +declare const ca: CoolArray; +>ca : CoolArray + +baz(); // Error +>baz() : any +>baz : (...args: CoolArray) => void + +baz(1); // Error +>baz(1) : any +>baz : (...args: CoolArray) => void +>1 : 1 + +baz(1, 2); // Error +>baz(1, 2) : any +>baz : (...args: CoolArray) => void +>1 : 1 +>2 : 2 + +baz(...ca); // Error +>baz(...ca) : any +>baz : (...args: CoolArray) => void +>...ca : number +>ca : CoolArray + +// Repro from #26491 + +declare function hmm(...args: A): void; +>hmm : (...args: A) => void +>args : A + +hmm(); // okay, A = [] +>hmm() : void +>hmm : (...args: A) => void + +hmm(1, "s"); // okay, A = [1, "s"] +>hmm(1, "s") : void +>hmm : (...args: A) => void +>1 : 1 +>"s" : "s" + +hmm("what"); // no error? A = [] | [number, string] ? +>hmm("what") : any +>hmm : (...args: A) => void +>"what" : "what" + From 9f4ae5f5eaa48c4ee52caaaae4193a0ad519b5bc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 29 Aug 2018 06:57:21 -0700 Subject: [PATCH 7/7] Fix typo --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 39e1ab5e52..0de2aa1c32 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10725,7 +10725,7 @@ namespace ts { const sourceRestType = getNonArrayRestType(source); const targetRestType = getNonArrayRestType(target); if (sourceRestType && targetRestType && sourceCount !== targetCount) { - // We're not able to relate misaliged complex rest parameters + // We're not able to relate misaligned complex rest parameters return Ternary.False; }