Skip to content

Commit acda704

Browse files
committed
Merge pull request #3397 from Microsoft/genericTypeAliases
Generic type aliases
2 parents 29afea3 + cd59573 commit acda704

13 files changed

+940
-91
lines changed

src/compiler/binder.ts

+12-9
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ module ts {
338338
case SyntaxKind.ArrowFunction:
339339
case SyntaxKind.ModuleDeclaration:
340340
case SyntaxKind.SourceFile:
341+
case SyntaxKind.TypeAliasDeclaration:
341342
return ContainerFlags.IsContainerWithLocals;
342343

343344
case SyntaxKind.CatchClause:
@@ -385,10 +386,10 @@ module ts {
385386

386387
function declareSymbolAndAddToSymbolTableWorker(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol {
387388
switch (container.kind) {
388-
// Modules, source files, and classes need specialized handling for how their
389+
// Modules, source files, and classes need specialized handling for how their
389390
// members are declared (for example, a member of a class will go into a specific
390-
// symbol table depending on if it is static or not). As such, we defer to
391-
// specialized handlers to take care of declaring these child members.
391+
// symbol table depending on if it is static or not). We defer to specialized
392+
// handlers to take care of declaring these child members.
392393
case SyntaxKind.ModuleDeclaration:
393394
return declareModuleMember(node, symbolFlags, symbolExcludes);
394395

@@ -406,9 +407,10 @@ module ts {
406407
case SyntaxKind.ObjectLiteralExpression:
407408
case SyntaxKind.InterfaceDeclaration:
408409
// Interface/Object-types always have their children added to the 'members' of
409-
// their container. They are only accessible through an instance of their
410-
// container, and are never in scope otherwise (even inside the body of the
411-
// object / type / interface declaring them).
410+
// their container. They are only accessible through an instance of their
411+
// container, and are never in scope otherwise (even inside the body of the
412+
// object / type / interface declaring them). An exception is type parameters,
413+
// which are in scope without qualification (similar to 'locals').
412414
return declareSymbol(container.symbol.members, container.symbol, node, symbolFlags, symbolExcludes);
413415

414416
case SyntaxKind.FunctionType:
@@ -424,11 +426,12 @@ module ts {
424426
case SyntaxKind.FunctionDeclaration:
425427
case SyntaxKind.FunctionExpression:
426428
case SyntaxKind.ArrowFunction:
429+
case SyntaxKind.TypeAliasDeclaration:
427430
// All the children of these container types are never visible through another
428-
// symbol (i.e. through another symbol's 'exports' or 'members'). Instead,
429-
// they're only accessed 'lexically' (i.e. from code that exists underneath
431+
// symbol (i.e. through another symbol's 'exports' or 'members'). Instead,
432+
// they're only accessed 'lexically' (i.e. from code that exists underneath
430433
// their container in the tree. To accomplish this, we simply add their declared
431-
// symbol to the 'locals' of the container. These symbols can then be found as
434+
// symbol to the 'locals' of the container. These symbols can then be found as
432435
// the type checker walks up the containers, checking them for matching names.
433436
return declareSymbol(container.locals, undefined, node, symbolFlags, symbolExcludes);
434437
}

src/compiler/checker.ts

+94-68
Large diffs are not rendered by default.

src/compiler/parser.ts

+2
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ module ts {
258258
return visitNodes(cbNodes, node.decorators) ||
259259
visitNodes(cbNodes, node.modifiers) ||
260260
visitNode(cbNode, (<TypeAliasDeclaration>node).name) ||
261+
visitNodes(cbNodes, (<TypeAliasDeclaration>node).typeParameters) ||
261262
visitNode(cbNode, (<TypeAliasDeclaration>node).type);
262263
case SyntaxKind.EnumDeclaration:
263264
return visitNodes(cbNodes, node.decorators) ||
@@ -4591,6 +4592,7 @@ module ts {
45914592
setModifiers(node, modifiers);
45924593
parseExpected(SyntaxKind.TypeKeyword);
45934594
node.name = parseIdentifier();
4595+
node.typeParameters = parseTypeParameters();
45944596
parseExpected(SyntaxKind.EqualsToken);
45954597
node.type = parseType();
45964598
parseSemicolon();

src/compiler/types.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,7 @@ module ts {
946946

947947
export interface TypeAliasDeclaration extends Declaration, Statement {
948948
name: Identifier;
949+
typeParameters?: NodeArray<TypeParameterDeclaration>;
949950
type: TypeNode;
950951
}
951952

@@ -1539,7 +1540,9 @@ module ts {
15391540
export interface SymbolLinks {
15401541
target?: Symbol; // Resolved (non-alias) target of an alias
15411542
type?: Type; // Type of value symbol
1542-
declaredType?: Type; // Type of class, interface, enum, or type parameter
1543+
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
1544+
typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic)
1545+
instantiations?: Map<Type>; // Instantiations of generic type alias (undefined if non-generic)
15431546
mapper?: TypeMapper; // Type mapper for instantiation alias
15441547
referenced?: boolean; // True if alias symbol has been referenced as a value
15451548
unionType?: UnionType; // Containing union type for union property
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//// [genericTypeAliases.ts]
2+
type Tree<T> = T | { left: Tree<T>, right: Tree<T> };
3+
4+
var tree: Tree<number> = {
5+
left: {
6+
left: 0,
7+
right: {
8+
left: 1,
9+
right: 2
10+
},
11+
},
12+
right: 3
13+
};
14+
15+
type Lazy<T> = T | (() => T);
16+
17+
var ls: Lazy<string>;
18+
ls = "eager";
19+
ls = () => "lazy";
20+
21+
type Foo<T> = T | { x: Foo<T> };
22+
type Bar<U> = U | { x: Bar<U> };
23+
24+
// Deeply instantiated generics
25+
var x: Foo<string>;
26+
var y: Bar<string>;
27+
x = y;
28+
y = x;
29+
30+
x = "string";
31+
x = { x: "hello" };
32+
x = { x: { x: "world" } };
33+
34+
var z: Foo<number>;
35+
z = 42;
36+
z = { x: 42 };
37+
z = { x: { x: 42 } };
38+
39+
type Strange<T> = string; // Type parameter not used
40+
var s: Strange<number>;
41+
s = "hello";
42+
43+
interface Tuple<A, B> {
44+
a: A;
45+
b: B;
46+
}
47+
48+
type Pair<T> = Tuple<T, T>;
49+
50+
interface TaggedPair<T> extends Pair<T> {
51+
tag: string;
52+
}
53+
54+
var p: TaggedPair<number>;
55+
p.a = 1;
56+
p.b = 2;
57+
p.tag = "test";
58+
59+
function f<A>() {
60+
type Foo<T> = T | { x: Foo<T> };
61+
var x: Foo<A[]>;
62+
return x;
63+
}
64+
65+
function g<B>() {
66+
type Bar<U> = U | { x: Bar<U> };
67+
var x: Bar<B[]>;
68+
return x;
69+
}
70+
71+
// Deeply instantiated generics
72+
var a = f<string>();
73+
var b = g<string>();
74+
a = b;
75+
76+
77+
//// [genericTypeAliases.js]
78+
var tree = {
79+
left: {
80+
left: 0,
81+
right: {
82+
left: 1,
83+
right: 2
84+
}
85+
},
86+
right: 3
87+
};
88+
var ls;
89+
ls = "eager";
90+
ls = function () { return "lazy"; };
91+
// Deeply instantiated generics
92+
var x;
93+
var y;
94+
x = y;
95+
y = x;
96+
x = "string";
97+
x = { x: "hello" };
98+
x = { x: { x: "world" } };
99+
var z;
100+
z = 42;
101+
z = { x: 42 };
102+
z = { x: { x: 42 } };
103+
var s;
104+
s = "hello";
105+
var p;
106+
p.a = 1;
107+
p.b = 2;
108+
p.tag = "test";
109+
function f() {
110+
var x;
111+
return x;
112+
}
113+
function g() {
114+
var x;
115+
return x;
116+
}
117+
// Deeply instantiated generics
118+
var a = f();
119+
var b = g();
120+
a = b;

0 commit comments

Comments
 (0)