Skip to content

Commit cc8d392

Browse files
committed
Add tests and code for preserving tuple names through spreads where possible
1 parent fcb324d commit cc8d392

File tree

8 files changed

+95
-5
lines changed

8 files changed

+95
-5
lines changed

src/compiler/checker.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25168,19 +25168,23 @@ namespace ts {
2516825168
}
2516925169
}
2517025170
const types = [];
25171+
const names: (ParameterDeclaration | NamedTupleMember)[] = [];
2517125172
let spreadIndex = -1;
2517225173
for (let i = index; i < argCount; i++) {
2517325174
const contextualType = getIndexedAccessType(restType, getLiteralType(i - index));
2517425175
const argType = checkExpressionWithContextualType(args[i], contextualType, context, CheckMode.Normal);
2517525176
if (spreadIndex < 0 && isSpreadArgument(args[i])) {
2517625177
spreadIndex = i - index;
2517725178
}
25179+
if (args[i].kind === SyntaxKind.SyntheticExpression && (args[i] as SyntheticExpression).tupleNameSource) {
25180+
names.push((args[i] as SyntheticExpression).tupleNameSource!);
25181+
}
2517825182
const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index);
2517925183
types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType));
2518025184
}
2518125185
return spreadIndex < 0 ?
25182-
createTupleType(types) :
25183-
createTupleType(append(types.slice(0, spreadIndex), getUnionType(types.slice(spreadIndex))), spreadIndex, /*hasRestElement*/ true);
25186+
createTupleType(types, /*minLength*/ undefined, /*hasRestElement*/ undefined, /*readonly*/ undefined, length(names) === length(types) ? names : undefined) :
25187+
createTupleType(append(types.slice(0, spreadIndex), getUnionType(types.slice(spreadIndex))), spreadIndex, /*hasRestElement*/ true, /*readonly*/ undefined);
2518425188
}
2518525189

