Skip to content

Commit

Permalink
merge in other PR for type spread node
Browse files Browse the repository at this point in the history
  • Loading branch information
KiaraGrouwstra committed Aug 24, 2017
2 parents 49eec37 + 568b899 commit c274d9b
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3358,6 +3358,7 @@ namespace ts {
case SyntaxKind.TypeLiteral:
case SyntaxKind.ArrayType:
case SyntaxKind.TupleType:
case SyntaxKind.TypeSpread:
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
case SyntaxKind.ParenthesizedType:
Expand Down
101 changes: 100 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/// <reference path="moduleNameResolver.ts"/>
/// <reference path="binder.ts"/>
/// <reference path="symbolWalker.ts" />
/// <reference types="node" />

declare var console: Console;

/* @internal */
namespace ts {
Expand Down Expand Up @@ -239,6 +242,7 @@ namespace ts {
const intersectionTypes = createMap<IntersectionType>();
const literalTypes = createMap<LiteralType>();
const indexedAccessTypes = createMap<IndexedAccessType>();
const spreadTypes = createMap<TypeSpreadType>();
const evolvingArrayTypes: EvolvingArrayType[] = [];

const unknownSymbol = createSymbol(SymbolFlags.Property, "unknown" as __String);
Expand Down Expand Up @@ -2542,6 +2546,10 @@ namespace ts {
const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType, context);
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
}
if (type.flags & TypeFlags.TypeSpread) {
const typeNode = typeToTypeNodeHelper((<TypeSpreadType>type).type, context);
return createTypeSpread(typeNode);
}

Debug.fail("Should be unreachable.");

Expand Down Expand Up @@ -3305,6 +3313,10 @@ namespace ts {
writeType((<IndexedAccessType>type).indexType, TypeFormatFlags.None);
writePunctuation(writer, SyntaxKind.CloseBracketToken);
}
else if (type.flags & TypeFlags.TypeSpread) {
writePunctuation(writer, SyntaxKind.DotDotDotToken);
writeType((<TypeSpreadType>type).type, TypeFormatFlags.None);
}
else {
// Should never get here
// { ... }
Expand Down Expand Up @@ -5392,6 +5404,7 @@ namespace ts {
}

function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: TypeParameter[], typeArguments: Type[]) {
if (allowSyntheticDefaultImports) console.log("resolveObjectTypeMembers", typeToString(type));
let mapper: TypeMapper;
let members: SymbolTable;
let callSignatures: Signature[];
Expand Down Expand Up @@ -7218,11 +7231,69 @@ namespace ts {
function getTypeFromTupleTypeNode(node: TupleTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = createTupleType(map(node.elementTypes, getTypeFromTypeNode));
links.resolvedType = createTupleType(flatMap(node.elementTypes, getTypeFromTupleElement));
}
return links.resolvedType;
}

function getTypeSpreadTypes(tuple: Type): Type[] {
if (isGenericTupleType(tuple)) {
// Defer the operation by creating a spread type.
const id = "" + tuple.id;
let type = spreadTypes.get(id);
if (!type) {
spreadTypes.set(id, type = createTypeSpreadType(tuple));
}
return [type];
}
else {
// const type = getApparentType(nodeType);
if (allowSyntheticDefaultImports) {
console.log("type", typeToString(tuple));
console.log("isTupleLikeType(type)", isTupleLikeType(tuple));
}
if (isTupleLikeType(tuple)) {
// return map(getPropertiesOfType(tuple), getTypeOfSymbol);
return getTupleTypeElementTypes(tuple);
}
else {
// error(typeNode, Diagnostics.Tuple_type_spreads_may_only_be_created_from_tuple_types);
console.log("not a tuple, don't resolve?");
return [];
}
}
}

function isGenericTupleType(type: Type): boolean {
return type.flags & TypeFlags.TypeVariable ? true :
type.flags & TypeFlags.UnionOrIntersection ? forEach((<UnionOrIntersectionType>type).types, isGenericTupleType) :
false;
}

function getTupleTypeElementTypes(type: Type): Type[] {
Debug.assert(isTupleLikeType(type));
const types = [];
let idx = 0;
let symbol: Symbol;
while (symbol = getPropertyOfObjectType(type, idx++ + "" as __String)) {
types.push(getTypeOfSymbol(symbol));
}
return types;
}

function getTypeFromTupleElement(node: TypeNode | TypeSpreadTypeNode): Type | Type[] {
if (node.kind === SyntaxKind.TypeSpread) {
const links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = getTypeFromTypeNode((node as TypeSpreadTypeNode).type);
}
return getTypeSpreadTypes(links.resolvedType);
}
else {
return getTypeFromTypeNode(node as TypeNode);
}
}

interface TypeSet extends Array<Type> {
containsAny?: boolean;
containsUndefined?: boolean;
Expand Down Expand Up @@ -7572,6 +7643,13 @@ namespace ts {
return type;
}

function createTypeSpreadType(tuple: Type) {
console.log("createTypeSpreadType");
const type = <TypeSpreadType>createType(TypeFlags.TypeSpread);
type.type = tuple;
return type;
}

function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) {
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
const propName = indexType.flags & TypeFlags.StringOrNumberLiteral ?
Expand Down Expand Up @@ -8389,6 +8467,9 @@ namespace ts {
if (type.flags & TypeFlags.IndexedAccess) {
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
}
// if (type.flags & TypeFlags.TypeSpread) {
// return getTypeSpreadTypes(instantiateType((<TypeSpreadType>type).type, mapper));
// }
return type;
}

Expand Down Expand Up @@ -18849,6 +18930,22 @@ namespace ts {
forEach(node.elementTypes, checkSourceElement);
}

function checkTypeSpreadTypeNode(node: TypeSpreadTypeNode) {
checkSourceElement(node.type);
// checkTypeSpreadType(<TypeSpreadType> getTypeFromTypeNode(node.type), node);
const type = getApparentType(getTypeFromTypeNode(node.type));
if (!isArrayLikeType(type)) { // isTupleLikeType
grammarErrorOnNode(node, Diagnostics.Tuple_type_spreads_may_only_be_created_from_tuple_types);
}
}

// function checkTypeSpreadType(spread: TypeSpreadType, node: TypeSpreadTypeNode) {
// const type = getApparentType(spread.type);
// if (!isArrayLikeType(type)) { // isTupleLikeType
// grammarErrorOnNode(node, Diagnostics.Tuple_type_spreads_may_only_be_created_from_tuple_types);
// }
// }

function checkUnionOrIntersectionType(node: UnionOrIntersectionTypeNode) {
forEach(node.types, checkSourceElement);
}
Expand Down Expand Up @@ -22384,6 +22481,8 @@ namespace ts {
return checkArrayType(<ArrayTypeNode>node);
case SyntaxKind.TupleType:
return checkTupleType(<TupleTypeNode>node);
case SyntaxKind.TypeSpread:
return checkTypeSpreadTypeNode(<TypeSpreadTypeNode>node);
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
return checkUnionOrIntersectionType(<UnionOrIntersectionTypeNode>node);
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2208,6 +2208,10 @@
"category": "Error",
"code": 2713
},
"Tuple type spreads may only be created from tuple types.": {
"category": "Error",
"code": 2714
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down
9 changes: 9 additions & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,8 @@ namespace ts {
return emitShorthandPropertyAssignment(<ShorthandPropertyAssignment>node);
case SyntaxKind.SpreadAssignment:
return emitSpreadAssignment(node as SpreadAssignment);
case SyntaxKind.TypeSpread:
return emitTypeSpread(node as TypeSpreadTypeNode);

// Enum
case SyntaxKind.EnumMember:
Expand Down Expand Up @@ -2201,6 +2203,13 @@ namespace ts {
}
}

function emitTypeSpread(node: TypeSpreadTypeNode) {
if (node.type) {
write("...");
emit(node.type);
}
}

//
// Enum
//
Expand Down
13 changes: 13 additions & 0 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2201,6 +2201,19 @@ namespace ts {
: node;
}

export function createTypeSpread(type: TypeNode) {
console.log("createTypeSpread");
const node = <TypeSpreadTypeNode>createSynthesizedNode(SyntaxKind.TypeSpread);
node.type = type !== undefined ? parenthesizeElementTypeMember(type) : undefined;
return node;
}

export function updateTypeSpread(node: TypeSpreadTypeNode, type: TypeNode) {
return node.type !== type
? updateNode(createTypeSpread(type), node)
: node;
}

// Enum

export function createEnumMember(name: string | PropertyName, initializer?: Expression) {
Expand Down
20 changes: 18 additions & 2 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ namespace ts {
visitNode(cbNode, (<ShorthandPropertyAssignment>node).objectAssignmentInitializer);
case SyntaxKind.SpreadAssignment:
return visitNode(cbNode, (<SpreadAssignment>node).expression);
case SyntaxKind.TypeSpread:
return visitNode(cbNode, (<TypeSpreadTypeNode>node).type);
case SyntaxKind.Parameter:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
Expand Down Expand Up @@ -1382,8 +1384,9 @@ namespace ts {
case ParsingContext.Parameters:
return isStartOfParameter();
case ParsingContext.TypeArguments:
case ParsingContext.TupleElementTypes:
return token() === SyntaxKind.CommaToken || isStartOfType();
case ParsingContext.TupleElementTypes:
return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isStartOfType();
case ParsingContext.HeritageClauses:
return isHeritageClause();
case ParsingContext.ImportOrExportSpecifiers:
Expand Down Expand Up @@ -2589,7 +2592,7 @@ namespace ts {

function parseTupleType(): TupleTypeNode {
const node = <TupleTypeNode>createNode(SyntaxKind.TupleType);
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElement, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
return finishNode(node);
}

Expand Down Expand Up @@ -5205,6 +5208,19 @@ namespace ts {
return finishNode(node);
}

function parseTupleElement(): TypeSpreadTypeNode | TypeNode {
return (token() === SyntaxKind.DotDotDotToken) ?
parseTypeSpread() :
parseType();
}

function parseTypeSpread(): TypeSpreadTypeNode {
const node = <TypeSpreadTypeNode>createNode(SyntaxKind.TypeSpread);
parseExpected(SyntaxKind.DotDotDotToken);
node.type = parseTypeOperatorOrHigher();
return finishNode(node);
}

function parseObjectBindingElement(): BindingElement {
const node = <BindingElement>createNode(SyntaxKind.BindingElement);
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
Expand Down
14 changes: 13 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ namespace ts {
PropertyAssignment,
ShorthandPropertyAssignment,
SpreadAssignment,
TypeSpread,

// Enum
EnumMember,
Expand Down Expand Up @@ -951,7 +952,12 @@ namespace ts {

export interface TupleTypeNode extends TypeNode {
kind: SyntaxKind.TupleType;
elementTypes: NodeArray<TypeNode>;
elementTypes: NodeArray<TypeNode | TypeSpreadTypeNode>;
}

export interface TypeSpreadTypeNode extends TypeNode {
kind: SyntaxKind.TypeSpread;
type: TypeNode;
}

export type UnionOrIntersectionTypeNode = UnionTypeNode | IntersectionTypeNode;
Expand Down Expand Up @@ -3158,6 +3164,7 @@ namespace ts {
NonPrimitive = 1 << 24, // intrinsic object type
/* @internal */
JsxAttributes = 1 << 25, // Jsx attributes type
TypeSpread = 1 << 26, // spread in tuple types

/* @internal */
Nullable = Undefined | Null,
Expand Down Expand Up @@ -3406,6 +3413,11 @@ namespace ts {
constraint?: Type;
}

// type spread types (TypeFlags.TypeSpread)
export interface TypeSpreadType extends TypeVariable {
type: Type;
}

// keyof T types (TypeFlags.Index)
export interface IndexType extends Type {
type: TypeVariable | UnionOrIntersectionType;
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4506,6 +4506,10 @@ namespace ts {
return node.kind === SyntaxKind.SpreadAssignment;
}

export function isTypeSpread(node: Node): node is TypeSpreadTypeNode {
return node.kind === SyntaxKind.TypeSpread;
}

// Enum

export function isEnumMember(node: Node): node is EnumMember {
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,10 @@ namespace ts {
return updateSpreadAssignment(<SpreadAssignment>node,
visitNode((<SpreadAssignment>node).expression, visitor, isExpression));

case SyntaxKind.TypeSpread:
return updateTypeSpread(<TypeSpreadTypeNode>node,
visitNode((<TypeSpreadTypeNode>node).type, visitor, isTypeNode));

// Enum
case SyntaxKind.EnumMember:
return updateEnumMember(<EnumMember>node,
Expand Down Expand Up @@ -1401,6 +1405,10 @@ namespace ts {
result = reduceNode((<TypeCallTypeNode>node).type, cbNode, result);
break;

case SyntaxKind.TypeSpread:
result = reduceNode((<TypeSpreadTypeNode>node).type, cbNode, result);
break;

// Enum
case SyntaxKind.EnumMember:
result = reduceNode((<EnumMember>node).name, cbNode, result);
Expand Down
7 changes: 7 additions & 0 deletions tests/baselines/reference/tupleTypeSpread.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//// [tupleTypeSpread.ts]
type a = [1, ...[2]];
type Combine<Head, Tail extends any[]> = [Head, ...Tail];
type b = Combine<1, [2, 3]>;


//// [tupleTypeSpread.js]
15 changes: 15 additions & 0 deletions tests/baselines/reference/tupleTypeSpread.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
=== tests/cases/compiler/tupleTypeSpread.ts ===
type a = [1, ...[2]];
>a : Symbol(a, Decl(tupleTypeSpread.ts, 0, 0))

type Combine<Head, Tail extends any[]> = [Head, ...Tail];
>Combine : Symbol(Combine, Decl(tupleTypeSpread.ts, 0, 21))
>Head : Symbol(Head, Decl(tupleTypeSpread.ts, 1, 13))
>Tail : Symbol(Tail, Decl(tupleTypeSpread.ts, 1, 18))
>Head : Symbol(Head, Decl(tupleTypeSpread.ts, 1, 13))
>Tail : Symbol(Tail, Decl(tupleTypeSpread.ts, 1, 18))

type b = Combine<1, [2, 3]>;
>b : Symbol(b, Decl(tupleTypeSpread.ts, 1, 57))
>Combine : Symbol(Combine, Decl(tupleTypeSpread.ts, 0, 21))

Loading

0 comments on commit c274d9b

Please sign in to comment.