Skip to content

Commit ddc7c3b

Browse files
add type-level function application
1 parent 4307195 commit ddc7c3b

File tree

10 files changed

+337
-7
lines changed

10 files changed

+337
-7
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7526,6 +7526,18 @@ namespace ts {
75267526
return links.resolvedType;
75277527
}
75287528

7529+
function getTypeFromTypeCallNode(node: TypeCallTypeNode): Type {
7530+
const fn = typeToExpression(node.type);
7531+
const args = map(node.arguments, typeToExpression);
7532+
const callExpr = createCall(fn, node.typeArguments, args);
7533+
return checkExpression(callExpr);
7534+
}
7535+
7536+
// null! as type
7537+
function typeToExpression(type: TypeNode): Expression {
7538+
return createAsExpression(createNonNullExpression(createNull()), type);
7539+
}
7540+
75297541
function createIndexedAccessType(objectType: Type, indexType: Type) {
75307542
const type = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
75317543
type.objectType = objectType;
@@ -7985,6 +7997,8 @@ namespace ts {
79857997
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
79867998
case SyntaxKind.TypeOperator:
79877999
return getTypeFromTypeOperatorNode(<TypeOperatorNode>node);
8000+
case SyntaxKind.TypeCall:
8001+
return getTypeFromTypeCallNode(<TypeCallTypeNode>node);
79888002
case SyntaxKind.IndexedAccessType:
79898003
return getTypeFromIndexedAccessTypeNode(<IndexedAccessTypeNode>node);
79908004
case SyntaxKind.MappedType:
@@ -13161,7 +13175,7 @@ namespace ts {
1316113175
return node.contextualType;
1316213176
}
1316313177
const parent = node.parent;
13164-
switch (parent.kind) {
13178+
switch (parent && parent.kind) {
1316513179
case SyntaxKind.VariableDeclaration:
1316613180
case SyntaxKind.Parameter:
1316713181
case SyntaxKind.PropertyDeclaration:

src/compiler/emitter.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,8 @@ namespace ts {
753753
return emitPropertyAccessExpression(<PropertyAccessExpression>node);
754754
case SyntaxKind.ElementAccessExpression:
755755
return emitElementAccessExpression(<ElementAccessExpression>node);
756+
case SyntaxKind.TypeCall:
757+
return emitTypeCall(<TypeCallTypeNode>node);
756758
case SyntaxKind.CallExpression:
757759
return emitCallExpression(<CallExpression>node);
758760
case SyntaxKind.NewExpression:
@@ -1240,6 +1242,12 @@ namespace ts {
12401242
write("]");
12411243
}
12421244

1245+
function emitTypeCall(node: TypeCallTypeNode) {
1246+
emit(node.type);
1247+
emitTypeArguments(node, node.typeArguments);
1248+
emitList(node, node.arguments, ListFormat.CallExpressionArguments);
1249+
}
1250+
12431251
function emitCallExpression(node: CallExpression) {
12441252
emitExpression(node.expression);
12451253
emitTypeArguments(node, node.typeArguments);

src/compiler/factory.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,22 @@ namespace ts {
888888
: node;
889889
}
890890

891+
export function createTypeCall(type: TypeNode, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentsArray: ReadonlyArray<TypeNode>) {
892+
const node = <TypeCallTypeNode>createSynthesizedNode(SyntaxKind.TypeCall);
893+
node.type = parenthesizeElementTypeMember(type);
894+
node.typeArguments = asNodeArray(typeArguments);
895+
node.arguments = parenthesizeElementTypeMembers(createNodeArray(argumentsArray));
896+
return node;
897+
}
898+
899+
export function updateTypeCall(node: TypeCallTypeNode, type: TypeNode, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentsArray: ReadonlyArray<TypeNode>) {
900+
return node.type !== type
901+
|| node.typeArguments !== typeArguments
902+
|| node.arguments !== argumentsArray
903+
? updateNode(createTypeCall(type, typeArguments, argumentsArray), node)
904+
: node;
905+
}
906+
891907
export function createCall(expression: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentsArray: ReadonlyArray<Expression>) {
892908
const node = <CallExpression>createSynthesizedNode(SyntaxKind.CallExpression);
893909
node.expression = parenthesizeForAccess(expression);

src/compiler/parser.ts

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ namespace ts {
170170
case SyntaxKind.ElementAccessExpression:
171171
return visitNode(cbNode, (<ElementAccessExpression>node).expression) ||
172172
visitNode(cbNode, (<ElementAccessExpression>node).argumentExpression);
173+
case SyntaxKind.TypeCall:
174+
return visitNode(cbNode, (<TypeCallTypeNode>node).type) ||
175+
visitNodes(cbNode, cbNodes, (<TypeCallTypeNode>node).typeArguments) ||
176+
visitNodes(cbNode, cbNodes, (<TypeCallTypeNode>node).arguments);
173177
case SyntaxKind.CallExpression:
174178
case SyntaxKind.NewExpression:
175179
return visitNode(cbNode, (<CallExpression>node).expression) ||
@@ -2738,8 +2742,8 @@ namespace ts {
27382742
return token() === SyntaxKind.CloseParenToken || isStartOfParameter() || isStartOfType();
27392743
}
27402744

2741-
function parseJSDocPostfixTypeOrHigher(): TypeNode {
2742-
const type = parseNonArrayType();
2745+
function parseJSDocPostfixTypeOrHigher(typeNode?: TypeNode): TypeNode {
2746+
const type = typeNode || parseNonArrayType();
27432747
const kind = getKind(token());
27442748
if (!kind) return type;
27452749
nextToken();
@@ -2761,8 +2765,8 @@ namespace ts {
27612765
}
27622766
}
27632767

2764-
function parseArrayTypeOrHigher(): TypeNode {
2765-
let type = parseJSDocPostfixTypeOrHigher();
2768+
function parseArrayTypeOrHigher(typeNode?: TypeNode): TypeNode {
2769+
let type = parseJSDocPostfixTypeOrHigher(typeNode);
27662770
while (!scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.OpenBracketToken)) {
27672771
if (isStartOfType()) {
27682772
const node = <IndexedAccessTypeNode>createNode(SyntaxKind.IndexedAccessType, type.pos);
@@ -2794,7 +2798,7 @@ namespace ts {
27942798
case SyntaxKind.KeyOfKeyword:
27952799
return parseTypeOperator(SyntaxKind.KeyOfKeyword);
27962800
}
2797-
return parseArrayTypeOrHigher();
2801+
return parseTypeCallRest();
27982802
}
27992803

28002804
function parseUnionOrIntersectionType(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, parseConstituentType: () => TypeNode, operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken): TypeNode {
@@ -4240,6 +4244,46 @@ namespace ts {
42404244
}
42414245
}
42424246

4247+
// type equivalent of parseCallExpressionRest
4248+
function parseTypeCallRest(type?: TypeNode): TypeNode {
4249+
while (true) {
4250+
type = parseArrayTypeOrHigher(type);
4251+
if (token() === SyntaxKind.LessThanToken) {
4252+
// See if this is the start of a generic invocation. If so, consume it and
4253+
// keep checking for postfix expressions. Otherwise, it's just a '<' that's
4254+
// part of an arithmetic expression. Break out so we consume it higher in the
4255+
// stack.
4256+
const typeArguments = tryParse(parseTypeArgumentsInExpression);
4257+
if (!typeArguments) {
4258+
return type;
4259+
}
4260+
4261+
const callExpr = <TypeCallTypeNode>createNode(SyntaxKind.TypeCall, type.pos);
4262+
callExpr.type = type;
4263+
callExpr.typeArguments = typeArguments;
4264+
callExpr.arguments = parseTypeArgumentList();
4265+
type = finishNode(callExpr);
4266+
continue;
4267+
}
4268+
else if (token() === SyntaxKind.OpenParenToken) {
4269+
const callExpr = <TypeCallTypeNode>createNode(SyntaxKind.TypeCall, type.pos);
4270+
callExpr.type = type;
4271+
callExpr.arguments = parseTypeArgumentList();
4272+
type = finishNode(callExpr);
4273+
continue;
4274+
}
4275+
4276+
return type;
4277+
}
4278+
}
4279+
4280+
function parseTypeArgumentList() {
4281+
parseExpected(SyntaxKind.OpenParenToken);
4282+
const result = parseDelimitedList(ParsingContext.TypeArguments, parseType);
4283+
parseExpected(SyntaxKind.CloseParenToken);
4284+
return result;
4285+
}
4286+
42434287
function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression {
42444288
while (true) {
42454289
expression = parseMemberExpressionRest(expression);

src/compiler/types.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ namespace ts {
240240
IndexedAccessType,
241241
MappedType,
242242
LiteralType,
243+
TypeCall,
243244
// Binding patterns
244245
ObjectBindingPattern,
245246
ArrayBindingPattern,
@@ -398,7 +399,7 @@ namespace ts {
398399
FirstFutureReservedWord = ImplementsKeyword,
399400
LastFutureReservedWord = YieldKeyword,
400401
FirstTypeNode = TypePredicate,
401-
LastTypeNode = LiteralType,
402+
LastTypeNode = TypeCall,
402403
FirstPunctuation = OpenBraceToken,
403404
LastPunctuation = CaretEqualsToken,
404405
FirstToken = Unknown,
@@ -1495,6 +1496,13 @@ namespace ts {
14951496
arguments: NodeArray<Expression>;
14961497
}
14971498

1499+
export interface TypeCallTypeNode extends TypeNode {
1500+
kind: SyntaxKind.TypeCall;
1501+
type: TypeNode;
1502+
typeArguments?: NodeArray<TypeNode>;
1503+
arguments: NodeArray<TypeNode>;
1504+
}
1505+
14981506
// see: https://tc39.github.io/ecma262/#prod-SuperCall
14991507
export interface SuperCall extends CallExpression {
15001508
expression: SuperExpression;

src/compiler/visitor.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,12 @@ namespace ts {
446446
visitNode((<ElementAccessExpression>node).expression, visitor, isExpression),
447447
visitNode((<ElementAccessExpression>node).argumentExpression, visitor, isExpression));
448448

449+
case SyntaxKind.TypeCall:
450+
return updateTypeCall(<TypeCallTypeNode>node,
451+
visitNode((<TypeCallTypeNode>node).type, visitor, isTypeNode),
452+
nodesVisitor((<TypeCallTypeNode>node).typeArguments, visitor, isTypeNode),
453+
nodesVisitor((<TypeCallTypeNode>node).arguments, visitor, isTypeNode));
454+
449455
case SyntaxKind.CallExpression:
450456
return updateCall(<CallExpression>node,
451457
visitNode((<CallExpression>node).expression, visitor, isExpression),
@@ -1391,6 +1397,10 @@ namespace ts {
13911397
result = reduceNode((<SpreadAssignment>node).expression, cbNode, result);
13921398
break;
13931399

1400+
case SyntaxKind.TypeCall:
1401+
result = reduceNode((<TypeCallTypeNode>node).type, cbNode, result);
1402+
break;
1403+
13941404
// Enum
13951405
case SyntaxKind.EnumMember:
13961406
result = reduceNode((<EnumMember>node).name, cbNode, result);

tests/baselines/reference/typeCall.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [typeCall.ts]
2+
type F1 = () => 1;
3+
type a = F1();
4+
5+
type F2 = (a: string) => 1;
6+
type b = F2('foo');
7+
8+
interface F3 {
9+
(): 1;
10+
(a: number): 2;
11+
(a: string): 3;
12+
}
13+
type c = F3();
14+
type d = F3(123);
15+
type e = F3('foo');
16+
17+
declare function f4(a: string): 1;
18+
let a = 'foo';
19+
type f = typeof f4(typeof a);
20+
21+
type g = (() => 1)();
22+
23+
type Id = <T>(v: T) => T;
24+
type h = Id(123);
25+
26+
type Wrap<T> = Id(T);
27+
type i = Wrap<123>;
28+
29+
type F5 = () => () => { a: () => 1; };
30+
type j = F5()()['a']();
31+
32+
33+
//// [typeCall.js]
34+
var a = 'foo';
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
=== tests/cases/compiler/typeCall.ts ===
2+
type F1 = () => 1;
3+
>F1 : Symbol(F1, Decl(typeCall.ts, 0, 0))
4+
5+
type a = F1();
6+
>a : Symbol(a, Decl(typeCall.ts, 0, 18), Decl(typeCall.ts, 16, 3))
7+
>F1 : Symbol(F1, Decl(typeCall.ts, 0, 0))
8+
9+
type F2 = (a: string) => 1;
10+
>F2 : Symbol(F2, Decl(typeCall.ts, 1, 14))
11+
>a : Symbol(a, Decl(typeCall.ts, 3, 11))
12+
13+
type b = F2('foo');
14+
>b : Symbol(b, Decl(typeCall.ts, 3, 27))
15+
>F2 : Symbol(F2, Decl(typeCall.ts, 1, 14))
16+
17+
interface F3 {
18+
>F3 : Symbol(F3, Decl(typeCall.ts, 4, 19))
19+
20+
(): 1;
21+
(a: number): 2;
22+
>a : Symbol(a, Decl(typeCall.ts, 8, 5))
23+
24+
(a: string): 3;
25+
>a : Symbol(a, Decl(typeCall.ts, 9, 5))
26+
}
27+
type c = F3();
28+
>c : Symbol(c, Decl(typeCall.ts, 10, 1))
29+
>F3 : Symbol(F3, Decl(typeCall.ts, 4, 19))
30+
31+
type d = F3(123);
32+
>d : Symbol(d, Decl(typeCall.ts, 11, 14))
33+
>F3 : Symbol(F3, Decl(typeCall.ts, 4, 19))
34+
35+
type e = F3('foo');
36+
>e : Symbol(e, Decl(typeCall.ts, 12, 17))
37+
>F3 : Symbol(F3, Decl(typeCall.ts, 4, 19))
38+
39+
declare function f4(a: string): 1;
40+
>f4 : Symbol(f4, Decl(typeCall.ts, 13, 19))
41+
>a : Symbol(a, Decl(typeCall.ts, 15, 20))
42+
43+
let a = 'foo';
44+
>a : Symbol(a, Decl(typeCall.ts, 0, 18), Decl(typeCall.ts, 16, 3))
45+
46+
type f = typeof f4(typeof a);
47+
>f : Symbol(f, Decl(typeCall.ts, 16, 14))
48+
>f4 : Symbol(f4, Decl(typeCall.ts, 13, 19))
49+
>a : Symbol(a, Decl(typeCall.ts, 0, 18), Decl(typeCall.ts, 16, 3))
50+
51+
type g = (() => 1)();
52+
>g : Symbol(g, Decl(typeCall.ts, 17, 29))
53+
54+
type Id = <T>(v: T) => T;
55+
>Id : Symbol(Id, Decl(typeCall.ts, 19, 21))
56+
>T : Symbol(T, Decl(typeCall.ts, 21, 11))
57+
>v : Symbol(v, Decl(typeCall.ts, 21, 14))
58+
>T : Symbol(T, Decl(typeCall.ts, 21, 11))
59+
>T : Symbol(T, Decl(typeCall.ts, 21, 11))
60+
61+
type h = Id(123);
62+
>h : Symbol(h, Decl(typeCall.ts, 21, 25))
63+
>Id : Symbol(Id, Decl(typeCall.ts, 19, 21))
64+
65+
type Wrap<T> = Id(T);
66+
>Wrap : Symbol(Wrap, Decl(typeCall.ts, 22, 17))
67+
>T : Symbol(T, Decl(typeCall.ts, 24, 10))
68+
>Id : Symbol(Id, Decl(typeCall.ts, 19, 21))
69+
>T : Symbol(T, Decl(typeCall.ts, 24, 10))
70+
71+
type i = Wrap<123>;
72+
>i : Symbol(i, Decl(typeCall.ts, 24, 21))
73+
>Wrap : Symbol(Wrap, Decl(typeCall.ts, 22, 17))
74+
75+
type F5 = () => () => { a: () => 1; };
76+
>F5 : Symbol(F5, Decl(typeCall.ts, 25, 19))
77+
>a : Symbol(a, Decl(typeCall.ts, 27, 23))
78+
79+
type j = F5()()['a']();
80+
>j : Symbol(j, Decl(typeCall.ts, 27, 38))
81+
>F5 : Symbol(F5, Decl(typeCall.ts, 25, 19))
82+

0 commit comments

Comments
 (0)