2518625190
function checkTypeArguments(signature: Signature, typeArgumentNodes: readonly TypeNode[], reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | undefined {
@@ -25431,11 +25435,12 @@ namespace ts {
2543125435
}
2543225436
}
2543325437

25434-
function createSyntheticExpression(parent: Node, type: Type, isSpread?: boolean) {
25438+
function createSyntheticExpression(parent: Node, type: Type, isSpread?: boolean, tupleNameSource?: ParameterDeclaration | NamedTupleMember) {
2543525439
const result = <SyntheticExpression>createNode(SyntaxKind.SyntheticExpression, parent.pos, parent.end);
2543625440
result.parent = parent;
2543725441
result.type = type;
2543825442
result.isSpread = isSpread || false;
25443+
result.tupleNameSource = tupleNameSource;
2543925444
return result;
2544025445
}
2544125446

@@ -25470,7 +25475,7 @@ namespace ts {
2547025475
if (isTupleType(type)) {
2547125476
const typeArguments = getTypeArguments(<TypeReference>type);
2547225477
const restIndex = type.target.hasRestElement ? typeArguments.length - 1 : -1;
25473-
const syntheticArgs = map(typeArguments, (t, i) => createSyntheticExpression(spreadArgument, t, /*isSpread*/ i === restIndex));
25478+
const syntheticArgs = map(typeArguments, (t, i) => createSyntheticExpression(spreadArgument, t, /*isSpread*/ i === restIndex, type.target.labeledElementDeclarations?.[i]));
2547425479
return concatenate(args.slice(0, length - 1), syntheticArgs);
2547525480
}
2547625481
}

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,6 +1487,7 @@ namespace ts {
14871487
kind: SyntaxKind.SyntheticExpression;
14881488
isSpread: boolean;
14891489
type: Type;
1490+
tupleNameSource?: ParameterDeclaration | NamedTupleMember;
14901491
}
14911492

14921493
// see: https://tc39.github.io/ecma262/#prod-ExponentiationExpression

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,7 @@ declare namespace ts {
954954
kind: SyntaxKind.SyntheticExpression;
955955
isSpread: boolean;
956956
type: Type;
957+
tupleNameSource?: ParameterDeclaration | NamedTupleMember;
957958
}
958959
export type ExponentiationOperator = SyntaxKind.AsteriskAsteriskToken;
959960
export type MultiplicativeOperator = SyntaxKind.AsteriskToken | SyntaxKind.SlashToken | SyntaxKind.PercentToken;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,7 @@ declare namespace ts {
954954
kind: SyntaxKind.SyntheticExpression;
955955
isSpread: boolean;
956956
type: Type;
957+
tupleNameSource?: ParameterDeclaration | NamedTupleMember;
957958
}
958959
export type ExponentiationOperator = SyntaxKind.AsteriskAsteriskToken;
959960
export type MultiplicativeOperator = SyntaxKind.AsteriskToken | SyntaxKind.SlashToken | SyntaxKind.PercentToken;

tests/baselines/reference/namedTupleMembers.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,19 @@ declare var y: RecusiveRest2;
6969

7070
x = y;
7171
y = x;
72+
73+
declare function f<T extends any[]>(...x: T): T;
74+
declare function g(elem: object, index: number): object;
75+
declare function getArgsForInjection<T extends (...args: any[]) => any>(x: T): Parameters<T>;
76+
77+
export const argumentsOfGAsFirstArgument = f(getArgsForInjection(g)); // one tuple with captures arguments as first member
78+
export const argumentsOfG = f(...getArgsForInjection(g)); // captured arguments list re-spread
7279

7380

7481
//// [namedTupleMembers.js]
7582
"use strict";
7683
exports.__esModule = true;
77-
exports.val = exports.readSegment = exports.useState = exports.func = void 0;
84+
exports.argumentsOfG = exports.argumentsOfGAsFirstArgument = exports.val = exports.readSegment = exports.useState = exports.func = void 0;
7885
a = b;
7986
a = c;
8087
a = d;
@@ -102,6 +109,8 @@ q = r;
102109
r = q;
103110
x = y;
104111
y = x;
112+
exports.argumentsOfGAsFirstArgument = f(getArgsForInjection(g)); // one tuple with captures arguments as first member
113+
exports.argumentsOfG = f.apply(void 0, getArgsForInjection(g)); // captured arguments list re-spread
105114

106115

107116
//// [namedTupleMembers.d.ts]
@@ -127,3 +136,5 @@ export declare type RecursiveTupleA = [initial: string, next: RecursiveTupleA];
127136
export declare type RecursiveTupleB = [first: string, ptr: RecursiveTupleB];
128137
export declare type RecusiveRest = [first: string, ...rest: RecusiveRest[]];
129138
export declare type RecusiveRest2 = [string, ...RecusiveRest2[]];
139+
export declare const argumentsOfGAsFirstArgument: [[elem: object, index: number]];
140+
export declare const argumentsOfG: [elem: object, index: number];

tests/baselines/reference/namedTupleMembers.symbols

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,36 @@ y = x;
166166
>y : Symbol(y, Decl(namedTupleMembers.ts, 66, 11))
167167
>x : Symbol(x, Decl(namedTupleMembers.ts, 65, 11))
168168

169+
declare function f<T extends any[]>(...x: T): T;
170+
>f : Symbol(f, Decl(namedTupleMembers.ts, 69, 6))
171+
>T : Symbol(T, Decl(namedTupleMembers.ts, 71, 19))
172+
>x : Symbol(x, Decl(namedTupleMembers.ts, 71, 36))
173+
>T : Symbol(T, Decl(namedTupleMembers.ts, 71, 19))
174+
>T : Symbol(T, Decl(namedTupleMembers.ts, 71, 19))
175+
176+
declare function g(elem: object, index: number): object;
177+
>g : Symbol(g, Decl(namedTupleMembers.ts, 71, 48))
178+
>elem : Symbol(elem, Decl(namedTupleMembers.ts, 72, 19))
179+
>index : Symbol(index, Decl(namedTupleMembers.ts, 72, 32))
180+
181+
declare function getArgsForInjection<T extends (...args: any[]) => any>(x: T): Parameters<T>;
182+
>getArgsForInjection : Symbol(getArgsForInjection, Decl(namedTupleMembers.ts, 72, 56))
183+
>T : Symbol(T, Decl(namedTupleMembers.ts, 73, 37))
184+
>args : Symbol(args, Decl(namedTupleMembers.ts, 73, 48))
185+
>x : Symbol(x, Decl(namedTupleMembers.ts, 73, 72))
186+
>T : Symbol(T, Decl(namedTupleMembers.ts, 73, 37))
187+
>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --))
188+
>T : Symbol(T, Decl(namedTupleMembers.ts, 73, 37))
189+
190+
export const argumentsOfGAsFirstArgument = f(getArgsForInjection(g)); // one tuple with captures arguments as first member
191+
>argumentsOfGAsFirstArgument : Symbol(argumentsOfGAsFirstArgument, Decl(namedTupleMembers.ts, 75, 12))
192+
>f : Symbol(f, Decl(namedTupleMembers.ts, 69, 6))
193+
>getArgsForInjection : Symbol(getArgsForInjection, Decl(namedTupleMembers.ts, 72, 56))
194+
>g : Symbol(g, Decl(namedTupleMembers.ts, 71, 48))
195+
196+
export const argumentsOfG = f(...getArgsForInjection(g)); // captured arguments list re-spread
197+
>argumentsOfG : Symbol(argumentsOfG, Decl(namedTupleMembers.ts, 76, 12))
198+
>f : Symbol(f, Decl(namedTupleMembers.ts, 69, 6))
199+
>getArgsForInjection : Symbol(getArgsForInjection, Decl(namedTupleMembers.ts, 72, 56))
200+
>g : Symbol(g, Decl(namedTupleMembers.ts, 71, 48))
201+

