From a0799810b39f77608da6e4a1e0fdcfe293ac77fa Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 22 Sep 2026 19:46:57 -0700 Subject: [PATCH 1/8] Test inlay hints with trailing tuple rest elements --- .../tests/inlayHintsTupleRestTrailing_test.go | 27 ++ .../inlayHintsTupleRestTrailing.baseline | 384 ++++++++++++++++++ 2 files changed, 411 insertions(+) create mode 100644 tsc/internal/fourslash/tests/inlayHintsTupleRestTrailing_test.go create mode 100644 tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline diff --git a/tsc/internal/fourslash/tests/inlayHintsTupleRestTrailing_test.go b/tsc/internal/fourslash/tests/inlayHintsTupleRestTrailing_test.go new file mode 100644 index 0000000000000..100e5bde8f3cf --- /dev/null +++ b/tsc/internal/fourslash/tests/inlayHintsTupleRestTrailing_test.go @@ -0,0 +1,27 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/TypeScript/tsc/internal/fourslash" + "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil" + "github.com/microsoft/TypeScript/tsc/internal/testutil" +) + +func TestInlayHintsTupleRestTrailing(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `declare function fn(prefix: boolean, ...args: [first: number, ...middle: string[], last: string]): void; +fn(true, 1, "a", "b", "end"); +fn(true, 1, "end"); +declare function onlyTrailing(...args: [...head: number[], tail: string]): void; +onlyTrailing(1, 2, "end"); +onlyTrailing("end"); +declare function noTrailing(...args: [first: number, ...rest: string[]]): void; +noTrailing(1, "a", "b"); +declare function skip({ x }: { x: number }, next: number): void; +skip({ x: 1 }, 2);` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) +} diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline new file mode 100644 index 0000000000000..1d5d6227ff776 --- /dev/null +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline @@ -0,0 +1,384 @@ +// === Inlay Hints === +fn(true, 1, "a", "b", "end"); + ^ +{ + "position": { + "line": 1, + "character": 3 + }, + "label": [ + { + "value": "prefix", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 0, + "character": 20 + }, + "end": { + "line": 0, + "character": 26 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +fn(true, 1, "a", "b", "end"); + ^ +{ + "position": { + "line": 1, + "character": 9 + }, + "label": [ + { + "value": "first", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 0, + "character": 47 + }, + "end": { + "line": 0, + "character": 52 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +fn(true, 1, "a", "b", "end"); + ^ +{ + "position": { + "line": 1, + "character": 12 + }, + "label": [ + { + "value": "...middle", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 0, + "character": 65 + }, + "end": { + "line": 0, + "character": 71 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +fn(true, 1, "a", "b", "end"); + ^ +{ + "position": { + "line": 1, + "character": 17 + }, + "label": [ + { + "value": "last", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 0, + "character": 83 + }, + "end": { + "line": 0, + "character": 87 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +fn(true, 1, "end"); + ^ +{ + "position": { + "line": 2, + "character": 3 + }, + "label": [ + { + "value": "prefix", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 0, + "character": 20 + }, + "end": { + "line": 0, + "character": 26 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +fn(true, 1, "end"); + ^ +{ + "position": { + "line": 2, + "character": 9 + }, + "label": [ + { + "value": "first", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 0, + "character": 47 + }, + "end": { + "line": 0, + "character": 52 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +fn(true, 1, "end"); + ^ +{ + "position": { + "line": 2, + "character": 12 + }, + "label": [ + { + "value": "...middle", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 0, + "character": 65 + }, + "end": { + "line": 0, + "character": 71 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +onlyTrailing(1, 2, "end"); + ^ +{ + "position": { + "line": 4, + "character": 13 + }, + "label": [ + { + "value": "...head", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 3, + "character": 43 + }, + "end": { + "line": 3, + "character": 47 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +onlyTrailing(1, 2, "end"); + ^ +{ + "position": { + "line": 4, + "character": 16 + }, + "label": [ + { + "value": "tail", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 3, + "character": 59 + }, + "end": { + "line": 3, + "character": 63 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +onlyTrailing("end"); + ^ +{ + "position": { + "line": 5, + "character": 13 + }, + "label": [ + { + "value": "...head", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 3, + "character": 43 + }, + "end": { + "line": 3, + "character": 47 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +noTrailing(1, "a", "b"); + ^ +{ + "position": { + "line": 7, + "character": 11 + }, + "label": [ + { + "value": "first", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 6, + "character": 38 + }, + "end": { + "line": 6, + "character": 43 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +noTrailing(1, "a", "b"); + ^ +{ + "position": { + "line": 7, + "character": 14 + }, + "label": [ + { + "value": "...rest", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 6, + "character": 56 + }, + "end": { + "line": 6, + "character": 60 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} \ No newline at end of file From 755ff350e29c369f299e66bd23a39b32c8bed882 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 22 Sep 2026 19:49:49 -0700 Subject: [PATCH 2/8] Align inlay hints with trailing tuple arguments Trailing fixed tuple elements correspond to the last arguments, not the first positions after a rest element. Without aligning from the end, inlay hints point to the wrong parameter and can hide names of later parameters. --- tsc/internal/checker/exports.go | 4 ++ tsc/internal/ls/inlay_hints.go | 51 ++++++++++-------- tsc/internal/ls/signaturehelp.go | 22 ++++---- .../inlayHintsTupleRestTrailing.baseline | 52 +++++++++++++++---- 4 files changed, 85 insertions(+), 44 deletions(-) diff --git a/tsc/internal/checker/exports.go b/tsc/internal/checker/exports.go index c22901a84d2ab..919cb99de74fc 100644 --- a/tsc/internal/checker/exports.go +++ b/tsc/internal/checker/exports.go @@ -220,6 +220,10 @@ func IsTupleType(t *Type) bool { return isTupleType(t) } +func GetEndElementCount(t *TupleType, flags ElementFlags) int { + return getEndElementCount(t, flags) +} + func IsTupleTypeTarget(t *Type) bool { return isTupleType(t) && t.Target() == t } diff --git a/tsc/internal/ls/inlay_hints.go b/tsc/internal/ls/inlay_hints.go index 0864f8df361e7..26cca67840914 100644 --- a/tsc/internal/ls/inlay_hints.go +++ b/tsc/internal/ls/inlay_hints.go @@ -2,7 +2,6 @@ package ls import ( "context" - "slices" "strings" "unicode" @@ -157,6 +156,14 @@ func (s *inlayHintState) visitCallOrNewExpression(expr *ast.CallOrNewExpression) return } + // A spread prevents matching trailing tuple elements from the end of the argument list. + argumentCount := len(args) + for _, arg := range args { + if ast.IsSpreadElement(ast.SkipParentheses(arg)) { + argumentCount = -1 + break + } + } signatureParamPos := 0 for _, originalArg := range args { arg := ast.SkipParentheses(originalArg) @@ -169,25 +176,18 @@ func (s *inlayHintState) visitCallOrNewExpression(expr *ast.CallOrNewExpression) if ast.IsSpreadElement(arg) { spreadType := s.checker.GetTypeAtLocation(arg.Expression()) if spreadType.IsTupleType() { - elementFlags := spreadType.Target().AsTupleType().ElementFlags() - fixedLength := spreadType.Target().AsTupleType().FixedLength() - if fixedLength == 0 { + tupleType := spreadType.Target().AsTupleType() + if tupleType.FixedLength() == 0 { continue } - firstOptionalIndex := slices.IndexFunc(elementFlags, func(f checker.ElementFlags) bool { - return f&checker.ElementFlagsRequired == 0 - }) - requiredArgs := core.IfElse(firstOptionalIndex < 0, fixedLength, firstOptionalIndex) - if requiredArgs > 0 { - spreadArgs = requiredArgs - } + spreadArgs = getRequiredTupleElementCount(tupleType) } } - identifierInfo := s.getParameterIdentifierInfoAtPosition(signature, signatureParamPos) + identifierInfo := s.getParameterIdentifierInfoAtPosition(signature, signatureParamPos, argumentCount) signatureParamPos = signatureParamPos + core.IfElse(spreadArgs > 0, spreadArgs, 1) if identifierInfo == nil { - return + continue } parameter := identifierInfo.parameter @@ -831,7 +831,7 @@ type parameterInfo struct { isRestParameter bool } -func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker.Signature, pos int) *parameterInfo { +func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker.Signature, pos int, argumentCount int) *parameterInfo { parameters := signature.Parameters() paramCount := len(parameters) - core.IfElse(signature.HasRestParameter(), 1, 0) if pos < paramCount { @@ -859,14 +859,23 @@ func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker restType := s.checker.GetTypeOfSymbol(restParameter) if restType.IsTupleType() { - associatedNames := make([]*ast.Node, 0, len(restType.Target().AsTupleType().ElementInfos())) - for _, elementInfo := range restType.Target().AsTupleType().ElementInfos() { - labeledElement := elementInfo.LabeledDeclaration() - associatedNames = append(associatedNames, labeledElement) - } + tupleType := restType.Target().AsTupleType() + elementInfos := tupleType.ElementInfos() index := pos - paramCount - if index < len(associatedNames) { - associatedName := associatedNames[index] + restArgumentCount := argumentCount - paramCount + firstVariableIndex := tupleType.FixedLength() + trailingCount := checker.GetEndElementCount(tupleType, checker.ElementFlagsFixed) + if argumentCount >= 0 && trailingCount > 0 && firstVariableIndex+trailingCount+1 == len(elementInfos) && restArgumentCount >= firstVariableIndex+trailingCount { + trailingStart := restArgumentCount - trailingCount + switch { + case index >= trailingStart: + index = len(elementInfos) - (restArgumentCount - index) + case index > firstVariableIndex: + return nil + } + } + if index < len(elementInfos) { + associatedName := elementInfos[index].LabeledDeclaration() if associatedName != nil { debug.Assert(ast.IsIdentifier(associatedName.Name())) var isRestTupleElement bool diff --git a/tsc/internal/ls/signaturehelp.go b/tsc/internal/ls/signaturehelp.go index 78aa78490d4b8..19c9c87d3c273 100644 --- a/tsc/internal/ls/signaturehelp.go +++ b/tsc/internal/ls/signaturehelp.go @@ -1078,23 +1078,19 @@ func getSpreadElementCount(node *ast.SpreadElement, c *checker.Checker) int { if tupleType == nil { return 0 } - elementFlags := tupleType.ElementFlags() - fixedLength := tupleType.FixedLength() - if fixedLength == 0 { - return 0 - } - - firstOptionalIndex := core.FindIndex(elementFlags, func(f checker.ElementFlags) bool { - return (f&checker.ElementFlagsRequired == 0) - }) - if firstOptionalIndex < 0 { - return fixedLength - } - return firstOptionalIndex + return getRequiredTupleElementCount(tupleType) } return 0 } +func getRequiredTupleElementCount(tupleType *checker.TupleType) int { + fixedLength := tupleType.FixedLength() + firstOptionalIndex := core.FindIndex(tupleType.ElementInfos()[:fixedLength], func(info checker.TupleElementInfo) bool { + return info.TupleElementFlags()&checker.ElementFlagsRequired == 0 + }) + return core.IfElse(firstOptionalIndex < 0, fixedLength, firstOptionalIndex) +} + func getArgumentIndex(node *ast.Node, arguments *ast.NodeList, sourceFile *ast.SourceFile, c *checker.Checker) int { return getArgumentIndexOrCount(getTokenFromNodeList(arguments, node.Parent, sourceFile), node, c) } diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline index 1d5d6227ff776..eaf3cd8af0f4f 100644 --- a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline @@ -96,11 +96,11 @@ fn(true, 1, "a", "b", "end"); } fn(true, 1, "a", "b", "end"); - ^ + ^ { "position": { "line": 1, - "character": 17 + "character": 22 }, "label": [ { @@ -200,17 +200,17 @@ fn(true, 1, "end"); }, "label": [ { - "value": "...middle", + "value": "last", "location": { "uri": "file:///inlayHintsTupleRestTrailing.ts", "range": { "start": { "line": 0, - "character": 65 + "character": 83 }, "end": { "line": 0, - "character": 71 + "character": 87 } } } @@ -256,11 +256,11 @@ onlyTrailing(1, 2, "end"); } onlyTrailing(1, 2, "end"); - ^ + ^ { "position": { "line": 4, - "character": 16 + "character": 19 }, "label": [ { @@ -296,17 +296,17 @@ onlyTrailing("end"); }, "label": [ { - "value": "...head", + "value": "tail", "location": { "uri": "file:///inlayHintsTupleRestTrailing.ts", "range": { "start": { "line": 3, - "character": 43 + "character": 59 }, "end": { "line": 3, - "character": 47 + "character": 63 } } } @@ -381,4 +381,36 @@ noTrailing(1, "a", "b"); ], "kind": 2, "paddingRight": true +} + +skip({ x: 1 }, 2); + ^ +{ + "position": { + "line": 9, + "character": 15 + }, + "label": [ + { + "value": "next", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 8, + "character": 44 + }, + "end": { + "line": 8, + "character": 48 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true } \ No newline at end of file From 96b101abae563470ef850941832c33c04ad49dc3 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 23 Sep 2026 11:42:14 -0700 Subject: [PATCH 3/8] Test inlay hints with multiple variadic tuple elements --- .../tests/inlayHintsTupleRestTrailing_test.go | 5 + .../inlayHintsTupleRestTrailing.baseline | 102 +++++++++++++++++- 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/tsc/internal/fourslash/tests/inlayHintsTupleRestTrailing_test.go b/tsc/internal/fourslash/tests/inlayHintsTupleRestTrailing_test.go index 100e5bde8f3cf..e7e4f0887dc1f 100644 --- a/tsc/internal/fourslash/tests/inlayHintsTupleRestTrailing_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsTupleRestTrailing_test.go @@ -19,9 +19,14 @@ onlyTrailing(1, 2, "end"); onlyTrailing("end"); declare function noTrailing(...args: [first: number, ...rest: string[]]): void; noTrailing(1, "a", "b"); +declare function multi(...args: [first: number, ...left: T, ...right: U, penultimate: string, last: boolean]): void; +function combined(middle: [...T, ...U]) { + multi(1, ...middle, "end", true); +} declare function skip({ x }: { x: number }, next: number): void; skip({ x: 1 }, 2);` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() + f.VerifyNoErrors(t) f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) } diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline index eaf3cd8af0f4f..dabd688daa0b9 100644 --- a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline @@ -383,11 +383,107 @@ noTrailing(1, "a", "b"); "paddingRight": true } + multi(1, ...middle, "end", true); + ^ +{ + "position": { + "line": 10, + "character": 16 + }, + "label": [ + { + "value": "first", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 8, + "character": 73 + }, + "end": { + "line": 8, + "character": 78 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + + multi(1, ...middle, "end", true); + ^ +{ + "position": { + "line": 10, + "character": 30 + }, + "label": [ + { + "value": "...left", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 8, + "character": 91 + }, + "end": { + "line": 8, + "character": 95 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + + multi(1, ...middle, "end", true); + ^ +{ + "position": { + "line": 10, + "character": 37 + }, + "label": [ + { + "value": "...right", + "location": { + "uri": "file:///inlayHintsTupleRestTrailing.ts", + "range": { + "start": { + "line": 8, + "character": 103 + }, + "end": { + "line": 8, + "character": 108 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + skip({ x: 1 }, 2); ^ { "position": { - "line": 9, + "line": 13, "character": 15 }, "label": [ @@ -397,11 +493,11 @@ skip({ x: 1 }, 2); "uri": "file:///inlayHintsTupleRestTrailing.ts", "range": { "start": { - "line": 8, + "line": 12, "character": 44 }, "end": { - "line": 8, + "line": 12, "character": 48 } } From edf2f7bd3192791cb097d1dad20d5fab8adf1ef1 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 23 Sep 2026 11:45:03 -0700 Subject: [PATCH 4/8] Align trailing tuple hints after generic spreads A spread can leave the effective argument count unknown even when explicit arguments follow it. Those trailing arguments still have known positions from the end of the call. --- tsc/internal/ls/inlay_hints.go | 36 +++++++++++++------ .../inlayHintsTupleRestTrailing.baseline | 12 +++---- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/tsc/internal/ls/inlay_hints.go b/tsc/internal/ls/inlay_hints.go index 26cca67840914..c0c9ab32eee4e 100644 --- a/tsc/internal/ls/inlay_hints.go +++ b/tsc/internal/ls/inlay_hints.go @@ -156,16 +156,18 @@ func (s *inlayHintState) visitCallOrNewExpression(expr *ast.CallOrNewExpression) return } - // A spread prevents matching trailing tuple elements from the end of the argument list. + // A spread makes the effective argument count unknown, but explicit arguments after the last + // spread still have a known offset from the end. argumentCount := len(args) - for _, arg := range args { + lastSpreadIndex := -1 + for i, arg := range args { if ast.IsSpreadElement(ast.SkipParentheses(arg)) { argumentCount = -1 - break + lastSpreadIndex = i } } signatureParamPos := 0 - for _, originalArg := range args { + for i, originalArg := range args { arg := ast.SkipParentheses(originalArg) if shouldShowLiteralParameterNameHintsOnly(s.preferences) && !isHintableLiteral(arg) { signatureParamPos++ @@ -184,7 +186,11 @@ func (s *inlayHintState) visitCallOrNewExpression(expr *ast.CallOrNewExpression) } } - identifierInfo := s.getParameterIdentifierInfoAtPosition(signature, signatureParamPos, argumentCount) + offsetFromEnd := -1 + if lastSpreadIndex >= 0 && i > lastSpreadIndex { + offsetFromEnd = len(args) - i + } + identifierInfo := s.getParameterIdentifierInfoAtPosition(signature, signatureParamPos, argumentCount, offsetFromEnd) signatureParamPos = signatureParamPos + core.IfElse(spreadArgs > 0, spreadArgs, 1) if identifierInfo == nil { continue @@ -831,7 +837,7 @@ type parameterInfo struct { isRestParameter bool } -func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker.Signature, pos int, argumentCount int) *parameterInfo { +func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker.Signature, pos int, argumentCount int, offsetFromEnd int) *parameterInfo { parameters := signature.Parameters() paramCount := len(parameters) - core.IfElse(signature.HasRestParameter(), 1, 0) if pos < paramCount { @@ -865,13 +871,21 @@ func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker restArgumentCount := argumentCount - paramCount firstVariableIndex := tupleType.FixedLength() trailingCount := checker.GetEndElementCount(tupleType, checker.ElementFlagsFixed) - if argumentCount >= 0 && trailingCount > 0 && firstVariableIndex+trailingCount+1 == len(elementInfos) && restArgumentCount >= firstVariableIndex+trailingCount { - trailingStart := restArgumentCount - trailingCount + variableCount := len(elementInfos) - firstVariableIndex - trailingCount + if trailingCount > 0 && variableCount > 0 { switch { - case index >= trailingStart: - index = len(elementInfos) - (restArgumentCount - index) - case index > firstVariableIndex: + case offsetFromEnd > 0 && offsetFromEnd <= trailingCount: + index = len(elementInfos) - offsetFromEnd + case offsetFromEnd > trailingCount && variableCount > 1: return nil + case argumentCount >= 0 && restArgumentCount >= firstVariableIndex+trailingCount: + trailingStart := restArgumentCount - trailingCount + switch { + case index >= trailingStart: + index = len(elementInfos) - (restArgumentCount - index) + case index >= firstVariableIndex && (variableCount > 1 || index > firstVariableIndex): + return nil + } } } if index < len(elementInfos) { diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline index dabd688daa0b9..25c0274b2ca58 100644 --- a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsTupleRestTrailing.baseline @@ -424,17 +424,17 @@ noTrailing(1, "a", "b"); }, "label": [ { - "value": "...left", + "value": "penultimate", "location": { "uri": "file:///inlayHintsTupleRestTrailing.ts", "range": { "start": { "line": 8, - "character": 91 + "character": 113 }, "end": { "line": 8, - "character": 95 + "character": 124 } } } @@ -456,17 +456,17 @@ noTrailing(1, "a", "b"); }, "label": [ { - "value": "...right", + "value": "last", "location": { "uri": "file:///inlayHintsTupleRestTrailing.ts", "range": { "start": { "line": 8, - "character": 103 + "character": 134 }, "end": { "line": 8, - "character": 108 + "character": 138 } } } From 6bc1039ff969f1e8be4966ca1ffacf3d2568262a Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 23 Sep 2026 14:10:45 -0700 Subject: [PATCH 5/8] Test trailing tuple hints after spreads --- ...ayHintsRestTrailingSpreadEdgeCases_test.go | 35 ++++ ...sOptionalTrailingTupleAfterSpread.baseline | 160 ++++++++++++++++++ ...intsSingleRestWithSpreadAndSuffix.baseline | 96 +++++++++++ 3 files changed, 291 insertions(+) create mode 100644 tsc/internal/fourslash/tests/inlayHintsRestTrailingSpreadEdgeCases_test.go create mode 100644 tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingTupleAfterSpread.baseline create mode 100644 tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsSingleRestWithSpreadAndSuffix.baseline diff --git a/tsc/internal/fourslash/tests/inlayHintsRestTrailingSpreadEdgeCases_test.go b/tsc/internal/fourslash/tests/inlayHintsRestTrailingSpreadEdgeCases_test.go new file mode 100644 index 0000000000000..7fdf15e3e501f --- /dev/null +++ b/tsc/internal/fourslash/tests/inlayHintsRestTrailingSpreadEdgeCases_test.go @@ -0,0 +1,35 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/TypeScript/tsc/internal/fourslash" + "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil" + "github.com/microsoft/TypeScript/tsc/internal/testutil" +) + +func TestInlayHintsOptionalTrailingTupleAfterSpread(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `declare function optional(...args: [...head: T, first?: number, second?: string]): void; +function forward(x: T) { + optional(...x, 1); + optional(...x, 1, "two"); +}` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyNoErrors(t) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) +} + +func TestInlayHintsSingleRestWithSpreadAndSuffix(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `declare function f(...args: [...head: string[], tail: string]): void; +declare const xs: string[]; +f(...xs, "middle", "end");` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyNoErrors(t) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) +} diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingTupleAfterSpread.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingTupleAfterSpread.baseline new file mode 100644 index 0000000000000..a85236acf0c8c --- /dev/null +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingTupleAfterSpread.baseline @@ -0,0 +1,160 @@ +// === Inlay Hints === + optional(...x, 1); + ^ +{ + "position": { + "line": 2, + "character": 16 + }, + "label": [ + { + "value": "...head", + "location": { + "uri": "file:///inlayHintsOptionalTrailingTupleAfterSpread.ts", + "range": { + "start": { + "line": 0, + "character": 60 + }, + "end": { + "line": 0, + "character": 64 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + + optional(...x, 1); + ^ +{ + "position": { + "line": 2, + "character": 22 + }, + "label": [ + { + "value": "second", + "location": { + "uri": "file:///inlayHintsOptionalTrailingTupleAfterSpread.ts", + "range": { + "start": { + "line": 0, + "character": 85 + }, + "end": { + "line": 0, + "character": 91 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + + optional(...x, 1, "two"); + ^ +{ + "position": { + "line": 3, + "character": 16 + }, + "label": [ + { + "value": "...head", + "location": { + "uri": "file:///inlayHintsOptionalTrailingTupleAfterSpread.ts", + "range": { + "start": { + "line": 0, + "character": 60 + }, + "end": { + "line": 0, + "character": 64 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + + optional(...x, 1, "two"); + ^ +{ + "position": { + "line": 3, + "character": 22 + }, + "label": [ + { + "value": "first", + "location": { + "uri": "file:///inlayHintsOptionalTrailingTupleAfterSpread.ts", + "range": { + "start": { + "line": 0, + "character": 69 + }, + "end": { + "line": 0, + "character": 74 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + + optional(...x, 1, "two"); + ^ +{ + "position": { + "line": 3, + "character": 25 + }, + "label": [ + { + "value": "second", + "location": { + "uri": "file:///inlayHintsOptionalTrailingTupleAfterSpread.ts", + "range": { + "start": { + "line": 0, + "character": 85 + }, + "end": { + "line": 0, + "character": 91 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsSingleRestWithSpreadAndSuffix.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsSingleRestWithSpreadAndSuffix.baseline new file mode 100644 index 0000000000000..f737df406ea9c --- /dev/null +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsSingleRestWithSpreadAndSuffix.baseline @@ -0,0 +1,96 @@ +// === Inlay Hints === +f(...xs, "middle", "end"); + ^ +{ + "position": { + "line": 2, + "character": 2 + }, + "label": [ + { + "value": "...head", + "location": { + "uri": "file:///inlayHintsSingleRestWithSpreadAndSuffix.ts", + "range": { + "start": { + "line": 0, + "character": 32 + }, + "end": { + "line": 0, + "character": 36 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +f(...xs, "middle", "end"); + ^ +{ + "position": { + "line": 2, + "character": 9 + }, + "label": [ + { + "value": "tail", + "location": { + "uri": "file:///inlayHintsSingleRestWithSpreadAndSuffix.ts", + "range": { + "start": { + "line": 0, + "character": 48 + }, + "end": { + "line": 0, + "character": 52 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +f(...xs, "middle", "end"); + ^ +{ + "position": { + "line": 2, + "character": 19 + }, + "label": [ + { + "value": "tail", + "location": { + "uri": "file:///inlayHintsSingleRestWithSpreadAndSuffix.ts", + "range": { + "start": { + "line": 0, + "character": 48 + }, + "end": { + "line": 0, + "character": 52 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} \ No newline at end of file From 02b185fe99c6361912fd51a543326afeba01b0b9 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 23 Sep 2026 14:17:00 -0700 Subject: [PATCH 6/8] Avoid incorrect trailing tuple hints after spreads Optional tuple elements may be omitted, so their names cannot always be inferred from the end of a call. An argument before a known trailing suffix must not be labeled as that suffix either. --- tsc/internal/ls/inlay_hints.go | 6 ++-- ...sOptionalTrailingTupleAfterSpread.baseline | 6 ++-- ...intsSingleRestWithSpreadAndSuffix.baseline | 32 ------------------- 3 files changed, 7 insertions(+), 37 deletions(-) diff --git a/tsc/internal/ls/inlay_hints.go b/tsc/internal/ls/inlay_hints.go index c0c9ab32eee4e..781b299e93eaa 100644 --- a/tsc/internal/ls/inlay_hints.go +++ b/tsc/internal/ls/inlay_hints.go @@ -871,12 +871,14 @@ func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker restArgumentCount := argumentCount - paramCount firstVariableIndex := tupleType.FixedLength() trailingCount := checker.GetEndElementCount(tupleType, checker.ElementFlagsFixed) + // Optional trailing elements may be omitted, so only required ones can be aligned from the end. + requiredTrailingCount := checker.GetEndElementCount(tupleType, checker.ElementFlagsRequired) variableCount := len(elementInfos) - firstVariableIndex - trailingCount if trailingCount > 0 && variableCount > 0 { switch { - case offsetFromEnd > 0 && offsetFromEnd <= trailingCount: + case offsetFromEnd > 0 && offsetFromEnd <= requiredTrailingCount: index = len(elementInfos) - offsetFromEnd - case offsetFromEnd > trailingCount && variableCount > 1: + case offsetFromEnd > trailingCount: return nil case argumentCount >= 0 && restArgumentCount >= firstVariableIndex+trailingCount: trailingStart := restArgumentCount - trailingCount diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingTupleAfterSpread.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingTupleAfterSpread.baseline index a85236acf0c8c..b812b30a245d3 100644 --- a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingTupleAfterSpread.baseline +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingTupleAfterSpread.baseline @@ -40,17 +40,17 @@ }, "label": [ { - "value": "second", + "value": "first", "location": { "uri": "file:///inlayHintsOptionalTrailingTupleAfterSpread.ts", "range": { "start": { "line": 0, - "character": 85 + "character": 69 }, "end": { "line": 0, - "character": 91 + "character": 74 } } } diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsSingleRestWithSpreadAndSuffix.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsSingleRestWithSpreadAndSuffix.baseline index f737df406ea9c..e70c044f810d4 100644 --- a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsSingleRestWithSpreadAndSuffix.baseline +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsSingleRestWithSpreadAndSuffix.baseline @@ -31,38 +31,6 @@ f(...xs, "middle", "end"); "paddingRight": true } -f(...xs, "middle", "end"); - ^ -{ - "position": { - "line": 2, - "character": 9 - }, - "label": [ - { - "value": "tail", - "location": { - "uri": "file:///inlayHintsSingleRestWithSpreadAndSuffix.ts", - "range": { - "start": { - "line": 0, - "character": 48 - }, - "end": { - "line": 0, - "character": 52 - } - } - } - }, - { - "value": ":" - } - ], - "kind": 2, - "paddingRight": true -} - f(...xs, "middle", "end"); ^ { From 3f6f1b8dec587ea3e20f1657e889eb667fb98de2 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 23 Sep 2026 15:12:06 -0700 Subject: [PATCH 7/8] Test ambiguous tuple spread parameter hints --- ...ayHintsRestTrailingSpreadEdgeCases_test.go | 25 ++++++++ ...OptionalParameterAfterTupleSpread.baseline | 64 +++++++++++++++++++ ...sOptionalTrailingAfterTupleSpread.baseline | 32 ++++++++++ 3 files changed, 121 insertions(+) create mode 100644 tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalParameterAfterTupleSpread.baseline create mode 100644 tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingAfterTupleSpread.baseline diff --git a/tsc/internal/fourslash/tests/inlayHintsRestTrailingSpreadEdgeCases_test.go b/tsc/internal/fourslash/tests/inlayHintsRestTrailingSpreadEdgeCases_test.go index 7fdf15e3e501f..438834cf70f37 100644 --- a/tsc/internal/fourslash/tests/inlayHintsRestTrailingSpreadEdgeCases_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsRestTrailingSpreadEdgeCases_test.go @@ -33,3 +33,28 @@ f(...xs, "middle", "end");` f.VerifyNoErrors(t) f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) } + +func TestInlayHintsOptionalTrailingAfterTupleSpread(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `declare function optional(...args: [...head: T, first?: number, second?: string]): void; +function forward(x: [...T]) { + optional(...x, 1); +}` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyNoErrors(t) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) +} + +func TestInlayHintsOptionalParameterAfterTupleSpread(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `declare function g(a: number, b?: number, ...rest: string[]): void; +declare const x: [number, number?]; +g(...x, "end");` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyNoErrors(t) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) +} diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalParameterAfterTupleSpread.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalParameterAfterTupleSpread.baseline new file mode 100644 index 0000000000000..f8c015a790fde --- /dev/null +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalParameterAfterTupleSpread.baseline @@ -0,0 +1,64 @@ +// === Inlay Hints === +g(...x, "end"); + ^ +{ + "position": { + "line": 2, + "character": 2 + }, + "label": [ + { + "value": "a", + "location": { + "uri": "file:///inlayHintsOptionalParameterAfterTupleSpread.ts", + "range": { + "start": { + "line": 0, + "character": 19 + }, + "end": { + "line": 0, + "character": 20 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +g(...x, "end"); + ^ +{ + "position": { + "line": 2, + "character": 8 + }, + "label": [ + { + "value": "b", + "location": { + "uri": "file:///inlayHintsOptionalParameterAfterTupleSpread.ts", + "range": { + "start": { + "line": 0, + "character": 30 + }, + "end": { + "line": 0, + "character": 31 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingAfterTupleSpread.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingAfterTupleSpread.baseline new file mode 100644 index 0000000000000..e3d2a6037b9c3 --- /dev/null +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingAfterTupleSpread.baseline @@ -0,0 +1,32 @@ +// === Inlay Hints === + optional(...x, 1); + ^ +{ + "position": { + "line": 2, + "character": 22 + }, + "label": [ + { + "value": "...head", + "location": { + "uri": "file:///inlayHintsOptionalTrailingAfterTupleSpread.ts", + "range": { + "start": { + "line": 0, + "character": 60 + }, + "end": { + "line": 0, + "character": 64 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} \ No newline at end of file From c6ca73cd7341b425796a06682b2c127c65deb866 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 23 Sep 2026 15:19:42 -0700 Subject: [PATCH 8/8] Omit uncertain hints after tuple spreads Optional and variable tuple elements make the next parameter position uncertain. Keep hints for positions known from the end of a required tuple suffix, but omit names that could refer to a different argument. --- tsc/internal/ls/inlay_hints.go | 33 +++++++++++++------ ...ayHintsInteractiveRestParameters2.baseline | 32 ------------------ ...OptionalParameterAfterTupleSpread.baseline | 32 ------------------ ...sOptionalTrailingAfterTupleSpread.baseline | 32 +----------------- .../inlayHintsRestParameters2.baseline | 32 ------------------ 5 files changed, 24 insertions(+), 137 deletions(-) diff --git a/tsc/internal/ls/inlay_hints.go b/tsc/internal/ls/inlay_hints.go index 781b299e93eaa..92e065c086fba 100644 --- a/tsc/internal/ls/inlay_hints.go +++ b/tsc/internal/ls/inlay_hints.go @@ -167,30 +167,34 @@ func (s *inlayHintState) visitCallOrNewExpression(expr *ast.CallOrNewExpression) } } signatureParamPos := 0 + hasUncertainTupleSpread := false for i, originalArg := range args { arg := ast.SkipParentheses(originalArg) - if shouldShowLiteralParameterNameHintsOnly(s.preferences) && !isHintableLiteral(arg) { - signatureParamPos++ - continue - } - spreadArgs := 0 + skipSpreadHint := false if ast.IsSpreadElement(arg) { spreadType := s.checker.GetTypeAtLocation(arg.Expression()) if spreadType.IsTupleType() { tupleType := spreadType.Target().AsTupleType() - if tupleType.FixedLength() == 0 { - continue - } spreadArgs = getRequiredTupleElementCount(tupleType) + // Optional or variable tuple elements make subsequent positional hints ambiguous. + hasUncertainTupleSpread = hasUncertainTupleSpread || spreadArgs < len(tupleType.ElementInfos()) + skipSpreadHint = tupleType.FixedLength() == 0 } } + if shouldShowLiteralParameterNameHintsOnly(s.preferences) && !isHintableLiteral(arg) { + signatureParamPos++ + continue + } + if skipSpreadHint { + continue + } offsetFromEnd := -1 if lastSpreadIndex >= 0 && i > lastSpreadIndex { offsetFromEnd = len(args) - i } - identifierInfo := s.getParameterIdentifierInfoAtPosition(signature, signatureParamPos, argumentCount, offsetFromEnd) + identifierInfo := s.getParameterIdentifierInfoAtPosition(signature, signatureParamPos, argumentCount, offsetFromEnd, hasUncertainTupleSpread && !ast.IsSpreadElement(arg)) signatureParamPos = signatureParamPos + core.IfElse(spreadArgs > 0, spreadArgs, 1) if identifierInfo == nil { continue @@ -837,10 +841,13 @@ type parameterInfo struct { isRestParameter bool } -func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker.Signature, pos int, argumentCount int, offsetFromEnd int) *parameterInfo { +func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker.Signature, pos int, argumentCount int, offsetFromEnd int, uncertainTupleSpread bool) *parameterInfo { parameters := signature.Parameters() paramCount := len(parameters) - core.IfElse(signature.HasRestParameter(), 1, 0) if pos < paramCount { + if uncertainTupleSpread { + return nil + } param := parameters[pos] paramId := getParameterDeclarationIdentifier(param) if paramId == nil { @@ -873,6 +880,9 @@ func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker trailingCount := checker.GetEndElementCount(tupleType, checker.ElementFlagsFixed) // Optional trailing elements may be omitted, so only required ones can be aligned from the end. requiredTrailingCount := checker.GetEndElementCount(tupleType, checker.ElementFlagsRequired) + if uncertainTupleSpread && (offsetFromEnd <= 0 || offsetFromEnd > requiredTrailingCount) { + return nil + } variableCount := len(elementInfos) - firstVariableIndex - trailingCount if trailingCount > 0 && variableCount > 0 { switch { @@ -911,6 +921,9 @@ func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker return nil } + if uncertainTupleSpread { + return nil + } if pos == paramCount { return ¶meterInfo{ parameter: restId, diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsInteractiveRestParameters2.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsInteractiveRestParameters2.baseline index f7f00df072f35..d1e67912a4693 100644 --- a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsInteractiveRestParameters2.baseline +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsInteractiveRestParameters2.baseline @@ -255,38 +255,6 @@ "paddingRight": true } - foo(...x, 3); - ^ -{ - "position": { - "line": 11, - "character": 14 - }, - "label": [ - { - "value": "b", - "location": { - "uri": "file:///inlayHintsInteractiveRestParameters2.ts", - "range": { - "start": { - "line": 0, - "character": 25 - }, - "end": { - "line": 0, - "character": 26 - } - } - } - }, - { - "value": ":" - } - ], - "kind": 2, - "paddingRight": true -} - foo(...x, 3); ^ { diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalParameterAfterTupleSpread.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalParameterAfterTupleSpread.baseline index f8c015a790fde..d8b46d917f841 100644 --- a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalParameterAfterTupleSpread.baseline +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalParameterAfterTupleSpread.baseline @@ -29,36 +29,4 @@ g(...x, "end"); ], "kind": 2, "paddingRight": true -} - -g(...x, "end"); - ^ -{ - "position": { - "line": 2, - "character": 8 - }, - "label": [ - { - "value": "b", - "location": { - "uri": "file:///inlayHintsOptionalParameterAfterTupleSpread.ts", - "range": { - "start": { - "line": 0, - "character": 30 - }, - "end": { - "line": 0, - "character": 31 - } - } - } - }, - { - "value": ":" - } - ], - "kind": 2, - "paddingRight": true } \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingAfterTupleSpread.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingAfterTupleSpread.baseline index e3d2a6037b9c3..1d8aa81fc427b 100644 --- a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingAfterTupleSpread.baseline +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsOptionalTrailingAfterTupleSpread.baseline @@ -1,32 +1,2 @@ // === Inlay Hints === - optional(...x, 1); - ^ -{ - "position": { - "line": 2, - "character": 22 - }, - "label": [ - { - "value": "...head", - "location": { - "uri": "file:///inlayHintsOptionalTrailingAfterTupleSpread.ts", - "range": { - "start": { - "line": 0, - "character": 60 - }, - "end": { - "line": 0, - "character": 64 - } - } - } - }, - { - "value": ":" - } - ], - "kind": 2, - "paddingRight": true -} \ No newline at end of file +=== No inlay hints === \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsRestParameters2.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsRestParameters2.baseline index 8fe8f3267f525..8ca414ac75cd9 100644 --- a/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsRestParameters2.baseline +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/inlayHintsRestParameters2.baseline @@ -255,38 +255,6 @@ "paddingRight": true } - foo(...x, 3); - ^ -{ - "position": { - "line": 11, - "character": 14 - }, - "label": [ - { - "value": "b", - "location": { - "uri": "file:///inlayHintsRestParameters2.ts", - "range": { - "start": { - "line": 0, - "character": 25 - }, - "end": { - "line": 0, - "character": 26 - } - } - } - }, - { - "value": ":" - } - ], - "kind": 2, - "paddingRight": true -} - foo(...x, 3); ^ {