Skip to content

Commit

Permalink
Merge pull request #3397 from Microsoft/genericTypeAliases
Browse files Browse the repository at this point in the history
Generic type aliases
  • Loading branch information
ahejlsberg committed Jun 9, 2015
2 parents 29afea3 + cd59573 commit acda704
Show file tree
Hide file tree
Showing 13 changed files with 940 additions and 91 deletions.
21 changes: 12 additions & 9 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ module ts {
case SyntaxKind.ArrowFunction:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.SourceFile:
case SyntaxKind.TypeAliasDeclaration:
return ContainerFlags.IsContainerWithLocals;

case SyntaxKind.CatchClause:
Expand Down Expand Up @@ -385,10 +386,10 @@ module ts {

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

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

case SyntaxKind.FunctionType:
Expand All @@ -424,11 +426,12 @@ module ts {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.TypeAliasDeclaration:
// All the children of these container types are never visible through another
// symbol (i.e. through another symbol's 'exports' or 'members'). Instead,
// they're only accessed 'lexically' (i.e. from code that exists underneath
// symbol (i.e. through another symbol's 'exports' or 'members'). Instead,
// they're only accessed 'lexically' (i.e. from code that exists underneath
// their container in the tree. To accomplish this, we simply add their declared
// symbol to the 'locals' of the container. These symbols can then be found as
// symbol to the 'locals' of the container. These symbols can then be found as
// the type checker walks up the containers, checking them for matching names.
return declareSymbol(container.locals, undefined, node, symbolFlags, symbolExcludes);
}
Expand Down
162 changes: 94 additions & 68 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ module ts {
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
visitNode(cbNode, (<TypeAliasDeclaration>node).name) ||
visitNodes(cbNodes, (<TypeAliasDeclaration>node).typeParameters) ||
visitNode(cbNode, (<TypeAliasDeclaration>node).type);
case SyntaxKind.EnumDeclaration:
return visitNodes(cbNodes, node.decorators) ||
Expand Down Expand Up @@ -4591,6 +4592,7 @@ module ts {
setModifiers(node, modifiers);
parseExpected(SyntaxKind.TypeKeyword);
node.name = parseIdentifier();
node.typeParameters = parseTypeParameters();
parseExpected(SyntaxKind.EqualsToken);
node.type = parseType();
parseSemicolon();
Expand Down
5 changes: 4 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,7 @@ module ts {

export interface TypeAliasDeclaration extends Declaration, Statement {
name: Identifier;
typeParameters?: NodeArray<TypeParameterDeclaration>;
type: TypeNode;
}

Expand Down Expand Up @@ -1539,7 +1540,9 @@ module ts {
export interface SymbolLinks {
target?: Symbol; // Resolved (non-alias) target of an alias
type?: Type; // Type of value symbol
declaredType?: Type; // Type of class, interface, enum, or type parameter
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic)
instantiations?: Map<Type>; // Instantiations of generic type alias (undefined if non-generic)
mapper?: TypeMapper; // Type mapper for instantiation alias
referenced?: boolean; // True if alias symbol has been referenced as a value
unionType?: UnionType; // Containing union type for union property
Expand Down
120 changes: 120 additions & 0 deletions tests/baselines/reference/genericTypeAliases.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//// [genericTypeAliases.ts]
type Tree<T> = T | { left: Tree<T>, right: Tree<T> };

var tree: Tree<number> = {
left: {
left: 0,
right: {
left: 1,
right: 2
},
},
right: 3
};

type Lazy<T> = T | (() => T);

var ls: Lazy<string>;
ls = "eager";
ls = () => "lazy";

type Foo<T> = T | { x: Foo<T> };
type Bar<U> = U | { x: Bar<U> };

// Deeply instantiated generics
var x: Foo<string>;
var y: Bar<string>;
x = y;
y = x;

x = "string";
x = { x: "hello" };
x = { x: { x: "world" } };

var z: Foo<number>;
z = 42;
z = { x: 42 };
z = { x: { x: 42 } };

type Strange<T> = string; // Type parameter not used
var s: Strange<number>;
s = "hello";

interface Tuple<A, B> {
a: A;
b: B;
}

type Pair<T> = Tuple<T, T>;

interface TaggedPair<T> extends Pair<T> {
tag: string;
}

var p: TaggedPair<number>;
p.a = 1;
p.b = 2;
p.tag = "test";

function f<A>() {
type Foo<T> = T | { x: Foo<T> };
var x: Foo<A[]>;
return x;
}

function g<B>() {
type Bar<U> = U | { x: Bar<U> };
var x: Bar<B[]>;
return x;
}

// Deeply instantiated generics
var a = f<string>();
var b = g<string>();
a = b;


//// [genericTypeAliases.js]
var tree = {
left: {
left: 0,
right: {
left: 1,
right: 2
}
},
right: 3
};
var ls;
ls = "eager";
ls = function () { return "lazy"; };
// Deeply instantiated generics
var x;
var y;
x = y;
y = x;
x = "string";
x = { x: "hello" };
x = { x: { x: "world" } };
var z;
z = 42;
z = { x: 42 };
z = { x: { x: 42 } };
var s;
s = "hello";
var p;
p.a = 1;
p.b = 2;
p.tag = "test";
function f() {
var x;
return x;
}
function g() {
var x;
return x;
}
// Deeply instantiated generics
var a = f();
var b = g();
a = b;
Loading

0 comments on commit acda704

Please sign in to comment.