tests/baselines/reference/namedTupleMembers.types

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,34 @@ y = x;
171171
>y : RecusiveRest2
172172
>x : RecusiveRest
173173

174+
declare function f<T extends any[]>(...x: T): T;
175+
>f : <T extends any[]>(...x: T) => T
176+
>x : T
177+
178+
declare function g(elem: object, index: number): object;
179+
>g : (elem: object, index: number) => object
180+
>elem : object
181+
>index : number
182+
183+
declare function getArgsForInjection<T extends (...args: any[]) => any>(x: T): Parameters<T>;
184+
>getArgsForInjection : <T extends (...args: any[]) => any>(x: T) => Parameters<T>
185+
>args : any[]
186+
>x : T
187+
188+
export const argumentsOfGAsFirstArgument = f(getArgsForInjection(g)); // one tuple with captures arguments as first member
189+
>argumentsOfGAsFirstArgument : [[elem: object, index: number]]
190+
>f(getArgsForInjection(g)) : [[elem: object, index: number]]
191+
>f : <T extends any[]>(...x: T) => T
192+
>getArgsForInjection(g) : [elem: object, index: number]
193+
>getArgsForInjection : <T extends (...args: any[]) => any>(x: T) => Parameters<T>
194+
>g : (elem: object, index: number) => object
195+
196+
export const argumentsOfG = f(...getArgsForInjection(g)); // captured arguments list re-spread
197+
>argumentsOfG : [elem: object, index: number]
198+
>f(...getArgsForInjection(g)) : [elem: object, index: number]
199+
>f : <T extends any[]>(...x: T) => T
200+
>...getArgsForInjection(g) : number | object
201+
>getArgsForInjection(g) : [elem: object, index: number]
202+
>getArgsForInjection : <T extends (...args: any[]) => any>(x: T) => Parameters<T>
203+
>g : (elem: object, index: number) => object
204+

tests/cases/conformance/types/tuple/named/namedTupleMembers.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,10 @@ declare var y: RecusiveRest2;
7070

7171
x = y;
7272
y = x;
73+
74+
declare function f<T extends any[]>(...x: T): T;
75+
declare function g(elem: object, index: number): object;
76+
declare function getArgsForInjection<T extends (...args: any[]) => any>(x: T): Parameters<T>;
77+
78+
export const argumentsOfGAsFirstArgument = f(getArgsForInjection(g)); // one tuple with captures arguments as first member
79+
export const argumentsOfG = f(...getArgsForInjection(g)); // captured arguments list re-spread

0 commit comments

Comments
 (0)