From fd65966a5028d3403dda934f97fe285cee427198 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 10 Mar 2017 21:18:18 -0800 Subject: [PATCH] temp --- src/compiler/checker.ts | 191 ++++++++++++++++++++++++++++++++++++++++ src/compiler/factory.ts | 37 +++++++- src/compiler/types.ts | 21 +++-- 3 files changed, 240 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index aa7908f52c1..109e6f33ea3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2388,11 +2388,198 @@ namespace ts { } } + function createTypeNode(type: Type) { + let encounteredError = false; + let checkAlias = true; + + return createTypeNodeWorker(type); + + function createTypeNodeWorker(type: Type): TypeNode { + if(!type) { + return undefined; + } + + if (checkAlias && type.aliasSymbol) { + const name = getNameOfSymbol(type.aliasSymbol); + const typeArguments = mapToTypeNodeArray(type.aliasTypeArguments); + return createTypeReferenceNode(createIdentifier(name), typeArguments); + } + checkAlias = false; + + + if(type.flags & TypeFlags.Any) { + // TODO: add other case where type ends up being `any`. + return createKeywordTypeNode(SyntaxKind.StringKeyword); + } + if(type.flags & TypeFlags.String) { + return createKeywordTypeNode(SyntaxKind.StringKeyword); + } + if(type.flags & TypeFlags.Number) { + return createKeywordTypeNode(SyntaxKind.NumberKeyword); + } + if(type.flags & (TypeFlags.Boolean | TypeFlags.StringOrNumberLiteral)) { + // TODO: check if this actually works with boolean. + return createLiteralTypeNode((type).text); + } + if(type.flags & TypeFlags.Void) { + return createKeywordTypeNode(SyntaxKind.VoidKeyword); + } + if(type.flags & TypeFlags.Undefined) { + return createKeywordTypeNode(SyntaxKind.UndefinedKeyword); + } + if(type.flags & TypeFlags.Null) { + return createKeywordTypeNode(SyntaxKind.NullKeyword); + } + if(type.flags & TypeFlags.Never) { + return createKeywordTypeNode(SyntaxKind.NeverKeyword); + } + if(type.flags & TypeFlags.Enum) { + throw new Error("not implemented"); + } + if(type.flags & TypeFlags.ESSymbol) { + throw new Error("not implemented"); + } + if(type.flags & TypeFlags.TypeParameter) { + const constraint = createTypeNodeWorker(getConstraintFromTypeParameter(type)); + const defaultParameter = createTypeNodeWorker(getDefaultFromTypeParameter(type)); + if(!type.symbol) { + encounteredError = true; + throw new Error("No symbol for type parameter so can't get name"); + } + const name = getNameOfSymbol(type.symbol); + return createTypeParameterNode(name, constraint, defaultParameter); + } + if(type.flags & TypeFlags.Union) { + throw new Error("not implemented"); + } + if(type.flags & TypeFlags.Intersection) { + throw new Error("not implemented"); + } + if(type.flags & TypeFlags.Index) { + throw new Error("not implemented"); + } + if(type.flags & TypeFlags.IndexedAccess) { + throw new Error("not implemented"); + } + + // if(type.flags & TypeFlags.Object) { + // throw new Error("not implemented"); + // } + + // TODO: should these be within the if above (check with asserts) + const objectFlags = getObjectFlags(type); + + if (objectFlags & ObjectFlags.ClassOrInterface) { + Debug.assert(!!(type.flags & TypeFlags.Object)); + // If type is a class or interface type that wasn't hit by the isSymbolAccessible check above, + // type must be an anonymous class or interface. + return false; + } + + if (objectFlags & ObjectFlags.Reference) { + Debug.assert(!!(type.flags & TypeFlags.Object)); + // and vice versa. + // this case includes tuple types + const typeArguments = (type as TypeReference).typeArguments || emptyArray; + return allTypesVisible(typeArguments); + } + + // keyword types + // this type node + // function type node + // constructor type node + // type reference node + // type predicate node - is Foo (for return types) + // type query node -- typeof number + // type literal node (like object literal) + // array type + // tuple type + // union type + // might need parens + // intersection type + // Type operator node (eg (ie?): keyof T) + // IndexedAccess Type Node + // mapped type node + // literal type node + + // if (inTypeAlias && type.aliasSymbol) { + // return isSymbolAccessible(type.aliasSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/false).accessibility === SymbolAccessibility.Accessible + // && (!type.aliasTypeArguments || allTypesVisible(type.aliasTypeArguments)); + // } + // const typeSymbolAccessibility = type.symbol && isSymbolAccessible(type.symbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility; + // if (type.flags & TypeFlags.TypeParameter) { + // if (inObjectLiteral && (type as TypeParameter).isThisType) { + // return false; + // } + // const constraint = getConstraintFromTypeParameter((type)); + // return typeSymbolAccessibility === SymbolAccessibility.Accessible + // && (!constraint || isTypeAccessibleWorker(constraint, inObjectLiteral, /*inTypeAlias*/false)); + // } + // if (typeSymbolAccessibility === SymbolAccessibility.Accessible) { + // return true; + // } + // if (type.flags & (TypeFlags.Intrinsic | TypeFlags.Literal)) { + // return true; + // } + // const objectFlags = getObjectFlags(type); + // if (objectFlags & ObjectFlags.ClassOrInterface) { + // // If type is a class or interface type that wasn't hit by the isSymbolAccessible check above, + // // type must be an anonymous class or interface. + // return false; + // } + // if (objectFlags & ObjectFlags.Reference) { + // // and vice versa. + // // this case includes tuple types + // const typeArguments = (type as TypeReference).typeArguments || emptyArray; + // return allTypesVisible(typeArguments); + // } + // if (type.flags & TypeFlags.UnionOrIntersection) { + // return allTypesVisible((type as UnionOrIntersectionType).types); + // } + + if (objectFlags & ObjectFlags.Mapped) { + Debug.assert(!!(type.flags & TypeFlags.Object)); + const typeParameter = getTypeParameterFromMappedType(type); + const constraintType = getConstraintTypeFromMappedType(type); + const templateType = getTemplateTypeFromMappedType(type); + } + + if (objectFlags & ObjectFlags.Anonymous) { + Debug.assert(!!(type.flags & TypeFlags.Object)); + // The type is an object literal type. + if (!type.symbol) { + // Anonymous types without symbols are literals. + return true; + } + // what case is this? + const members = type.symbol.members; + let allVisible = true; + members && members.forEach((member) => { + const memberType = getTypeOfSymbolAtLocation(member, enclosingDeclaration); + allVisible = allVisible && isTypeAccessibleWorker(memberType, /*inObjectLiteral*/ true, /*inTypeAlias*/false); + }); + return allVisible; + } + + Debug.fail("Should be unreachable here"); + + /** Note that mapToTypeNodeArray(undefined) === undefined. */ + function mapToTypeNodeArray(types: Type[]): NodeArray { + return asNodeArray(types && types.map(createTypeNodeWorker)); + } + // function allTypesVisible(types: Type[]): boolean { + // return types.every(type => isTypeAccessibleWorker(type, inObjectLiteral, /*inTypeAlias*/false)); + // } + } + } + function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]) { const globalFlagsToPass = globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike; let inObjectTypeLiteral = false; return writeType(type, globalFlags); + const typeNode = createTypeNode(type, enclosingDeclaration); + function writeType(type: Type, flags: TypeFormatFlags) { const nextFlags = flags & ~TypeFormatFlags.InTypeAlias; // Write undefined/null type as any @@ -6939,6 +7126,10 @@ namespace ts { } } + // export function synthesizeTypeNode(type: Type, enclosingDeclaration: Node): TypeNode { + // throw new Error("Not implemented" + enclosingDeclaration); + // } + function instantiateList(items: T[], mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): T[] { if (items && items.length) { const result: T[] = []; diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 669c66c4337..1e5395fe7b2 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -213,8 +213,43 @@ namespace ts { : node; } + // Types + + export function createLiteralTypeNode(value: string | number | boolean) { + const literal = createLiteral(value); + const literalTypeNode = createSynthesizedNode(SyntaxKind.LiteralType) as LiteralTypeNode; + literalTypeNode.literal = literal; + return literalTypeNode; + } + + export function createTypeReferenceNode(typeName: string | EntityName, typeArguments?: NodeArray) { + const typeReference = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode; + typeReference.typeName = asName(typeName); + typeReference.typeName.parent + typeReference.typeArguments = typeArguments; + return typeReference; + } + + export function createTypeParameterNode(name: string | Identifier, constraint?: TypeNode, defaultParameter?: TypeNode) { + const typeParameter = createSynthesizedNode(SyntaxKind.TypeParameter) as TypeParameterDeclaration; + typeParameter.name = asName(name); + typeParameter.constraint = constraint; + typeParameter.default = defaultParameter; + + return typeParameter; + } + // Signature elements + export function createSignature(kind: SyntaxKind, parameters: NodeArray, name?: PropertyName, typeParameters?: NodeArray, returnType?: TypeNode): SignatureDeclaration { + const signature = createSynthesizedNode(kind) as SignatureDeclaration; + signature.parameters = parameters; + signature.name = name; + signature.typeParameters = typeParameters; + signature.type = returnType; + return signature; + } + export function createParameter(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression) { const node = createSynthesizedNode(SyntaxKind.Parameter); node.decorators = asNodeArray(decorators); @@ -1801,7 +1836,7 @@ namespace ts { return typeof value === "string" || typeof value === "number" ? createLiteral(value) : value; } - function asNodeArray(array: T[] | undefined): NodeArray | undefined { + export function asNodeArray(array: T[] | undefined): NodeArray | undefined { return array ? createNodeArray(array) : undefined; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1492a106d2b..52207920b48 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -849,14 +849,19 @@ namespace ts { _typeNodeBrand: any; } + export type KeywordKind = SyntaxKind.AnyKeyword + | SyntaxKind.NumberKeyword + | SyntaxKind.ObjectKeyword + | SyntaxKind.BooleanKeyword + | SyntaxKind.StringKeyword + | SyntaxKind.SymbolKeyword + | SyntaxKind.VoidKeyword + | SyntaxKind.UndefinedKeyword + | SyntaxKind.NullKeyword + | SyntaxKind.NeverKeyword; + export interface KeywordTypeNode extends TypeNode { - kind: SyntaxKind.AnyKeyword - | SyntaxKind.NumberKeyword - | SyntaxKind.ObjectKeyword - | SyntaxKind.BooleanKeyword - | SyntaxKind.StringKeyword - | SyntaxKind.SymbolKeyword - | SyntaxKind.VoidKeyword; + kind: KeywordKind; } export interface ThisTypeNode extends TypeNode { @@ -892,7 +897,7 @@ namespace ts { exprName: EntityName; } - // A TypeLiteral is the declaration node for an anonymous symbol. + /** A TypeLiteral is the declaration node for an anonymous symbol. */ export interface TypeLiteralNode extends TypeNode, Declaration { kind: SyntaxKind.TypeLiteral; members: NodeArray;