diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bdc844df970..6ebd67e6cfd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9781,7 +9781,7 @@ namespace ts { const restParams = map(elementTypes, (t, i) => { // Lookup the label from the individual tuple passed in before falling back to the signature `rest` parameter name const tupleLabelName = !!associatedNames && getTupleElementLabel(associatedNames[i]); - const name = tupleLabelName || getParameterNameAtPosition(sig, restIndex + i); + const name = tupleLabelName || getParameterNameAtPosition(sig, restIndex + i, restType); const flags = restType.target.elementFlags[i]; const checkFlags = flags & ElementFlags.Variable ? CheckFlags.RestParameter : flags & ElementFlags.Optional ? CheckFlags.OptionalParameter : 0; @@ -27708,13 +27708,13 @@ namespace ts { return d.name.escapedText; } - function getParameterNameAtPosition(signature: Signature, pos: number) { + function getParameterNameAtPosition(signature: Signature, pos: number, overrideRestType?: Type) { const paramCount = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); if (pos < paramCount) { return signature.parameters[pos].escapedName; } const restParameter = signature.parameters[paramCount] || unknownSymbol; - const restType = getTypeOfSymbol(restParameter); + const restType = overrideRestType || getTypeOfSymbol(restParameter); if (isTupleType(restType)) { const associatedNames = ((restType).target).labeledElementDeclarations; const index = pos - paramCount; diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 88ba1fa6508..08ed8709fb0 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -1426,7 +1426,7 @@ namespace FourSlash { this.raiseError("Could not get a help signature"); } - const selectedItem = help.items[help.selectedItemIndex]; + const selectedItem = help.items[options.overrideSelectedItemIndex ?? help.selectedItemIndex]; // Argument index may exceed number of parameters const currentParameter = selectedItem.parameters[help.argumentIndex] as ts.SignatureHelpParameter | undefined; @@ -1478,6 +1478,7 @@ namespace FourSlash { "isVariadic", "tags", "argumentCount", + "overrideSelectedItemIndex" ]; for (const key in options) { if (!ts.contains(allKeys, key)) { diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 3b6b1a9eb2c..876a5bc37b0 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -1533,6 +1533,7 @@ namespace FourSlashInterface { /** @default ts.emptyArray */ readonly tags?: readonly ts.JSDocTagInfo[]; readonly triggerReason?: ts.SignatureHelpTriggerReason; + readonly overrideSelectedItemIndex?: number; } export interface VerifyNavigateToOptions { diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 3efb65d1251..a1f91482309 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -644,6 +644,7 @@ declare namespace FourSlashInterface { isVariadic?: boolean; tags?: ReadonlyArray; triggerReason?: SignatureHelpTriggerReason; + overrideSelectedItemIndex?: number; } export type SignatureHelpTriggerReason = diff --git a/tests/cases/fourslash/signatureHelpExpandedRestUnlabeledTuples.ts b/tests/cases/fourslash/signatureHelpExpandedRestUnlabeledTuples.ts new file mode 100644 index 00000000000..6ddd19f0728 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpExpandedRestUnlabeledTuples.ts @@ -0,0 +1,36 @@ +/// + +////export function complex(item: string, another: string, ...rest: [] | [object, (err: Error) => void] | [(err: Error) => void, ...object[]]) { +//// +////} +//// +////complex(/*1*/); +////complex("ok", "ok", /*2*/); +////complex("ok", "ok", e => void e, {}, /*3*/); + +verify.signatureHelp( + { + marker: "1", + text: "complex(item: string, another: string): void", + overloadsCount: 3, + parameterCount: 2, + parameterName: "item", + parameterSpan: "item: string", + isVariadic: false, + }, + { + marker: "2", + text: "complex(item: string, another: string, rest_0: object, rest_1: (err: Error) => void): void", + overloadsCount: 3, + parameterCount: 4, + parameterName: "rest_0", + parameterSpan: "rest_0: object", + isVariadic: false, + }, + { + marker: "3", + text: "complex(item: string, another: string, rest_0: (err: Error) => void, ...rest_1: object[]): void", + overloadsCount: 3, + isVariadic: true, + }, +); diff --git a/tests/cases/fourslash/signatureHelpExpandedTuplesArgumentIndex.ts b/tests/cases/fourslash/signatureHelpExpandedTuplesArgumentIndex.ts new file mode 100644 index 00000000000..5c97b874c63 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpExpandedTuplesArgumentIndex.ts @@ -0,0 +1,94 @@ +/// + +////function foo(...args: [string, string] | [number, string, string] +////) { +//// +////} +//// +////foo(123/*1*/,) +////foo(""/*2*/, ""/*3*/) +////foo(123/*4*/, ""/*5*/, ) +////foo(123/*6*/, ""/*7*/, ""/*8*/) + +verify.signatureHelp( + { + marker: "1", + text: "foo(args_0: number, args_1: string, args_2: string): void", + overloadsCount: 2, + parameterCount: 3, + parameterName: "args_0", + parameterSpan: "args_0: number", + isVariadic: false, + overrideSelectedItemIndex: 1 + }, + { + marker: "2", + text: "foo(args_0: string, args_1: string): void", + overloadsCount: 2, + parameterCount: 2, + parameterName: "args_0", + parameterSpan: "args_0: string", + isVariadic: false, + overrideSelectedItemIndex: 0 + }, + { + marker: "3", + text: "foo(args_0: string, args_1: string): void", + overloadsCount: 2, + parameterCount: 2, + parameterName: "args_1", + parameterSpan: "args_1: string", + isVariadic: false, + overrideSelectedItemIndex: 0 + }, + { + marker: "4", + text: "foo(args_0: number, args_1: string, args_2: string): void", + overloadsCount: 2, + parameterCount: 3, + parameterName: "args_0", + parameterSpan: "args_0: number", + isVariadic: false, + overrideSelectedItemIndex: 1 + }, + { + marker: "5", + text: "foo(args_0: number, args_1: string, args_2: string): void", + overloadsCount: 2, + parameterCount: 3, + parameterName: "args_1", + parameterSpan: "args_1: string", + isVariadic: false, + overrideSelectedItemIndex: 1 + }, + { + marker: "6", + text: "foo(args_0: number, args_1: string, args_2: string): void", + overloadsCount: 2, + parameterCount: 3, + parameterName: "args_0", + parameterSpan: "args_0: number", + isVariadic: false, + overrideSelectedItemIndex: 1 + }, + { + marker: "7", + text: "foo(args_0: number, args_1: string, args_2: string): void", + overloadsCount: 2, + parameterCount: 3, + parameterName: "args_1", + parameterSpan: "args_1: string", + isVariadic: false, + overrideSelectedItemIndex: 1 + }, + { + marker: "8", + text: "foo(args_0: number, args_1: string, args_2: string): void", + overloadsCount: 2, + parameterCount: 3, + parameterName: "args_2", + parameterSpan: "args_2: string", + isVariadic: false, + overrideSelectedItemIndex: 1 + }, +);