From 3e142f8e524233b9cd6aa84f17ed0f4d3d719fdb Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 6 Feb 2017 08:47:11 -0800 Subject: [PATCH 01/83] Object literal freshness errors with spreads Previously, object literals with spreads in them would not issue object literal freshness errors. Fixes #13878 --- src/compiler/checker.ts | 2 ++ .../objectLiteralFreshnessWithSpread.errors.txt | 11 +++++++++++ .../objectLiteralFreshnessWithSpread.js | 16 ++++++++++++++++ .../compiler/objectLiteralFreshnessWithSpread.ts | 2 ++ 4 files changed, 31 insertions(+) create mode 100644 tests/baselines/reference/objectLiteralFreshnessWithSpread.errors.txt create mode 100644 tests/baselines/reference/objectLiteralFreshnessWithSpread.js create mode 100644 tests/cases/compiler/objectLiteralFreshnessWithSpread.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b5306771dd..80a2f2f6e7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11864,6 +11864,8 @@ namespace ts { if (spread.flags & TypeFlags.Object) { // only set the symbol and flags if this is a (fresh) object type spread.flags |= propagatedFlags; + spread.flags |= TypeFlags.FreshLiteral; + (spread as ObjectType).objectFlags |= ObjectFlags.ObjectLiteral; spread.symbol = node.symbol; } return spread; diff --git a/tests/baselines/reference/objectLiteralFreshnessWithSpread.errors.txt b/tests/baselines/reference/objectLiteralFreshnessWithSpread.errors.txt new file mode 100644 index 0000000000..ac6b56f6ce --- /dev/null +++ b/tests/baselines/reference/objectLiteralFreshnessWithSpread.errors.txt @@ -0,0 +1,11 @@ +tests/cases/compiler/objectLiteralFreshnessWithSpread.ts(2,35): error TS2322: Type '{ z: number; b: number; extra: number; a: number; }' is not assignable to type '{ a: any; b: any; }'. + Object literal may only specify known properties, and 'z' does not exist in type '{ a: any; b: any; }'. + + +==== tests/cases/compiler/objectLiteralFreshnessWithSpread.ts (1 errors) ==== + let x = { b: 1, extra: 2 } + let xx: { a, b } = { a: 1, ...x, z: 3 } // error for 'z', no error for 'extra' + ~~~~ +!!! error TS2322: Type '{ z: number; b: number; extra: number; a: number; }' is not assignable to type '{ a: any; b: any; }'. +!!! error TS2322: Object literal may only specify known properties, and 'z' does not exist in type '{ a: any; b: any; }'. + \ No newline at end of file diff --git a/tests/baselines/reference/objectLiteralFreshnessWithSpread.js b/tests/baselines/reference/objectLiteralFreshnessWithSpread.js new file mode 100644 index 0000000000..0a4222603a --- /dev/null +++ b/tests/baselines/reference/objectLiteralFreshnessWithSpread.js @@ -0,0 +1,16 @@ +//// [objectLiteralFreshnessWithSpread.ts] +let x = { b: 1, extra: 2 } +let xx: { a, b } = { a: 1, ...x, z: 3 } // error for 'z', no error for 'extra' + + +//// [objectLiteralFreshnessWithSpread.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var x = { b: 1, extra: 2 }; +var xx = __assign({ a: 1 }, x, { z: 3 }); // error for 'z', no error for 'extra' diff --git a/tests/cases/compiler/objectLiteralFreshnessWithSpread.ts b/tests/cases/compiler/objectLiteralFreshnessWithSpread.ts new file mode 100644 index 0000000000..7e8044e064 --- /dev/null +++ b/tests/cases/compiler/objectLiteralFreshnessWithSpread.ts @@ -0,0 +1,2 @@ +let x = { b: 1, extra: 2 } +let xx: { a, b } = { a: 1, ...x, z: 3 } // error for 'z', no error for 'extra' From 7e2517975c0dd86b7549f3ab4e231d9c207d0e65 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 30 Mar 2017 14:14:15 -0700 Subject: [PATCH 02/83] Basic functionality * pass context as argument in xToNode methods * make sourcefile optional in printer * start consolidating NodeBuilderFlags and TypeFormatFlags --- src/compiler/checker.ts | 186 +++++++++++++++++------------- src/compiler/emitter.ts | 24 ++-- src/compiler/factory.ts | 25 ++++ src/compiler/types.ts | 11 +- src/compiler/utilities.ts | 14 ++- src/services/codefixes/helpers.ts | 2 +- src/services/textChanges.ts | 24 +--- 7 files changed, 162 insertions(+), 124 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4e55a1c46b..28ba350f38 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2188,8 +2188,7 @@ namespace ts { return result; } - - function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { + function oldTypeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { const writer = getSingleLineStringWriter(); getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); let result = writer.string(); @@ -2202,25 +2201,43 @@ namespace ts { return result; } - function createNodeBuilder() { - let context: NodeBuilderContext; + function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { + const str = oldTypeToString(type, enclosingDeclaration, flags); str; + const str2 = oldTypeToString(type, enclosingDeclaration, flags); str2; + const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, NodeBuilderFlags.ignoreErrors); + Debug.assert(typeNode !== undefined, "should always get typenode?"); + const newLine = NewLineKind.None; + const options = { newLine, removeComments: true }; + const writer = createTextWriter(""); + // writer.writeLine = noop; + const printer = createPrinter(options, writer); + printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ undefined, writer); + const result = writer.getText(); + const maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100; + if (maxLength && result.length >= maxLength) { + return result.substr(0, maxLength - "...".length) + "..."; + } + return result; + } + + function createNodeBuilder() { return { typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { - context = createNodeBuilderContext(enclosingDeclaration, flags); - const resultingNode = typeToTypeNodeHelper(type); + const context = createNodeBuilderContext(enclosingDeclaration, flags); + const resultingNode = typeToTypeNodeHelper(type, context); const result = context.encounteredError ? undefined : resultingNode; return result; }, indexInfoToIndexSignatureDeclaration: (indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { - context = createNodeBuilderContext(enclosingDeclaration, flags); - const resultingNode = indexInfoToIndexSignatureDeclarationHelper(indexInfo, kind); + const context = createNodeBuilderContext(enclosingDeclaration, flags); + const resultingNode = indexInfoToIndexSignatureDeclarationHelper(indexInfo, kind, context); const result = context.encounteredError ? undefined : resultingNode; return result; }, signatureToSignatureDeclaration: (signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { - context = createNodeBuilderContext(enclosingDeclaration, flags); - const resultingNode = signatureToSignatureDeclarationHelper(signature, kind); + const context = createNodeBuilderContext(enclosingDeclaration, flags); + const resultingNode = signatureToSignatureDeclarationHelper(signature, kind, context); const result = context.encounteredError ? undefined : resultingNode; return result; } @@ -2246,7 +2263,7 @@ namespace ts { }; } - function typeToTypeNodeHelper(type: Type): TypeNode { + function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { if (!type) { context.encounteredError = true; // TODO(aozgaa): should we return implict any (undefined) or explicit any (keywordtypenode)? @@ -2266,7 +2283,7 @@ namespace ts { return createKeywordTypeNode(SyntaxKind.BooleanKeyword); } if (type.flags & TypeFlags.Enum) { - const name = symbolToName(type.symbol, /*expectsIdentifier*/ false); + const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, context); return createTypeReferenceNode(name, /*typeArguments*/ undefined); } if (type.flags & (TypeFlags.StringLiteral)) { @@ -2279,8 +2296,11 @@ namespace ts { return (type).intrinsicName === "true" ? createTrue() : createFalse(); } if (type.flags & TypeFlags.EnumLiteral) { - const name = symbolToName(type.symbol, /*expectsIdentifier*/ false); - return createTypeReferenceNode(name, /*typeArguments*/ undefined); + const parentSymbol = getParentOfSymbol(type.symbol); + const parentName = symbolToName(parentSymbol, /*expectsIdentifier*/ false, context); + const name = getNameOfSymbol(type.symbol, context); + const enumLiteralName = createQualifiedName(parentName, name); + return createTypeReferenceNode(enumLiteralName, /*typeArguments*/ undefined); } if (type.flags & TypeFlags.Void) { return createKeywordTypeNode(SyntaxKind.VoidKeyword); @@ -2317,18 +2337,18 @@ namespace ts { } if (objectFlags & ObjectFlags.ClassOrInterface) { Debug.assert(!!(type.flags & TypeFlags.Object)); - const name = symbolToName(type.symbol, /*expectsIdentifier*/ false); + const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, context); // TODO(aozgaa): handle type arguments. return createTypeReferenceNode(name, /*typeArguments*/ undefined); } if (type.flags & TypeFlags.TypeParameter) { - const name = symbolToName(type.symbol, /*expectsIdentifier*/ false); + const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, context); // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. return createTypeReferenceNode(name, /*typeArguments*/ undefined); } if (context.checkAlias && type.aliasSymbol) { - const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false); + const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, context); const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments); return createTypeReferenceNode(name, typeArgumentNodes); } @@ -2360,12 +2380,12 @@ namespace ts { if (type.flags & TypeFlags.Index) { const indexedType = (type).type; - const indexTypeNode = typeToTypeNodeHelper(indexedType); + const indexTypeNode = typeToTypeNodeHelper(indexedType, context); return createTypeOperatorNode(indexTypeNode); } if (type.flags & TypeFlags.IndexedAccess) { - const objectTypeNode = typeToTypeNodeHelper((type).objectType); - const indexTypeNode = typeToTypeNodeHelper((type).indexType); + const objectTypeNode = typeToTypeNodeHelper((type).objectType, context); + const indexTypeNode = typeToTypeNodeHelper((type).indexType, context); return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); } @@ -2374,7 +2394,7 @@ namespace ts { function mapToTypeNodeArray(types: Type[]): TypeNode[] { const result = []; for (const type of types) { - const typeNode = typeToTypeNodeHelper(type); + const typeNode = typeToTypeNodeHelper(type, context); if (typeNode) { result.push(typeNode); } @@ -2385,10 +2405,10 @@ namespace ts { function createMappedTypeNodeFromType(type: MappedType) { Debug.assert(!!(type.flags & TypeFlags.Object)); const typeParameter = getTypeParameterFromMappedType(type); - const typeParameterNode = typeParameterToDeclaration(typeParameter); + const typeParameterNode = typeParameterToDeclaration(typeParameter, context); const templateType = getTemplateTypeFromMappedType(type); - const templateTypeNode = typeToTypeNodeHelper(templateType); + const templateTypeNode = typeToTypeNodeHelper(templateType, context); const readonlyToken = type.declaration && type.declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined; const questionToken = type.declaration && type.declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined; @@ -2409,7 +2429,7 @@ namespace ts { const typeAlias = getTypeAliasForTypeLiteral(type); if (typeAlias) { // The specified symbol flags need to be reinterpreted as type flags - const entityName = symbolToName(typeAlias, /*expectsIdentifier*/ false); + const entityName = symbolToName(typeAlias, /*expectsIdentifier*/ false, context); return createTypeReferenceNode(entityName, /*typeArguments*/ undefined); } else { @@ -2462,11 +2482,11 @@ namespace ts { if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { const signature = resolved.callSignatures[0]; - return signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType); + return signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context); } if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { const signature = resolved.constructSignatures[0]; - return signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType); + return signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, context); } } @@ -2478,14 +2498,14 @@ namespace ts { } function createTypeQueryNodeFromSymbol(symbol: Symbol) { - const entityName = symbolToName(symbol, /*expectsIdentifier*/ false); + const entityName = symbolToName(symbol, /*expectsIdentifier*/ false, context); return createTypeQueryNode(entityName); } function typeReferenceToTypeNode(type: TypeReference) { const typeArguments: Type[] = type.typeArguments || emptyArray; if (type.target === globalArrayType) { - const elementType = typeToTypeNodeHelper(typeArguments[0]); + const elementType = typeToTypeNodeHelper(typeArguments[0], context); return createArrayTypeNode(elementType); } else if (type.target.objectFlags & ObjectFlags.Tuple) { @@ -2516,7 +2536,7 @@ namespace ts { // When type parameters are their own type arguments for the whole group (i.e. we have // the default outer type arguments), we don't show the group. if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { - const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true); + const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true, context); if (!qualifiedName) { qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined); } @@ -2529,7 +2549,7 @@ namespace ts { } } let entityName: EntityName = undefined; - const nameIdentifier = symbolToName(type.symbol, /*expectsIdentifier*/ true); + const nameIdentifier = symbolToName(type.symbol, /*expectsIdentifier*/ true, context); if (qualifiedName) { Debug.assert(!qualifiedName.right); qualifiedName.right = nameIdentifier; @@ -2547,16 +2567,16 @@ namespace ts { function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] { const typeElements: TypeElement[] = []; for (const signature of resolvedType.callSignatures) { - typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature)); + typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, context)); } for (const signature of resolvedType.constructSignatures) { - typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature)); + typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature, context)); } if (resolvedType.stringIndexInfo) { - typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.stringIndexInfo, IndexKind.String)); + typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.stringIndexInfo, IndexKind.String, context)); } if (resolvedType.numberIndexInfo) { - typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.numberIndexInfo, IndexKind.Number)); + typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.numberIndexInfo, IndexKind.Number, context)); } const properties = resolvedType.properties; @@ -2570,12 +2590,12 @@ namespace ts { if (!oldDeclaration) { return; } - const propertyName = oldDeclaration.name; + const propertyName = getDeepSynthesizedClone(oldDeclaration.name); const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined; if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) { const signatures = getSignaturesOfType(propertyType, SignatureKind.Call); for (const signature of signatures) { - const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature); + const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context); methodDeclaration.name = propertyName; methodDeclaration.questionToken = optionalToken; typeElements.push(methodDeclaration); @@ -2584,7 +2604,7 @@ namespace ts { else { // TODO(aozgaa): should we create a node with explicit or implict any? - const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType) : createKeywordTypeNode(SyntaxKind.AnyKeyword); + const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword); typeElements.push(createPropertySignature( propertyName, optionalToken, @@ -2596,7 +2616,7 @@ namespace ts { } } - function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind): IndexSignatureDeclaration { + function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, context: NodeBuilderContext): IndexSignatureDeclaration { const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword); const name = getNameFromIndexInfo(indexInfo); @@ -2608,7 +2628,7 @@ namespace ts { /*questionToken*/ undefined, indexerTypeNode, /*initializer*/ undefined); - const typeNode = typeToTypeNodeHelper(indexInfo.type); + const typeNode = typeToTypeNodeHelper(indexInfo.type, context); return createIndexSignatureDeclaration( /*decorators*/ undefined, indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined, @@ -2616,55 +2636,62 @@ namespace ts { typeNode); } - function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind): SignatureDeclaration { + function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind, context: NodeBuilderContext): SignatureDeclaration { - const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter)); - const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter)); - let returnTypeNode: TypeNode | TypePredicate; + const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context)); + const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter, context)); + let returnTypeNode: TypeNode; if (signature.typePredicate) { const typePredicate = signature.typePredicate; const parameterName = typePredicate.kind === TypePredicateKind.Identifier ? createIdentifier((typePredicate).parameterName) : createThisTypeNode(); - const typeNode = typeToTypeNodeHelper(typePredicate.type); + const typeNode = typeToTypeNodeHelper(typePredicate.type, context); returnTypeNode = createTypePredicateNode(parameterName, typeNode); } else { const returnType = getReturnTypeOfSignature(signature); - returnTypeNode = returnType && typeToTypeNodeHelper(returnType); + returnTypeNode = returnType && typeToTypeNodeHelper(returnType, context); } - const returnTypeNodeExceptAny = returnTypeNode && returnTypeNode.kind !== SyntaxKind.AnyKeyword ? returnTypeNode : undefined; - - return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNodeExceptAny); + if(context.flags & NodeBuilderFlags.suppressAnyReturnType) { + if(returnTypeNode && returnTypeNode.kind === SyntaxKind.AnyKeyword) { + returnTypeNode = undefined; + } + } + else if (!returnTypeNode) { + returnTypeNode = createKeywordTypeNode(SyntaxKind.AnyKeyword); + } + return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNode); } - function typeParameterToDeclaration(type: TypeParameter): TypeParameterDeclaration { + function typeParameterToDeclaration(type: TypeParameter, context: NodeBuilderContext): TypeParameterDeclaration { const constraint = getConstraintFromTypeParameter(type); - const constraintNode = constraint && typeToTypeNodeHelper(constraint); + const constraintNode = constraint && typeToTypeNodeHelper(constraint, context); const defaultParameter = getDefaultFromTypeParameter(type); - const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter); - const name = symbolToName(type.symbol, /*expectsIdentifier*/ true); + const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, context); + const name = symbolToName(type.symbol, /*expectsIdentifier*/ true, context); return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode); } - function symbolToParameterDeclaration(parameterSymbol: Symbol): ParameterDeclaration { + function symbolToParameterDeclaration(parameterSymbol: Symbol, context: NodeBuilderContext): ParameterDeclaration { const parameterDeclaration = getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter); const parameterType = getTypeOfSymbol(parameterSymbol); - const parameterTypeNode = typeToTypeNodeHelper(parameterType); + const parameterTypeNode = typeToTypeNodeHelper(parameterType, context); + const name = getDeepSynthesizedClone(parameterDeclaration.name); // TODO(aozgaa): In the future, check initializer accessibility. const parameterNode = createParameter( parameterDeclaration.decorators, parameterDeclaration.modifiers, parameterDeclaration.dotDotDotToken && createToken(SyntaxKind.DotDotDotToken), // Clone name to remove trivia. - getSynthesizedClone(parameterDeclaration.name), + name, parameterDeclaration.questionToken && createToken(SyntaxKind.QuestionToken), parameterTypeNode, parameterDeclaration.initializer); return parameterNode; } - function symbolToName(symbol: Symbol, expectsIdentifier: true): Identifier; - function symbolToName(symbol: Symbol, expectsIdentifier: false): EntityName; - function symbolToName(symbol: Symbol, expectsIdentifier: boolean): EntityName { + function symbolToName(symbol: Symbol, expectsIdentifier: true, context: NodeBuilderContext): Identifier; + function symbolToName(symbol: Symbol, expectsIdentifier: false, context: NodeBuilderContext): EntityName; + function symbolToName(symbol: Symbol, expectsIdentifier: boolean, context: NodeBuilderContext): EntityName { // Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration. let chain: Symbol[]; @@ -2714,7 +2741,7 @@ namespace ts { } } - const symbolName = getNameOfSymbol(symbol); + const symbolName = getNameOfSymbol(symbol, context); const symbolNameWithTypeParameters = typeParameterString.length > 0 ? `${symbolName}<${typeParameterString}>` : symbolName; const identifier = createIdentifier(symbolNameWithTypeParameters); @@ -2754,29 +2781,28 @@ namespace ts { return [symbol]; } } - - function getNameOfSymbol(symbol: Symbol): string { - const declaration = firstOrUndefined(symbol.declarations); - if (declaration) { - if (declaration.name) { - return declarationNameToString(declaration.name); - } - if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) { - return declarationNameToString((declaration.parent).name); - } - if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowAnonymousIdentifier)) { - context.encounteredError = true; - } - switch (declaration.kind) { - case SyntaxKind.ClassExpression: - return "(Anonymous class)"; - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - return "(Anonymous function)"; - } + } + function getNameOfSymbol(symbol: Symbol, context: NodeBuilderContext): string { + const declaration = firstOrUndefined(symbol.declarations); + if (declaration) { + if (declaration.name) { + return declarationNameToString(declaration.name); + } + if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) { + return declarationNameToString((declaration.parent).name); + } + if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowAnonymousIdentifier)) { + context.encounteredError = true; + } + switch (declaration.kind) { + case SyntaxKind.ClassExpression: + return "(Anonymous class)"; + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + return "(Anonymous function)"; } - return symbol.name; } + return symbol.name; } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 616be35270..f72d2bb19c 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -213,7 +213,7 @@ namespace ts { emitLeadingCommentsOfPosition, } = comments; - let currentSourceFile: SourceFile; + let currentSourceFile: SourceFile | undefined; let nodeIdToGeneratedName: string[]; // Map of generated names for specific nodes. let autoGeneratedIdToGeneratedName: string[]; // Map of generated names for temp and loop variables. let generatedNames: Map; // Set of names generated by the NameGenerator. @@ -235,7 +235,7 @@ namespace ts { writeBundle }; - function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string { + function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined): string { switch (hint) { case EmitHint.SourceFile: Debug.assert(isSourceFile(node), "Expected a SourceFile node."); @@ -265,7 +265,7 @@ namespace ts { return endPrint(); } - function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile, output: EmitTextWriter) { + function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, output: EmitTextWriter) { const previousWriter = writer; setWriter(output); print(hint, node, sourceFile); @@ -302,8 +302,10 @@ namespace ts { return text; } - function print(hint: EmitHint, node: Node, sourceFile: SourceFile) { - setSourceFile(sourceFile); + function print(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined) { + if (sourceFile) { + setSourceFile(sourceFile); + } pipelineEmitWithNotification(hint, node); } @@ -1101,7 +1103,7 @@ namespace ts { function emitPropertyAccessExpression(node: PropertyAccessExpression) { let indentBeforeDot = false; let indentAfterDot = false; - if (!(getEmitFlags(node) & EmitFlags.NoIndentation)) { + if (currentSourceFile && !(getEmitFlags(node) & EmitFlags.NoIndentation)) { const dotRangeStart = node.expression.end; const dotRangeEnd = skipTrivia(currentSourceFile.text, node.expression.end) + 1; const dotToken = { kind: SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd }; @@ -2461,7 +2463,7 @@ namespace ts { const firstChild = children[0]; if (firstChild === undefined) { - return !rangeIsOnSingleLine(parentNode, currentSourceFile); + return !(currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile)); } else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(firstChild)) { return synthesizedNodeStartsOnNewLine(firstChild, format); @@ -2487,7 +2489,7 @@ namespace ts { return synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format); } else { - return !rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile); + return !(currentSourceFile && rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile)); } } else { @@ -2506,13 +2508,13 @@ namespace ts { const lastChild = lastOrUndefined(children); if (lastChild === undefined) { - return !rangeIsOnSingleLine(parentNode, currentSourceFile); + return !(currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile)); } else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(lastChild)) { return synthesizedNodeStartsOnNewLine(lastChild, format); } else { - return !rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile); + return !(currentSourceFile && rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile)); } } else { @@ -2901,7 +2903,7 @@ namespace ts { // Precomputed Formats Modifiers = SingleLine | SpaceBetweenSiblings, HeritageClauses = SingleLine | SpaceBetweenSiblings, - TypeLiteralMembers = MultiLine | Indented, + TypeLiteralMembers = SpaceBetweenBraces | SpaceBetweenSiblings | Indented, // MultiLine | Indented, TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented, UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine, IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine, diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 66b3eb713e..4bf4d1a951 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2,6 +2,26 @@ /// namespace ts { + export const nullTransformationContext: TransformationContext = { + enableEmitNotification: noop, + enableSubstitution: noop, + endLexicalEnvironment: () => undefined, + getCompilerOptions: notImplemented, + getEmitHost: notImplemented, + getEmitResolver: notImplemented, + hoistFunctionDeclaration: noop, + hoistVariableDeclaration: noop, + isEmitNotificationEnabled: notImplemented, + isSubstitutionEnabled: notImplemented, + onEmitNode: noop, + onSubstituteNode: notImplemented, + readEmitHelpers: notImplemented, + requestEmitHelper: noop, + resumeLexicalEnvironment: noop, + startLexicalEnvironment: noop, + suspendLexicalEnvironment: noop + }; + function createSynthesizedNode(kind: SyntaxKind): Node { const node = createNode(kind, -1, -1); node.flags |= NodeFlags.Synthesized; @@ -64,6 +84,11 @@ namespace ts { return clone; } + export function getDeepSynthesizedClone(node: T | undefined): T { + const clone = visitEachChild(node, getDeepSynthesizedClone, nullTransformationContext, /*nodeVisitor*/ undefined, getSynthesizedClone); + return nodeIsSynthesized(clone) ? clone : getSynthesizedClone(clone); + } + // Literals export function createLiteral(value: string): StringLiteral; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 038f8bf316..12b9d333e3 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2541,8 +2541,10 @@ namespace ts { allowQualifedNameInPlaceOfIdentifier = 1 << 1, allowTypeParameterInQualifiedName = 1 << 2, allowAnonymousIdentifier = 1 << 3, - allowEmptyUnionOrIntersection = 1 << 4, - allowEmptyTuple = 1 << 5 + allowEmptyUnionOrIntersection = 1 << 4, + allowEmptyTuple = 1 << 5, + suppressAnyReturnType = 1 << 6, + ignoreErrors = allowThisInObjectLiteral | allowQualifedNameInPlaceOfIdentifier | allowTypeParameterInQualifiedName | allowAnonymousIdentifier | allowEmptyUnionOrIntersection | allowEmptyTuple } export interface SymbolDisplayBuilder { @@ -3470,6 +3472,7 @@ namespace ts { export const enum NewLineKind { CarriageReturnLineFeed = 0, LineFeed = 1, + None = 2 } export interface LineAndCharacter { @@ -4115,7 +4118,7 @@ namespace ts { * the identifiers of the source file are used when generating unique names to avoid * collisions. */ - printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string; + printNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined): string; /** * Prints a source file as-is, without any emit transformations. */ @@ -4124,7 +4127,7 @@ namespace ts { * Prints a bundle of source files as-is, without any emit transformations. */ printBundle(bundle: Bundle): string; - /*@internal*/ writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile, writer: EmitTextWriter): void; + /*@internal*/ writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, writer: EmitTextWriter): void; /*@internal*/ writeFile(sourceFile: SourceFile, writer: EmitTextWriter): void; /*@internal*/ writeBundle(bundle: Bundle, writer: EmitTextWriter): void; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 33cb0d8f48..9e39e66b64 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3272,13 +3272,15 @@ namespace ts { const carriageReturnLineFeed = "\r\n"; const lineFeed = "\n"; export function getNewLineCharacter(options: CompilerOptions | PrinterOptions): string { - if (options.newLine === NewLineKind.CarriageReturnLineFeed) { - return carriageReturnLineFeed; + switch (options.newLine) { + case NewLineKind.None: + return ""; + case NewLineKind.CarriageReturnLineFeed: + return carriageReturnLineFeed; + case NewLineKind.LineFeed: + return lineFeed; } - else if (options.newLine === NewLineKind.LineFeed) { - return lineFeed; - } - else if (sys) { + if (sys) { return sys.newLine; } return carriageReturnLineFeed; diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index b836815fc2..631fb560cd 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -130,7 +130,7 @@ namespace ts.codefix { } function signatureToMethodDeclaration(signature: Signature, enclosingDeclaration: Node, body?: Block) { - const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration); + const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration, NodeBuilderFlags.suppressAnyReturnType); if (signatureDeclaration) { signatureDeclaration.decorators = undefined; signatureDeclaration.modifiers = modifiers; diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index afc9892749..63e3a95bf1 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -497,8 +497,8 @@ namespace ts.textChanges { readonly node: Node; } - export function getNonformattedText(node: Node, sourceFile: SourceFile, newLine: NewLineKind): NonFormattedText { - const options = { newLine, target: sourceFile.languageVersion }; + export function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLine: NewLineKind): NonFormattedText { + const options = { newLine, target: sourceFile && sourceFile.languageVersion }; const writer = new Writer(getNewLineCharacter(options)); const printer = createPrinter(options, writer); printer.writeNode(EmitHint.Unspecified, node, sourceFile, writer); @@ -528,26 +528,6 @@ namespace ts.textChanges { return skipTrivia(s, 0) === s.length; } - const nullTransformationContext: TransformationContext = { - enableEmitNotification: noop, - enableSubstitution: noop, - endLexicalEnvironment: () => undefined, - getCompilerOptions: notImplemented, - getEmitHost: notImplemented, - getEmitResolver: notImplemented, - hoistFunctionDeclaration: noop, - hoistVariableDeclaration: noop, - isEmitNotificationEnabled: notImplemented, - isSubstitutionEnabled: notImplemented, - onEmitNode: noop, - onSubstituteNode: notImplemented, - readEmitHelpers: notImplemented, - requestEmitHelper: noop, - resumeLexicalEnvironment: noop, - startLexicalEnvironment: noop, - suspendLexicalEnvironment: noop - }; - function assignPositionsToNode(node: Node): Node { const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray, assignPositionsToNode); // create proxy node for non synthesized nodes From 55388d16b4c9de3686465c857eeb3d6db33f1492 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Wed, 19 Apr 2017 10:36:40 -0700 Subject: [PATCH 03/83] Readonly type literal members --- src/compiler/checker.ts | 9 ++++++--- src/compiler/factory.ts | 10 ++++++---- src/compiler/visitor.ts | 2 ++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 28ba350f38..0fd0925102 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2602,14 +2602,17 @@ namespace ts { } } else { - // TODO(aozgaa): should we create a node with explicit or implict any? const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword); - typeElements.push(createPropertySignature( + + const modifiers = isReadonlySymbol(propertySymbol) ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined; + const propertySignature = createPropertySignature( + modifiers, propertyName, optionalToken, propertyTypeNode, - /*initializer*/undefined)); + /*initializer*/undefined); + typeElements.push(propertySignature); } } return typeElements.length ? typeElements : undefined; diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 4bf4d1a951..6b265c03d2 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -480,8 +480,9 @@ namespace ts { // Signature elements - export function createPropertySignature(name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertySignature { + export function createPropertySignature(modifiers: Modifier[] | undefined, name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertySignature { const propertySignature = createSynthesizedNode(SyntaxKind.PropertySignature) as PropertySignature; + propertySignature.modifiers = asNodeArray(modifiers); propertySignature.name = asName(name); propertySignature.questionToken = questionToken; propertySignature.type = type; @@ -489,12 +490,13 @@ namespace ts { return propertySignature; } - export function updatePropertySignature(node: PropertySignature, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { - return node.name !== name + export function updatePropertySignature(node: PropertySignature, modifiers: Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { + return node.modifiers !== modifiers + || node.name !== name || node.questionToken !== questionToken || node.type !== type || node.initializer !== initializer - ? updateNode(createPropertySignature(name, questionToken, type, initializer), node) + ? updateNode(createPropertySignature(modifiers, name, questionToken, type, initializer), node) : node; } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 297d2cc0dd..523d4cb8e3 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -355,6 +355,8 @@ namespace ts { case SyntaxKind.PropertySignature: return updatePropertySignature((node), + // TODO: tokenVisitor or visitor for a nodearray of tokens? + nodesVisitor((node).modifiers, visitor, isToken), visitNode((node).name, visitor, isPropertyName), visitNode((node).questionToken, tokenVisitor, isToken), visitNode((node).type, visitor, isTypeNode), From 10afa2f6420202507bb4eb453878bfa5886046dc Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Wed, 19 Apr 2017 11:11:19 -0700 Subject: [PATCH 04/83] No space in empty type litereal --- src/compiler/emitter.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index f283bc0217..afafee51bf 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -954,7 +954,9 @@ namespace ts { function emitTypeLiteral(node: TypeLiteralNode) { write("{"); - emitList(node, node.members, ListFormat.TypeLiteralMembers); + if (node.members.length > 0) { + emitList(node, node.members, ListFormat.SingleLineTypeLiteralMembers); + } write("}"); } @@ -2945,7 +2947,8 @@ namespace ts { // Precomputed Formats Modifiers = SingleLine | SpaceBetweenSiblings, HeritageClauses = SingleLine | SpaceBetweenSiblings, - TypeLiteralMembers = SpaceBetweenBraces | SpaceBetweenSiblings | Indented, // MultiLine | Indented, + SingleLineTypeLiteralMembers = SpaceBetweenBraces | SpaceBetweenSiblings | Indented, // MultiLine | Indented, + MultiLineTypeLiteralMembers = MultiLine | Indented, TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented, UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine, IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine, From d0f371659004673b7c767ec0511143f69682e36c Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Wed, 19 Apr 2017 11:11:26 -0700 Subject: [PATCH 05/83] typo --- src/compiler/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4d8e886b2c..53507e3aa3 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2572,7 +2572,7 @@ namespace ts { export interface SymbolDisplayBuilder { buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void; - buildSignatureDisplay(signatures: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): void; + buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): void; buildIndexSignatureDisplay(info: IndexInfo, writer: SymbolWriter, kind: IndexKind, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]): void; buildParameterDisplay(parameter: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; From 8a1456ff7585ed87dc00e023d6168993dd36ee45 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 25 Apr 2017 14:55:31 -0700 Subject: [PATCH 06/83] Clean up computeEnumMemberValues function --- src/compiler/checker.ts | 281 ++++++++++++++++------------------------ 1 file changed, 112 insertions(+), 169 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 18e57303c1..a3e65b4eb6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20669,107 +20669,86 @@ namespace ts { function computeEnumMemberValues(node: EnumDeclaration) { const nodeLinks = getNodeLinks(node); - if (!(nodeLinks.flags & NodeCheckFlags.EnumValuesComputed)) { - const enumSymbol = getSymbolOfNode(node); - const enumType = getDeclaredTypeOfSymbol(enumSymbol); - let autoValue = 0; // set to undefined when enum member is non-constant - const ambient = isInAmbientContext(node); - const enumIsConst = isConst(node); - - for (const member of node.members) { - if (isComputedNonLiteralName(member.name)) { - error(member.name, Diagnostics.Computed_property_names_are_not_allowed_in_enums); - } - else { - const text = getTextOfPropertyName(member.name); - if (isNumericLiteralName(text) && !isInfinityOrNaNString(text)) { - error(member.name, Diagnostics.An_enum_member_cannot_have_a_numeric_name); - } - } - - const previousEnumMemberIsNonConstant = autoValue === undefined; - - const initializer = member.initializer; - if (initializer) { - autoValue = computeConstantValueForEnumMemberInitializer(initializer, enumType, enumIsConst, ambient); - } - else if (ambient && !enumIsConst) { - // In ambient enum declarations that specify no const modifier, enum member declarations - // that omit a value are considered computed members (as opposed to having auto-incremented values assigned). - autoValue = undefined; - } - else if (previousEnumMemberIsNonConstant) { - // If the member declaration specifies no value, the member is considered a constant enum member. - // If the member is the first member in the enum declaration, it is assigned the value zero. - // Otherwise, it is assigned the value of the immediately preceding member plus one, - // and an error occurs if the immediately preceding member is not a constant enum member - error(member.name, Diagnostics.Enum_member_must_have_initializer); - } - - if (autoValue !== undefined) { - getNodeLinks(member).enumMemberValue = autoValue; - autoValue++; - } - } - nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed; - } - - function computeConstantValueForEnumMemberInitializer(initializer: Expression, enumType: Type, enumIsConst: boolean, ambient: boolean): number { - // Controls if error should be reported after evaluation of constant value is completed - // Can be false if another more precise error was already reported during evaluation. - let reportError = true; - const value = evalConstant(initializer); - - if (reportError) { - if (value === undefined) { - if (enumIsConst) { - error(initializer, Diagnostics.In_const_enum_declarations_member_initializer_must_be_constant_expression); - } - else if (ambient) { - error(initializer, Diagnostics.In_ambient_enum_declarations_member_initializer_must_be_constant_expression); - } - else { - // Only here do we need to check that the initializer is assignable to the enum type. - checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*headMessage*/ undefined); - } - } - else if (enumIsConst) { - if (isNaN(value)) { - error(initializer, Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN); - } - else if (!isFinite(value)) { - error(initializer, Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value); - } - } + let autoValue = 0; + for (const member of node.members) { + const value = computeMemberValue(member, autoValue); + getNodeLinks(member).enumMemberValue = value; + autoValue = typeof value === "number" ? value + 1 : undefined; } + } + } - return value; + function computeMemberValue(member: EnumMember, autoValue: number) { + if (isComputedNonLiteralName(member.name)) { + error(member.name, Diagnostics.Computed_property_names_are_not_allowed_in_enums); + } + else { + const text = getTextOfPropertyName(member.name); + if (isNumericLiteralName(text) && !isInfinityOrNaNString(text)) { + error(member.name, Diagnostics.An_enum_member_cannot_have_a_numeric_name); + } + } + if (member.initializer) { + return computeConstantValue(member); + } + // In ambient enum declarations that specify no const modifier, enum member declarations that omit + // a value are considered computed members (as opposed to having auto-incremented values). + if (isInAmbientContext(member.parent) && !isConst(member.parent)) { + return undefined; + } + // If the member declaration specifies no value, the member is considered a constant enum member. + // If the member is the first member in the enum declaration, it is assigned the value zero. + // Otherwise, it is assigned the value of the immediately preceding member plus one, and an error + // occurs if the immediately preceding member is not a constant enum member. + if (autoValue !== undefined) { + return autoValue; + } + error(member.name, Diagnostics.Enum_member_must_have_initializer); + return undefined; + } - function evalConstant(e: Node): number { - switch (e.kind) { - case SyntaxKind.PrefixUnaryExpression: - const value = evalConstant((e).operand); - if (value === undefined) { - return undefined; - } - switch ((e).operator) { + function computeConstantValue(member: EnumMember): number { + const isConstEnum = isConst(member.parent); + const initializer = member.initializer; + const value = evaluate(member.initializer); + if (value !== undefined) { + if (isConstEnum && !isFinite(value)) { + error(initializer, isNaN(value) ? + Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN : + Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value); + } + } + else if (isConstEnum) { + error(initializer, Diagnostics.In_const_enum_declarations_member_initializer_must_be_constant_expression); + } + else if (isInAmbientContext(member.parent)) { + error(initializer, Diagnostics.In_ambient_enum_declarations_member_initializer_must_be_constant_expression); + } + else { + // Only here do we need to check that the initializer is assignable to the enum type. + checkTypeAssignableTo(checkExpression(initializer), getDeclaredTypeOfSymbol(getSymbolOfNode(member.parent)), initializer, /*headMessage*/ undefined); + } + return value; + + function evaluate(expr: Expression): number { + switch (expr.kind) { + case SyntaxKind.PrefixUnaryExpression: + const value = evaluate((expr).operand); + if (typeof value === "number") { + switch ((expr).operator) { case SyntaxKind.PlusToken: return value; case SyntaxKind.MinusToken: return -value; case SyntaxKind.TildeToken: return ~value; } - return undefined; - case SyntaxKind.BinaryExpression: - const left = evalConstant((e).left); - if (left === undefined) { - return undefined; - } - const right = evalConstant((e).right); - if (right === undefined) { - return undefined; - } - switch ((e).operatorToken.kind) { + } + break; + case SyntaxKind.BinaryExpression: + const left = evaluate((expr).left); + const right = evaluate((expr).right); + if (typeof left === "number" && typeof right === "number") { + switch ((expr).operatorToken.kind) { case SyntaxKind.BarToken: return left | right; case SyntaxKind.AmpersandToken: return left & right; case SyntaxKind.GreaterThanGreaterThanToken: return left >> right; @@ -20782,90 +20761,54 @@ namespace ts { case SyntaxKind.MinusToken: return left - right; case SyntaxKind.PercentToken: return left % right; } - return undefined; - case SyntaxKind.NumericLiteral: - checkGrammarNumericLiteral(e); - return +(e).text; - case SyntaxKind.ParenthesizedExpression: - return evalConstant((e).expression); - case SyntaxKind.Identifier: - case SyntaxKind.ElementAccessExpression: - case SyntaxKind.PropertyAccessExpression: - const member = initializer.parent; - const currentType = getTypeOfSymbol(getSymbolOfNode(member.parent)); - let enumType: Type; - let propertyName: string; - - if (e.kind === SyntaxKind.Identifier) { - // unqualified names can refer to member that reside in different declaration of the enum so just doing name resolution won't work. - // instead pick current enum type and later try to fetch member from the type - enumType = currentType; - propertyName = (e).text; + } + break; + case SyntaxKind.NumericLiteral: + checkGrammarNumericLiteral(expr); + return +(expr).text; + case SyntaxKind.ParenthesizedExpression: + return evaluate((expr).expression); + case SyntaxKind.Identifier: + return evaluateEnumMember(expr, getSymbolOfNode(member.parent), (expr).text); + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.PropertyAccessExpression: + if (isConstantMemberAccess(expr)) { + const type = getTypeOfExpression((expr).expression); + if (type.symbol && type.symbol.flags & SymbolFlags.Enum) { + const name = expr.kind === SyntaxKind.PropertyAccessExpression ? + (expr).name.text : + ((expr).argumentExpression).text; + return evaluateEnumMember(expr, type.symbol, name); } - else { - let expression: Expression; - if (e.kind === SyntaxKind.ElementAccessExpression) { - if ((e).argumentExpression === undefined || - (e).argumentExpression.kind !== SyntaxKind.StringLiteral) { - return undefined; - } - expression = (e).expression; - propertyName = ((e).argumentExpression).text; - } - else { - expression = (e).expression; - propertyName = (e).name.text; - } + } + break; + } + return undefined; + } - // expression part in ElementAccess\PropertyAccess should be either identifier or dottedName - let current = expression; - while (current) { - if (current.kind === SyntaxKind.Identifier) { - break; - } - else if (current.kind === SyntaxKind.PropertyAccessExpression) { - current = (current).expression; - } - else { - return undefined; - } - } - - enumType = getTypeOfExpression(expression); - // allow references to constant members of other enums - if (!(enumType.symbol && (enumType.symbol.flags & SymbolFlags.Enum))) { - return undefined; - } - } - - if (propertyName === undefined) { - return undefined; - } - - const property = getPropertyOfObjectType(enumType, propertyName); - if (!property || !(property.flags & SymbolFlags.EnumMember)) { - return undefined; - } - - const propertyDecl = property.valueDeclaration; - // self references are illegal - if (member === propertyDecl) { - return undefined; - } - - // illegal case: forward reference - if (!isBlockScopedNameDeclaredBeforeUse(propertyDecl, member)) { - reportError = false; - error(e, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums); - return undefined; - } - - return getNodeLinks(propertyDecl).enumMemberValue; + function evaluateEnumMember(expr: Expression, enumSymbol: Symbol, name: string) { + const memberSymbol = enumSymbol.exports.get(name); + if (memberSymbol) { + const declaration = memberSymbol.valueDeclaration; + if (declaration !== member) { + if (isBlockScopedNameDeclaredBeforeUse(declaration, member)) { + return getNodeLinks(declaration).enumMemberValue; + } + error(expr, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums); + return 0; } } + return undefined; } } + function isConstantMemberAccess(node: Expression): boolean { + return node.kind === SyntaxKind.Identifier || + node.kind === SyntaxKind.PropertyAccessExpression && isConstantMemberAccess((node).expression) || + node.kind === SyntaxKind.ElementAccessExpression && isConstantMemberAccess((node).expression) && + (node).argumentExpression.kind === SyntaxKind.StringLiteral; + } + function checkEnumDeclaration(node: EnumDeclaration) { if (!produceDiagnostics) { return; From f61efe5e19d35d81d5baa11d4539f92df5e50806 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 25 Apr 2017 14:55:51 -0700 Subject: [PATCH 07/83] Accept new baselines --- tests/baselines/reference/forwardRefInEnum.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/forwardRefInEnum.js b/tests/baselines/reference/forwardRefInEnum.js index 555454dcca..592adbd253 100644 --- a/tests/baselines/reference/forwardRefInEnum.js +++ b/tests/baselines/reference/forwardRefInEnum.js @@ -19,11 +19,11 @@ var E1; (function (E1) { // illegal case // forward reference to the element of the same enum - E1[E1["X"] = E1.Y] = "X"; - E1[E1["X1"] = E1["Y"]] = "X1"; + E1[E1["X"] = 0] = "X"; + E1[E1["X1"] = 0] = "X1"; // forward reference to the element of the same enum - E1[E1["Y"] = E1.Z] = "Y"; - E1[E1["Y1"] = E1["Z"]] = "Y1"; + E1[E1["Y"] = 0] = "Y"; + E1[E1["Y1"] = 0] = "Y1"; })(E1 || (E1 = {})); (function (E1) { E1[E1["Z"] = 4] = "Z"; From 19a1c2ca612001d2fe956dce60f7f963441a346e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 26 Apr 2017 14:18:11 -0700 Subject: [PATCH 08/83] Store actual literal value in LiteralType instances --- src/compiler/checker.ts | 64 ++++++++++++++++++------------------- src/compiler/types.ts | 10 +++++- src/services/completions.ts | 2 +- 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a3e65b4eb6..be72d9d657 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -309,8 +309,8 @@ namespace ts { let flowLoopCount = 0; let visitedFlowCount = 0; - const emptyStringType = getLiteralTypeForText(TypeFlags.StringLiteral, ""); - const zeroType = getLiteralTypeForText(TypeFlags.NumberLiteral, "0"); + const emptyStringType = getLiteralType(""); + const zeroType = getLiteralType(0); const resolutionTargets: TypeSystemEntity[] = []; const resolutionResults: boolean[] = []; @@ -1869,7 +1869,7 @@ namespace ts { } function createTypeofType() { - return getUnionType(convertToArray(typeofEQFacts.keys(), s => getLiteralTypeForText(TypeFlags.StringLiteral, s))); + return getUnionType(convertToArray(typeofEQFacts.keys(), getLiteralType)); } // A reserved member name starts with two underscores, but the third character cannot be an underscore @@ -2320,11 +2320,8 @@ namespace ts { const name = symbolToName(type.symbol, /*expectsIdentifier*/ false); return createTypeReferenceNode(name, /*typeArguments*/ undefined); } - if (type.flags & (TypeFlags.StringLiteral)) { - return createLiteralTypeNode((createLiteral((type).text))); - } - if (type.flags & (TypeFlags.NumberLiteral)) { - return createLiteralTypeNode((createNumericLiteral((type).text))); + if (type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { + return createLiteralTypeNode(createLiteral((type).value)); } if (type.flags & TypeFlags.BooleanLiteral) { return (type).intrinsicName === "true" ? createTrue() : createFalse(); @@ -2891,7 +2888,7 @@ namespace ts { } function literalTypeToString(type: LiteralType) { - return type.flags & TypeFlags.StringLiteral ? `"${escapeString((type).text)}"` : (type).text; + return type.flags & TypeFlags.StringLiteral ? `"${escapeString((type).value)}"` : "" + (type).value; } function getNameOfSymbol(symbol: Symbol): string { @@ -4933,11 +4930,11 @@ namespace ts { return true; } - function createEnumLiteralType(symbol: Symbol, baseType: EnumType, text: string) { + function createEnumLiteralType(symbol: Symbol, baseType: EnumType, value: number) { const type = createType(TypeFlags.EnumLiteral); type.symbol = symbol; type.baseType = baseType; - type.text = text; + type.value = value; return type; } @@ -4956,7 +4953,7 @@ namespace ts { const memberSymbol = getSymbolOfNode(member); const value = getEnumMemberValue(member); if (!memberTypes[value]) { - const memberType = memberTypes[value] = createEnumLiteralType(memberSymbol, enumType, "" + value); + const memberType = memberTypes[value] = createEnumLiteralType(memberSymbol, enumType, value); memberTypeList.push(memberType); } } @@ -5510,7 +5507,7 @@ namespace ts { // If the current iteration type constituent is a string literal type, create a property. // Otherwise, for type string create a string index signature. if (t.flags & TypeFlags.StringLiteral) { - const propName = (t).text; + const propName = (t).value; const modifiersProp = getPropertyOfType(modifiersType, propName); const isOptional = templateOptional || !!(modifiersProp && modifiersProp.flags & SymbolFlags.Optional); const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName); @@ -7216,7 +7213,7 @@ namespace ts { function getLiteralTypeFromPropertyName(prop: Symbol) { return getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier || startsWith(prop.name, "__@") ? neverType : - getLiteralTypeForText(TypeFlags.StringLiteral, unescapeIdentifier(prop.name)); + getLiteralType(unescapeIdentifier(prop.name)); } function getLiteralTypeFromPropertyNames(type: Type) { @@ -7253,7 +7250,7 @@ namespace ts { function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) { const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; const propName = indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral) ? - (indexType).text : + "" + (indexType).value : accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ? getPropertyNameForKnownSymbolName(((accessExpression.argumentExpression).name).text) : undefined; @@ -7301,7 +7298,7 @@ namespace ts { if (accessNode) { const indexNode = accessNode.kind === SyntaxKind.ElementAccessExpression ? (accessNode).argumentExpression : (accessNode).indexType; if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { - error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType).text, typeToString(objectType)); + error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, "" + (indexType).value, typeToString(objectType)); } else if (indexType.flags & (TypeFlags.String | TypeFlags.Number)) { error(indexNode, Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, typeToString(objectType), typeToString(indexType)); @@ -7512,16 +7509,16 @@ namespace ts { return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent)); } - function createLiteralType(flags: TypeFlags, text: string) { + function createLiteralType(flags: TypeFlags, value: string | number) { const type = createType(flags); - type.text = text; + type.value = value; return type; } function getFreshTypeOfLiteralType(type: Type) { if (type.flags & TypeFlags.StringOrNumberLiteral && !(type.flags & TypeFlags.FreshLiteral)) { if (!(type).freshType) { - const freshType = createLiteralType(type.flags | TypeFlags.FreshLiteral, (type).text); + const freshType = createLiteralType(type.flags | TypeFlags.FreshLiteral, (type).value); freshType.regularType = type; (type).freshType = freshType; } @@ -7534,11 +7531,12 @@ namespace ts { return type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral ? (type).regularType : type; } - function getLiteralTypeForText(flags: TypeFlags, text: string) { - const map = flags & TypeFlags.StringLiteral ? stringLiteralTypes : numericLiteralTypes; + function getLiteralType(value: string | number) { + const map = typeof value === "number" ? numericLiteralTypes : stringLiteralTypes; + const text = "" + value; let type = map.get(text); if (!type) { - map.set(text, type = createLiteralType(flags, text)); + map.set(text, type = createLiteralType(typeof value === "number" ? TypeFlags.NumberLiteral : TypeFlags.StringLiteral, value)); } return type; } @@ -8434,7 +8432,7 @@ namespace ts { if ((source.flags & TypeFlags.Number | source.flags & TypeFlags.NumberLiteral) && target.flags & TypeFlags.EnumLike) return true; if (source.flags & TypeFlags.EnumLiteral && target.flags & TypeFlags.EnumLiteral && - (source).text === (target).text && + (source).value === (target).value && isEnumTypeRelatedTo((source).baseType, (target).baseType, errorReporter)) { return true; } @@ -9713,8 +9711,8 @@ namespace ts { // no flags for all other types (including non-falsy literal types). function getFalsyFlags(type: Type): TypeFlags { return type.flags & TypeFlags.Union ? getFalsyFlagsOfTypes((type).types) : - type.flags & TypeFlags.StringLiteral ? (type).text === "" ? TypeFlags.StringLiteral : 0 : - type.flags & TypeFlags.NumberLiteral ? (type).text === "0" ? TypeFlags.NumberLiteral : 0 : + type.flags & TypeFlags.StringLiteral ? (type).value === "" ? TypeFlags.StringLiteral : 0 : + type.flags & TypeFlags.NumberLiteral ? (type).value === 0 ? TypeFlags.NumberLiteral : 0 : type.flags & TypeFlags.BooleanLiteral ? type === falseType ? TypeFlags.BooleanLiteral : 0 : type.flags & TypeFlags.PossiblyFalsy; } @@ -10595,14 +10593,14 @@ namespace ts { } if (flags & TypeFlags.StringLiteral) { return strictNullChecks ? - (type).text === "" ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts : - (type).text === "" ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; + (type).value === "" ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts : + (type).value === "" ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; } if (flags & (TypeFlags.Number | TypeFlags.Enum)) { return strictNullChecks ? TypeFacts.NumberStrictFacts : TypeFacts.NumberFacts; } if (flags & (TypeFlags.NumberLiteral | TypeFlags.EnumLiteral)) { - const isZero = (type).text === "0"; + const isZero = (type).value === 0; return strictNullChecks ? isZero ? TypeFacts.ZeroStrictFacts : TypeFacts.NonZeroStrictFacts : isZero ? TypeFacts.ZeroFacts : TypeFacts.NonZeroFacts; @@ -13616,7 +13614,7 @@ namespace ts { // Hello World const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements); if (intrinsicElementsType !== unknownType) { - const stringLiteralTypeName = (elementType).text; + const stringLiteralTypeName = (elementType).value; const intrinsicProp = getPropertyOfType(intrinsicElementsType, stringLiteralTypeName); if (intrinsicProp) { return getTypeOfSymbol(intrinsicProp); @@ -14861,7 +14859,7 @@ namespace ts { case SyntaxKind.Identifier: case SyntaxKind.NumericLiteral: case SyntaxKind.StringLiteral: - return getLiteralTypeForText(TypeFlags.StringLiteral, (element.name).text); + return getLiteralType((element.name).text); case SyntaxKind.ComputedPropertyName: const nameType = checkComputedPropertyName(element.name); @@ -16345,7 +16343,7 @@ namespace ts { return silentNeverType; } if (node.operator === SyntaxKind.MinusToken && node.operand.kind === SyntaxKind.NumericLiteral) { - return getFreshTypeOfLiteralType(getLiteralTypeForText(TypeFlags.NumberLiteral, "" + -(node.operand).text)); + return getFreshTypeOfLiteralType(getLiteralType(-(node.operand).text)); } switch (node.operator) { case SyntaxKind.PlusToken: @@ -17021,9 +17019,9 @@ namespace ts { } switch (node.kind) { case SyntaxKind.StringLiteral: - return getFreshTypeOfLiteralType(getLiteralTypeForText(TypeFlags.StringLiteral, (node).text)); + return getFreshTypeOfLiteralType(getLiteralType((node).text)); case SyntaxKind.NumericLiteral: - return getFreshTypeOfLiteralType(getLiteralTypeForText(TypeFlags.NumberLiteral, (node).text)); + return getFreshTypeOfLiteralType(getLiteralType(+(node).text)); case SyntaxKind.TrueKeyword: return trueType; case SyntaxKind.FalseKeyword: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2389ba8075..c259366542 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3036,11 +3036,19 @@ namespace ts { // String literal types (TypeFlags.StringLiteral) // Numeric literal types (TypeFlags.NumberLiteral) export interface LiteralType extends Type { - text: string; // Text of literal + value: string | number; // Value of literal freshType?: LiteralType; // Fresh version of type regularType?: LiteralType; // Regular version of type } + export interface StringLiteralType extends LiteralType { + value: string; + } + + export interface NumberLiteralType extends LiteralType { + value: number; + } + // Enum types (TypeFlags.Enum) export interface EnumType extends Type { memberTypes: EnumLiteralType[]; diff --git a/src/services/completions.ts b/src/services/completions.ts index 6ac3762b4c..93f690c90f 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -272,7 +272,7 @@ namespace ts.Completions { } else if (type.flags & TypeFlags.StringLiteral) { result.push({ - name: (type).text, + name: (type).value, kindModifiers: ScriptElementKindModifier.none, kind: ScriptElementKind.variableElement, sortText: "0" From a504022e7b1b935f3e216de7b709e3a06c4a8716 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 28 Apr 2017 09:11:04 -0700 Subject: [PATCH 09/83] Classify literal enum members and NumberLiteral/StringLiteral etc. --- src/compiler/checker.ts | 227 +++++++++++++++++++++------------------- src/compiler/types.ts | 14 +-- 2 files changed, 122 insertions(+), 119 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index be72d9d657..4af13dfa21 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2316,7 +2316,7 @@ namespace ts { if (type.flags & TypeFlags.Boolean) { return createKeywordTypeNode(SyntaxKind.BooleanKeyword); } - if (type.flags & TypeFlags.Enum) { + if (type.flags & TypeFlags.EnumLike && !(type.flags & TypeFlags.Union)) { const name = symbolToName(type.symbol, /*expectsIdentifier*/ false); return createTypeReferenceNode(name, /*typeArguments*/ undefined); } @@ -2326,10 +2326,6 @@ namespace ts { if (type.flags & TypeFlags.BooleanLiteral) { return (type).intrinsicName === "true" ? createTrue() : createFalse(); } - if (type.flags & TypeFlags.EnumLiteral) { - const name = symbolToName(type.symbol, /*expectsIdentifier*/ false); - return createTypeReferenceNode(name, /*typeArguments*/ undefined); - } if (type.flags & TypeFlags.Void) { return createKeywordTypeNode(SyntaxKind.VoidKeyword); } @@ -2845,12 +2841,14 @@ namespace ts { flags |= t.flags; if (!(t.flags & TypeFlags.Nullable)) { if (t.flags & (TypeFlags.BooleanLiteral | TypeFlags.EnumLiteral)) { - const baseType = t.flags & TypeFlags.BooleanLiteral ? booleanType : (t).baseType; - const count = baseType.types.length; - if (i + count <= types.length && types[i + count - 1] === baseType.types[count - 1]) { - result.push(baseType); - i += count - 1; - continue; + const baseType = t.flags & TypeFlags.BooleanLiteral ? booleanType : getBaseTypeOfEnumLiteralType(t); + if (baseType.flags & TypeFlags.Union) { + const count = (baseType).types.length; + if (i + count <= types.length && types[i + count - 1] === (baseType).types[count - 1]) { + result.push(baseType); + i += count - 1; + continue; + } } } result.push(t); @@ -3048,7 +3046,7 @@ namespace ts { else if (getObjectFlags(type) & ObjectFlags.Reference) { writeTypeReference(type, nextFlags); } - else if (type.flags & TypeFlags.EnumLiteral) { + else if (type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union)) { buildSymbolDisplay(getParentOfSymbol(type.symbol), writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags); writePunctuation(writer, SyntaxKind.DotToken); appendSymbolNameOnly(type.symbol, writer); @@ -3424,7 +3422,7 @@ namespace ts { let type = getTypeOfSymbol(p); if (parameterNode && isRequiredInitializedParameter(parameterNode)) { - type = includeFalsyTypes(type, TypeFlags.Undefined); + type = getNullableType(type, TypeFlags.Undefined); } buildTypeDisplay(type, writer, enclosingDeclaration, flags, symbolStack); } @@ -4003,7 +4001,7 @@ namespace ts { } function addOptionality(type: Type, optional: boolean): Type { - return strictNullChecks && optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type; + return strictNullChecks && optional ? getNullableType(type, TypeFlags.Undefined) : type; } // Return the inferred type for a variable, parameter, or property declaration @@ -4422,7 +4420,7 @@ namespace ts { links.type = baseTypeVariable ? getIntersectionType([type, baseTypeVariable]) : type; } else { - links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type; + links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ? getNullableType(type, TypeFlags.Undefined) : type; } } } @@ -4930,53 +4928,63 @@ namespace ts { return true; } - function createEnumLiteralType(symbol: Symbol, baseType: EnumType, value: number) { - const type = createType(TypeFlags.EnumLiteral); + function createEnumLiteralType(symbol: Symbol, value: number) { + const type = createLiteralType(TypeFlags.NumberLiteral | TypeFlags.EnumLiteral, value); type.symbol = symbol; - type.baseType = baseType; - type.value = value; return type; } + function getBaseTypeOfEnumLiteralType(type: Type) { + return type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union) ? getDeclaredTypeOfSymbol(getParentOfSymbol(type.symbol)) : type; + } + function getDeclaredTypeOfEnum(symbol: Symbol): Type { const links = getSymbolLinks(symbol); - if (!links.declaredType) { - const enumType = links.declaredType = createType(TypeFlags.Enum); - enumType.symbol = symbol; - if (enumHasLiteralMembers(symbol)) { - const memberTypeList: Type[] = []; - const memberTypes: EnumLiteralType[] = []; - for (const declaration of enumType.symbol.declarations) { - if (declaration.kind === SyntaxKind.EnumDeclaration) { - computeEnumMemberValues(declaration); - for (const member of (declaration).members) { - const memberSymbol = getSymbolOfNode(member); - const value = getEnumMemberValue(member); - if (!memberTypes[value]) { - const memberType = memberTypes[value] = createEnumLiteralType(memberSymbol, enumType, value); - memberTypeList.push(memberType); - } + if (links.declaredType) { + return links.declaredType; + } + if (enumHasLiteralMembers(symbol)) { + const memberTypeList: Type[] = []; + const memberTypes: LiteralType[] = []; + for (const declaration of symbol.declarations) { + if (declaration.kind === SyntaxKind.EnumDeclaration) { + computeEnumMemberValues(declaration); + for (const member of (declaration).members) { + const memberSymbol = getSymbolOfNode(member); + const value = getEnumMemberValue(member); + if (!memberTypes[value]) { + const memberType = memberTypes[value] = createEnumLiteralType(memberSymbol, value); + memberTypeList.push(memberType); } } } - enumType.memberTypes = memberTypes; - if (memberTypeList.length > 1) { - enumType.flags |= TypeFlags.Union; - (enumType).types = memberTypeList; - unionTypes.set(getTypeListId(memberTypeList), enumType); + } + if (memberTypeList.length > 1) { + for (const declaration of symbol.declarations) { + if (declaration.kind === SyntaxKind.EnumDeclaration) { + for (const member of (declaration).members) { + getSymbolLinks(getSymbolOfNode(member)).declaredType = memberTypes[getEnumMemberValue(member)]; + } + } } + const enumType = getUnionType(memberTypeList, /*subtypeReduction*/ false, symbol, /*aliasTypeArguments*/ undefined); + enumType.flags |= TypeFlags.EnumLiteral; + enumType.symbol = symbol; + return links.declaredType = enumType; } } - return links.declaredType; + const enumType = createType(TypeFlags.Enum); + enumType.symbol = symbol; + return links.declaredType = enumType; } function getDeclaredTypeOfEnumMember(symbol: Symbol): Type { const links = getSymbolLinks(symbol); if (!links.declaredType) { - const enumType = getDeclaredTypeOfEnum(getParentOfSymbol(symbol)); - links.declaredType = enumType.flags & TypeFlags.Union ? - enumType.memberTypes[getEnumMemberValue(symbol.valueDeclaration)] : - enumType; + const enumType = getDeclaredTypeOfEnum(getParentOfSymbol(symbol)); + if (!links.declaredType) { + links.declaredType = enumType; + } } return links.declaredType; } @@ -7249,7 +7257,7 @@ namespace ts { function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) { const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; - const propName = indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral) ? + const propName = indexType.flags & TypeFlags.StringOrNumberLiteral ? "" + (indexType).value : accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ? getPropertyNameForKnownSymbolName(((accessExpression.argumentExpression).name).text) : @@ -8383,29 +8391,27 @@ namespace ts { false; } - function isEnumTypeRelatedTo(source: EnumType, target: EnumType, errorReporter?: ErrorReporter) { - if (source === target) { + function isEnumTypeRelatedTo(sourceSymbol: Symbol, targetSymbol: Symbol, errorReporter?: ErrorReporter) { + if (sourceSymbol === targetSymbol) { return true; } - const id = source.id + "," + target.id; + const id = getSymbolId(sourceSymbol) + "," + getSymbolId(targetSymbol); const relation = enumRelation.get(id); if (relation !== undefined) { return relation; } - if (source.symbol.name !== target.symbol.name || - !(source.symbol.flags & SymbolFlags.RegularEnum) || !(target.symbol.flags & SymbolFlags.RegularEnum) || - (source.flags & TypeFlags.Union) !== (target.flags & TypeFlags.Union)) { + if (sourceSymbol.name !== targetSymbol.name || !(sourceSymbol.flags & SymbolFlags.RegularEnum) || !(targetSymbol.flags & SymbolFlags.RegularEnum)) { enumRelation.set(id, false); return false; } - const targetEnumType = getTypeOfSymbol(target.symbol); - for (const property of getPropertiesOfType(getTypeOfSymbol(source.symbol))) { + const targetEnumType = getTypeOfSymbol(targetSymbol); + for (const property of getPropertiesOfType(getTypeOfSymbol(sourceSymbol))) { if (property.flags & SymbolFlags.EnumMember) { const targetProperty = getPropertyOfType(targetEnumType, property.name); if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) { if (errorReporter) { errorReporter(Diagnostics.Property_0_is_missing_in_type_1, property.name, - typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType)); + typeToString(getDeclaredTypeOfSymbol(targetSymbol), /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType)); } enumRelation.set(id, false); return false; @@ -8422,25 +8428,19 @@ namespace ts { if (source.flags & TypeFlags.StringLike && target.flags & TypeFlags.String) return true; if (source.flags & TypeFlags.NumberLike && target.flags & TypeFlags.Number) return true; if (source.flags & TypeFlags.BooleanLike && target.flags & TypeFlags.Boolean) return true; - if (source.flags & TypeFlags.EnumLiteral && target.flags & TypeFlags.Enum && (source).baseType === target) return true; - if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum && isEnumTypeRelatedTo(source, target, errorReporter)) return true; + if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; + if (source.flags & TypeFlags.EnumLiteral && target.flags & TypeFlags.EnumLiteral) { + if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; + if (source.flags & TypeFlags.Literal && target.flags & TypeFlags.Literal && + (source).value === (target).value && + isEnumTypeRelatedTo(getParentOfSymbol(source.symbol), getParentOfSymbol(target.symbol), errorReporter)) return true; + } if (source.flags & TypeFlags.Undefined && (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void))) return true; if (source.flags & TypeFlags.Null && (!strictNullChecks || target.flags & TypeFlags.Null)) return true; if (source.flags & TypeFlags.Object && target.flags & TypeFlags.NonPrimitive) return true; if (relation === assignableRelation || relation === comparableRelation) { if (source.flags & TypeFlags.Any) return true; - if ((source.flags & TypeFlags.Number | source.flags & TypeFlags.NumberLiteral) && target.flags & TypeFlags.EnumLike) return true; - if (source.flags & TypeFlags.EnumLiteral && - target.flags & TypeFlags.EnumLiteral && - (source).value === (target).value && - isEnumTypeRelatedTo((source).baseType, (target).baseType, errorReporter)) { - return true; - } - if (source.flags & TypeFlags.EnumLiteral && - target.flags & TypeFlags.Enum && - isEnumTypeRelatedTo(target, (source).baseType, errorReporter)) { - return true; - } + if (source.flags & (TypeFlags.Number | TypeFlags.NumberLiteral) && !(source.flags & TypeFlags.EnumLiteral) && target.flags & TypeFlags.EnumLike) return true; } return false; } @@ -9603,7 +9603,7 @@ namespace ts { return getUnionType(types, /*subtypeReduction*/ true); } const supertype = getSupertypeOrUnion(primaryTypes); - return supertype && includeFalsyTypes(supertype, getFalsyFlagsOfTypes(types) & TypeFlags.Nullable); + return supertype && getNullableType(supertype, getFalsyFlagsOfTypes(types) & TypeFlags.Nullable); } function reportNoCommonSupertypeError(types: Type[], errorLocation: Node, errorMessageChainHead: DiagnosticMessageChain): void { @@ -9668,26 +9668,26 @@ namespace ts { function isLiteralType(type: Type): boolean { return type.flags & TypeFlags.Boolean ? true : - type.flags & TypeFlags.Union ? type.flags & TypeFlags.Enum ? true : !forEach((type).types, t => !isUnitType(t)) : - isUnitType(type); + type.flags & TypeFlags.Union ? type.flags & TypeFlags.EnumLiteral ? true : !forEach((type).types, t => !isUnitType(t)) : + isUnitType(type); } function getBaseTypeOfLiteralType(type: Type): Type { - return type.flags & TypeFlags.StringLiteral ? stringType : + return type.flags & TypeFlags.EnumLiteral ? getBaseTypeOfEnumLiteralType(type) : + type.flags & TypeFlags.StringLiteral ? stringType : type.flags & TypeFlags.NumberLiteral ? numberType : - type.flags & TypeFlags.BooleanLiteral ? booleanType : - type.flags & TypeFlags.EnumLiteral ? (type).baseType : - type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(sameMap((type).types, getBaseTypeOfLiteralType)) : - type; + type.flags & TypeFlags.BooleanLiteral ? booleanType : + type.flags & TypeFlags.Union ? getUnionType(sameMap((type).types, getBaseTypeOfLiteralType)) : + type; } function getWidenedLiteralType(type: Type): Type { - return type.flags & TypeFlags.StringLiteral && type.flags & TypeFlags.FreshLiteral ? stringType : + return type.flags & TypeFlags.EnumLiteral ? getBaseTypeOfEnumLiteralType(type) : + type.flags & TypeFlags.StringLiteral && type.flags & TypeFlags.FreshLiteral ? stringType : type.flags & TypeFlags.NumberLiteral && type.flags & TypeFlags.FreshLiteral ? numberType : - type.flags & TypeFlags.BooleanLiteral ? booleanType : - type.flags & TypeFlags.EnumLiteral ? (type).baseType : - type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(sameMap((type).types, getWidenedLiteralType)) : - type; + type.flags & TypeFlags.BooleanLiteral ? booleanType : + type.flags & TypeFlags.Union ? getUnionType(sameMap((type).types, getWidenedLiteralType)) : + type; } /** @@ -9712,23 +9712,9 @@ namespace ts { function getFalsyFlags(type: Type): TypeFlags { return type.flags & TypeFlags.Union ? getFalsyFlagsOfTypes((type).types) : type.flags & TypeFlags.StringLiteral ? (type).value === "" ? TypeFlags.StringLiteral : 0 : - type.flags & TypeFlags.NumberLiteral ? (type).value === 0 ? TypeFlags.NumberLiteral : 0 : - type.flags & TypeFlags.BooleanLiteral ? type === falseType ? TypeFlags.BooleanLiteral : 0 : - type.flags & TypeFlags.PossiblyFalsy; - } - - function includeFalsyTypes(type: Type, flags: TypeFlags) { - if ((getFalsyFlags(type) & flags) === flags) { - return type; - } - const types = [type]; - if (flags & TypeFlags.StringLike) types.push(emptyStringType); - if (flags & TypeFlags.NumberLike) types.push(zeroType); - if (flags & TypeFlags.BooleanLike) types.push(falseType); - if (flags & TypeFlags.Void) types.push(voidType); - if (flags & TypeFlags.Undefined) types.push(undefinedType); - if (flags & TypeFlags.Null) types.push(nullType); - return getUnionType(types); + type.flags & TypeFlags.NumberLiteral ? (type).value === 0 ? TypeFlags.NumberLiteral : 0 : + type.flags & TypeFlags.BooleanLiteral ? type === falseType ? TypeFlags.BooleanLiteral : 0 : + type.flags & TypeFlags.PossiblyFalsy; } function removeDefinitelyFalsyTypes(type: Type): Type { @@ -9737,6 +9723,28 @@ namespace ts { type; } + function extractDefinitelyFalsyTypes(type: Type): Type { + return mapType(type, getDefinitelyFalsyPartOfType); + } + + function getDefinitelyFalsyPartOfType(type: Type): Type { + return type.flags & TypeFlags.String ? emptyStringType : + type.flags & TypeFlags.Number ? zeroType : + type.flags & TypeFlags.Boolean || type === falseType ? falseType : + type.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null) || + type.flags & TypeFlags.StringLiteral && (type).value === "" || + type.flags & TypeFlags.NumberLiteral && (type).value === 0 ? type : + neverType; + } + + function getNullableType(type: Type, flags: TypeFlags): Type { + const missing = (flags & ~type.flags) & (TypeFlags.Undefined | TypeFlags.Null); + return missing === 0 ? type : + missing === TypeFlags.Undefined ? getUnionType([type, undefinedType]) : + missing === TypeFlags.Null ? getUnionType([type, nullType]) : + getUnionType([type, undefinedType, nullType]); + } + function getNonNullableType(type: Type): Type { return strictNullChecks ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; } @@ -10074,7 +10082,7 @@ namespace ts { } return; } - if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union && !(source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum) || + if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union && !(source.flags & TypeFlags.EnumLiteral && target.flags & TypeFlags.EnumLiteral) || source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) { // Source and target are both unions or both intersections. If source and target // are the same type, just relate each constituent type to itself. @@ -10592,14 +10600,15 @@ namespace ts { return strictNullChecks ? TypeFacts.StringStrictFacts : TypeFacts.StringFacts; } if (flags & TypeFlags.StringLiteral) { + const isEmpty = (type).value === ""; return strictNullChecks ? - (type).value === "" ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts : - (type).value === "" ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; + isEmpty ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts : + isEmpty ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; } if (flags & (TypeFlags.Number | TypeFlags.Enum)) { return strictNullChecks ? TypeFacts.NumberStrictFacts : TypeFacts.NumberFacts; } - if (flags & (TypeFlags.NumberLiteral | TypeFlags.EnumLiteral)) { + if (flags & TypeFlags.NumberLiteral) { const isZero = (type).value === 0; return strictNullChecks ? isZero ? TypeFacts.ZeroStrictFacts : TypeFacts.NonZeroStrictFacts : @@ -10832,7 +10841,7 @@ namespace ts { } return true; } - if (source.flags & TypeFlags.EnumLiteral && target.flags & TypeFlags.Enum && (source).baseType === target) { + if (source.flags & TypeFlags.EnumLiteral && getBaseTypeOfEnumLiteralType(source) === target) { return true; } return containsType(target.types, source); @@ -11813,7 +11822,7 @@ namespace ts { isInAmbientContext(declaration); const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, getRootDeclaration(declaration) as VariableLikeDeclaration) : type) : type === autoType || type === autoArrayType ? undefinedType : - includeFalsyTypes(type, TypeFlags.Undefined); + getNullableType(type, TypeFlags.Undefined); const flowType = getFlowTypeOfReference(node, type, initialType, flowContainer, !assumeInitialized); // A variable is considered uninitialized when it is possible to analyze the entire control flow graph // from declaration to use, and when the variable's declared type doesn't include undefined but the @@ -15752,7 +15761,7 @@ namespace ts { if (strictNullChecks) { const declaration = symbol.valueDeclaration; if (declaration && (declaration).initializer) { - return includeFalsyTypes(type, TypeFlags.Undefined); + return getNullableType(type, TypeFlags.Undefined); } } return type; @@ -16851,7 +16860,7 @@ namespace ts { return checkInExpression(left, right, leftType, rightType); case SyntaxKind.AmpersandAmpersandToken: return getTypeFacts(leftType) & TypeFacts.Truthy ? - includeFalsyTypes(rightType, getFalsyFlags(strictNullChecks ? leftType : getBaseTypeOfLiteralType(rightType))) : + getUnionType([extractDefinitelyFalsyTypes(strictNullChecks ? leftType : getBaseTypeOfLiteralType(rightType)), rightType]) : leftType; case SyntaxKind.BarBarToken: return getTypeFacts(leftType) & TypeFacts.Falsy ? @@ -17940,7 +17949,7 @@ namespace ts { checkTypeArgumentConstraints(typeParameters, node.typeArguments); } } - if (type.flags & TypeFlags.Enum && !(type).memberTypes && getNodeLinks(node).resolvedSymbol.flags & SymbolFlags.EnumMember) { + if (type.flags & TypeFlags.Enum && getNodeLinks(node).resolvedSymbol.flags & SymbolFlags.EnumMember) { error(node, Diagnostics.Enum_type_0_has_members_with_initializers_that_are_not_literals, typeToString(type)); } } @@ -22567,7 +22576,7 @@ namespace ts { ? getWidenedLiteralType(getTypeOfSymbol(symbol)) : unknownType; if (flags & TypeFormatFlags.AddUndefined) { - type = includeFalsyTypes(type, TypeFlags.Undefined); + type = getNullableType(type, TypeFlags.Undefined); } getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c259366542..f17dec4bd1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2961,7 +2961,7 @@ namespace ts { StringLiteral = 1 << 5, NumberLiteral = 1 << 6, BooleanLiteral = 1 << 7, - EnumLiteral = 1 << 8, + EnumLiteral = 1 << 8, // Enum literal or union of enum literals ESSymbol = 1 << 9, // Type of symbol primitive introduced in ES6 Void = 1 << 10, Undefined = 1 << 11, @@ -2987,7 +2987,7 @@ namespace ts { /* @internal */ Nullable = Undefined | Null, - Literal = StringLiteral | NumberLiteral | BooleanLiteral | EnumLiteral, + Literal = StringLiteral | NumberLiteral | BooleanLiteral, StringOrNumberLiteral = StringLiteral | NumberLiteral, /* @internal */ DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null, @@ -2995,9 +2995,9 @@ namespace ts { /* @internal */ Intrinsic = Any | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive, /* @internal */ - Primitive = String | Number | Boolean | Enum | ESSymbol | Void | Undefined | Null | Literal, + Primitive = String | Number | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal, StringLike = String | StringLiteral | Index, - NumberLike = Number | NumberLiteral | Enum | EnumLiteral, + NumberLike = Number | NumberLiteral | Enum, BooleanLike = Boolean | BooleanLiteral, EnumLike = Enum | EnumLiteral, UnionOrIntersection = Union | Intersection, @@ -3051,12 +3051,6 @@ namespace ts { // Enum types (TypeFlags.Enum) export interface EnumType extends Type { - memberTypes: EnumLiteralType[]; - } - - // Enum types (TypeFlags.EnumLiteral) - export interface EnumLiteralType extends LiteralType { - baseType: EnumType & UnionType; // Base enum type } export const enum ObjectFlags { From 50a37cea5764f82cb1b16f5c3d87e44cd55ab4f3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 28 Apr 2017 09:11:20 -0700 Subject: [PATCH 10/83] Accept new baselines --- .../enumAssignmentCompat3.errors.txt | 20 ++++-- tests/baselines/reference/literalTypes2.types | 2 +- .../logicalAndOperatorWithEveryType.types | 2 +- .../logicalOrOperatorWithEveryType.types | 14 ++--- .../baselines/reference/metadataOfUnion.types | 2 +- .../reference/subtypesOfUnion.errors.txt | 60 +++++++++--------- ...IfEveryConstituentTypeIsSubtype.errors.txt | 61 +++++++++---------- 7 files changed, 83 insertions(+), 78 deletions(-) diff --git a/tests/baselines/reference/enumAssignmentCompat3.errors.txt b/tests/baselines/reference/enumAssignmentCompat3.errors.txt index 558540c32c..a458733bcc 100644 --- a/tests/baselines/reference/enumAssignmentCompat3.errors.txt +++ b/tests/baselines/reference/enumAssignmentCompat3.errors.txt @@ -1,15 +1,19 @@ -tests/cases/compiler/enumAssignmentCompat3.ts(68,1): error TS2324: Property 'd' is missing in type 'First.E'. +tests/cases/compiler/enumAssignmentCompat3.ts(68,1): error TS2322: Type 'Abcd.E' is not assignable to type 'First.E'. + Property 'd' is missing in type 'First.E'. tests/cases/compiler/enumAssignmentCompat3.ts(70,1): error TS2322: Type 'Cd.E' is not assignable to type 'First.E'. Property 'd' is missing in type 'First.E'. tests/cases/compiler/enumAssignmentCompat3.ts(71,1): error TS2322: Type 'Nope' is not assignable to type 'E'. tests/cases/compiler/enumAssignmentCompat3.ts(72,1): error TS2322: Type 'Decl.E' is not assignable to type 'First.E'. -tests/cases/compiler/enumAssignmentCompat3.ts(75,1): error TS2324: Property 'c' is missing in type 'Ab.E'. +tests/cases/compiler/enumAssignmentCompat3.ts(75,1): error TS2322: Type 'First.E' is not assignable to type 'Ab.E'. + Property 'c' is missing in type 'Ab.E'. tests/cases/compiler/enumAssignmentCompat3.ts(76,1): error TS2322: Type 'First.E' is not assignable to type 'Cd.E'. + Property 'a' is missing in type 'Cd.E'. tests/cases/compiler/enumAssignmentCompat3.ts(77,1): error TS2322: Type 'E' is not assignable to type 'Nope'. tests/cases/compiler/enumAssignmentCompat3.ts(78,1): error TS2322: Type 'First.E' is not assignable to type 'Decl.E'. tests/cases/compiler/enumAssignmentCompat3.ts(82,1): error TS2322: Type 'Const.E' is not assignable to type 'First.E'. tests/cases/compiler/enumAssignmentCompat3.ts(83,1): error TS2322: Type 'First.E' is not assignable to type 'Const.E'. -tests/cases/compiler/enumAssignmentCompat3.ts(86,1): error TS2324: Property 'd' is missing in type 'First.E'. +tests/cases/compiler/enumAssignmentCompat3.ts(86,1): error TS2322: Type 'Merged.E' is not assignable to type 'First.E'. + Property 'd' is missing in type 'First.E'. ==== tests/cases/compiler/enumAssignmentCompat3.ts (11 errors) ==== @@ -82,7 +86,8 @@ tests/cases/compiler/enumAssignmentCompat3.ts(86,1): error TS2324: Property 'd' abc = secondAbc; // ok abc = secondAbcd; // missing 'd' ~~~ -!!! error TS2324: Property 'd' is missing in type 'First.E'. +!!! error TS2322: Type 'Abcd.E' is not assignable to type 'First.E'. +!!! error TS2322: Property 'd' is missing in type 'First.E'. abc = secondAb; // ok abc = secondCd; // missing 'd' ~~~ @@ -98,10 +103,12 @@ tests/cases/compiler/enumAssignmentCompat3.ts(86,1): error TS2324: Property 'd' secondAbcd = abc; // ok secondAb = abc; // missing 'c' ~~~~~~~~ -!!! error TS2324: Property 'c' is missing in type 'Ab.E'. +!!! error TS2322: Type 'First.E' is not assignable to type 'Ab.E'. +!!! error TS2322: Property 'c' is missing in type 'Ab.E'. secondCd = abc; // missing 'a' and 'b' ~~~~~~~~ !!! error TS2322: Type 'First.E' is not assignable to type 'Cd.E'. +!!! error TS2322: Property 'a' is missing in type 'Cd.E'. nope = abc; // nope! ~~~~ !!! error TS2322: Type 'E' is not assignable to type 'Nope'. @@ -121,7 +128,8 @@ tests/cases/compiler/enumAssignmentCompat3.ts(86,1): error TS2324: Property 'd' // merged enums compare all their members abc = merged; // missing 'd' ~~~ -!!! error TS2324: Property 'd' is missing in type 'First.E'. +!!! error TS2322: Type 'Merged.E' is not assignable to type 'First.E'. +!!! error TS2322: Property 'd' is missing in type 'First.E'. merged = abc; // ok abc = merged2; // ok merged2 = abc; // ok \ No newline at end of file diff --git a/tests/baselines/reference/literalTypes2.types b/tests/baselines/reference/literalTypes2.types index 716b016f64..ab1d3e199d 100644 --- a/tests/baselines/reference/literalTypes2.types +++ b/tests/baselines/reference/literalTypes2.types @@ -290,7 +290,7 @@ function f3() { >c2 : 1 | "two" let x3 = c3; ->x3 : number | boolean | E +>x3 : number | boolean >c3 : true | E.A | 123 let x4 = c4; diff --git a/tests/baselines/reference/logicalAndOperatorWithEveryType.types b/tests/baselines/reference/logicalAndOperatorWithEveryType.types index 54770acfab..cbe37d54a4 100644 --- a/tests/baselines/reference/logicalAndOperatorWithEveryType.types +++ b/tests/baselines/reference/logicalAndOperatorWithEveryType.types @@ -365,7 +365,7 @@ var rf5 = a5 && a6; var rf6 = a6 && a6; >rf6 : E ->a6 && a6 : E.b | E.c +>a6 && a6 : E >a6 : E >a6 : E.b | E.c diff --git a/tests/baselines/reference/logicalOrOperatorWithEveryType.types b/tests/baselines/reference/logicalOrOperatorWithEveryType.types index 327ae64cf0..5e6fa98d74 100644 --- a/tests/baselines/reference/logicalOrOperatorWithEveryType.types +++ b/tests/baselines/reference/logicalOrOperatorWithEveryType.types @@ -128,7 +128,7 @@ var rb5 = a5 || a2; // void || boolean is void | boolean var rb6 = a6 || a2; // enum || boolean is E | boolean >rb6 : boolean | E ->a6 || a2 : boolean | E +>a6 || a2 : boolean | E.b | E.c >a6 : E >a2 : boolean @@ -248,7 +248,7 @@ var rd5 = a5 || a4; // void || string is void | string var rd6 = a6 || a4; // enum || string is enum | string >rd6 : string | E ->a6 || a4 : string | E +>a6 || a4 : string | E.b | E.c >a6 : E >a4 : string @@ -308,7 +308,7 @@ var re5 = a5 || a5; // void || void is void var re6 = a6 || a5; // enum || void is enum | void >re6 : void | E ->a6 || a5 : void | E +>a6 || a5 : void | E.b | E.c >a6 : E >a5 : void @@ -428,7 +428,7 @@ var rh5 = a5 || a7; // void || object is void | object var rh6 = a6 || a7; // enum || object is enum | object >rh6 : E | { a: string; } ->a6 || a7 : E | { a: string; } +>a6 || a7 : E.b | E.c | { a: string; } >a6 : E >a7 : { a: string; } @@ -488,7 +488,7 @@ var ri5 = a5 || a8; // void || array is void | array var ri6 = a6 || a8; // enum || array is enum | array >ri6 : E | string[] ->a6 || a8 : E | string[] +>a6 || a8 : E.b | E.c | string[] >a6 : E >a8 : string[] @@ -548,7 +548,7 @@ var rj5 = a5 || null; // void || null is void var rj6 = a6 || null; // enum || null is E >rj6 : E ->a6 || null : E +>a6 || null : E.b | E.c >a6 : E >null : null @@ -608,7 +608,7 @@ var rf5 = a5 || undefined; // void || undefined is void var rf6 = a6 || undefined; // enum || undefined is E >rf6 : E ->a6 || undefined : E +>a6 || undefined : E.b | E.c >a6 : E >undefined : undefined diff --git a/tests/baselines/reference/metadataOfUnion.types b/tests/baselines/reference/metadataOfUnion.types index 08afc4e81b..542d37e208 100644 --- a/tests/baselines/reference/metadataOfUnion.types +++ b/tests/baselines/reference/metadataOfUnion.types @@ -81,6 +81,6 @@ class D { >PropDeco : (target: Object, propKey: string | symbol) => void d: E | number; ->d : number | E +>d : number >E : E } diff --git a/tests/baselines/reference/subtypesOfUnion.errors.txt b/tests/baselines/reference/subtypesOfUnion.errors.txt index fade537781..7cbca6cc40 100644 --- a/tests/baselines/reference/subtypesOfUnion.errors.txt +++ b/tests/baselines/reference/subtypesOfUnion.errors.txt @@ -12,21 +12,21 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOf tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(28,5): error TS2411: Property 'foo16' of type 'T' is not assignable to string index type 'string | number'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(29,5): error TS2411: Property 'foo17' of type 'Object' is not assignable to string index type 'string | number'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(30,5): error TS2411: Property 'foo18' of type '{}' is not assignable to string index type 'string | number'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(35,5): error TS2411: Property 'foo2' of type 'string' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(37,5): error TS2411: Property 'foo4' of type 'boolean' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(39,5): error TS2411: Property 'foo6' of type 'Date' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(40,5): error TS2411: Property 'foo7' of type 'RegExp' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(41,5): error TS2411: Property 'foo8' of type '{ bar: number; }' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(42,5): error TS2411: Property 'foo9' of type 'I8' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(43,5): error TS2411: Property 'foo10' of type 'A' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(44,5): error TS2411: Property 'foo11' of type 'A2' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(45,5): error TS2411: Property 'foo12' of type '(x: any) => number' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(46,5): error TS2411: Property 'foo13' of type '(x: T) => T' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(47,5): error TS2411: Property 'foo14' of type 'typeof f' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(48,5): error TS2411: Property 'foo15' of type 'typeof c' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(49,5): error TS2411: Property 'foo16' of type 'T' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(50,5): error TS2411: Property 'foo17' of type 'Object' is not assignable to string index type 'number | E'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(51,5): error TS2411: Property 'foo18' of type '{}' is not assignable to string index type 'number | E'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(35,5): error TS2411: Property 'foo2' of type 'string' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(37,5): error TS2411: Property 'foo4' of type 'boolean' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(39,5): error TS2411: Property 'foo6' of type 'Date' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(40,5): error TS2411: Property 'foo7' of type 'RegExp' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(41,5): error TS2411: Property 'foo8' of type '{ bar: number; }' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(42,5): error TS2411: Property 'foo9' of type 'I8' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(43,5): error TS2411: Property 'foo10' of type 'A' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(44,5): error TS2411: Property 'foo11' of type 'A2' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(45,5): error TS2411: Property 'foo12' of type '(x: any) => number' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(46,5): error TS2411: Property 'foo13' of type '(x: T) => T' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(47,5): error TS2411: Property 'foo14' of type 'typeof f' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(48,5): error TS2411: Property 'foo15' of type 'typeof c' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(49,5): error TS2411: Property 'foo16' of type 'T' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(50,5): error TS2411: Property 'foo17' of type 'Object' is not assignable to string index type 'number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts(51,5): error TS2411: Property 'foo18' of type '{}' is not assignable to string index type 'number'. ==== tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOfUnion.ts (29 errors) ==== @@ -94,49 +94,49 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypesOf foo: any; // ok foo2: string; // error ~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'string' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo2' of type 'string' is not assignable to string index type 'number'. foo3: number; // ok foo4: boolean; // error ~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo4' of type 'boolean' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo4' of type 'boolean' is not assignable to string index type 'number'. foo5: E; // ok foo6: Date; // error ~~~~~~~~~~~ -!!! error TS2411: Property 'foo6' of type 'Date' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo6' of type 'Date' is not assignable to string index type 'number'. foo7: RegExp; // error ~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo7' of type 'RegExp' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo7' of type 'RegExp' is not assignable to string index type 'number'. foo8: { bar: number }; // error ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo8' of type '{ bar: number; }' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo8' of type '{ bar: number; }' is not assignable to string index type 'number'. foo9: I8; // error ~~~~~~~~~ -!!! error TS2411: Property 'foo9' of type 'I8' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo9' of type 'I8' is not assignable to string index type 'number'. foo10: A; // error ~~~~~~~~~ -!!! error TS2411: Property 'foo10' of type 'A' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo10' of type 'A' is not assignable to string index type 'number'. foo11: A2; // error ~~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo11' of type 'A2' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo11' of type 'A2' is not assignable to string index type 'number'. foo12: (x) => number; //error ~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo12' of type '(x: any) => number' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo12' of type '(x: any) => number' is not assignable to string index type 'number'. foo13: (x: T) => T; // error ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo13' of type '(x: T) => T' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo13' of type '(x: T) => T' is not assignable to string index type 'number'. foo14: typeof f; // error ~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo14' of type 'typeof f' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo14' of type 'typeof f' is not assignable to string index type 'number'. foo15: typeof c; // error ~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo15' of type 'typeof c' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo15' of type 'typeof c' is not assignable to string index type 'number'. foo16: T; // error ~~~~~~~~~ -!!! error TS2411: Property 'foo16' of type 'T' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo16' of type 'T' is not assignable to string index type 'number'. foo17: Object; // error ~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo17' of type 'Object' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo17' of type 'Object' is not assignable to string index type 'number'. foo18: {}; // error ~~~~~~~~~~ -!!! error TS2411: Property 'foo18' of type '{}' is not assignable to string index type 'number | E'. +!!! error TS2411: Property 'foo18' of type '{}' is not assignable to string index type 'number'. } \ No newline at end of file diff --git a/tests/baselines/reference/unionSubtypeIfEveryConstituentTypeIsSubtype.errors.txt b/tests/baselines/reference/unionSubtypeIfEveryConstituentTypeIsSubtype.errors.txt index 013b5d9a99..ddf5da8881 100644 --- a/tests/baselines/reference/unionSubtypeIfEveryConstituentTypeIsSubtype.errors.txt +++ b/tests/baselines/reference/unionSubtypeIfEveryConstituentTypeIsSubtype.errors.txt @@ -1,37 +1,36 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(15,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'number'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(21,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'string'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(22,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'string'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(22,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'string'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(28,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'boolean'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(29,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'boolean'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(29,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'boolean'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(35,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'Date'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(36,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'Date'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(36,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'Date'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(42,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'RegExp'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(43,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'RegExp'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(43,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'RegExp'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(49,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type '{ bar: number; }'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(50,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type '{ bar: number; }'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(50,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type '{ bar: number; }'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(56,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'number[]'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(57,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'number[]'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(57,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'number[]'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(63,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'I8'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(64,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'I8'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(64,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'I8'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(70,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'A'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(71,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'A'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(71,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'A'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(77,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'A2'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(78,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'A2'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(78,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'A2'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(84,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type '(x: any) => number'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(85,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type '(x: any) => number'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(85,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type '(x: any) => number'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(91,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type '(x: T) => T'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(92,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type '(x: T) => T'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(92,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type '(x: T) => T'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(99,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'E2'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(100,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'E2'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(110,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'typeof f'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(111,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'typeof f'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(111,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'typeof f'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(121,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'typeof c'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(122,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'typeof c'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(122,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'typeof c'. tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(128,5): error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'T'. -tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(129,5): error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'T'. +tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts(129,5): error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'T'. -==== tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts (31 errors) ==== +==== tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubtypeIfEveryConstituentTypeIsSubtype.ts (30 errors) ==== enum e { e1, e2 @@ -59,7 +58,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'string'. foo2: e | number; // error e and number both not subtype of string ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'string'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'string'. } // error cases @@ -70,7 +69,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'boolean'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'boolean'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'boolean'. } @@ -81,7 +80,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'Date'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'Date'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'Date'. } @@ -92,7 +91,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'RegExp'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'RegExp'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'RegExp'. } @@ -103,7 +102,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type '{ bar: number; }'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type '{ bar: number; }'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type '{ bar: number; }'. } @@ -114,7 +113,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'number[]'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'number[]'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'number[]'. } @@ -125,7 +124,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'I8'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'I8'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'I8'. } class A { foo: number; } @@ -136,7 +135,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'A'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'A'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'A'. } class A2 { foo: T; } @@ -147,7 +146,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'A2'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'A2'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'A2'. } @@ -158,7 +157,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type '(x: any) => number'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type '(x: any) => number'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type '(x: any) => number'. } @@ -169,7 +168,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type '(x: T) => T'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type '(x: T) => T'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type '(x: T) => T'. } @@ -180,8 +179,6 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty ~~~~~~~~~~~~~~~~~~~~~ !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'E2'. foo2: e | number; - ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'E2'. } @@ -196,7 +193,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'typeof f'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'typeof f'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'typeof f'. } @@ -211,7 +208,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'typeof c'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'typeof c'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'typeof c'. } @@ -222,7 +219,7 @@ tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/unionSubty !!! error TS2411: Property 'foo' of type 'string | number' is not assignable to string index type 'T'. foo2: e | number; ~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property 'foo2' of type 'number | e' is not assignable to string index type 'T'. +!!! error TS2411: Property 'foo2' of type 'number' is not assignable to string index type 'T'. } interface I19 { From d2fdebe246a6c93dbf679e28f1aa1d0484d5feb0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 28 Apr 2017 13:19:01 -0700 Subject: [PATCH 11/83] Fix type-to-string handling of enum literal types --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4af13dfa21..e1c185360d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3051,7 +3051,7 @@ namespace ts { writePunctuation(writer, SyntaxKind.DotToken); appendSymbolNameOnly(type.symbol, writer); } - else if (getObjectFlags(type) & ObjectFlags.ClassOrInterface || type.flags & (TypeFlags.Enum | TypeFlags.TypeParameter)) { + else if (getObjectFlags(type) & ObjectFlags.ClassOrInterface || type.flags & (TypeFlags.EnumLike | TypeFlags.TypeParameter)) { // The specified symbol flags need to be reinterpreted as type flags buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags); } From 9e7cdb4df57a27e7b14fb4e4d866c1b48e52f1aa Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 29 Apr 2017 08:37:33 -0700 Subject: [PATCH 12/83] Support string valued members in literal enums --- src/compiler/checker.ts | 86 ++++++++++++++++------------ src/compiler/diagnosticMessages.json | 4 ++ src/compiler/emitter.ts | 2 +- src/compiler/factory.ts | 2 +- src/compiler/transformers/ts.ts | 33 ++++++----- src/compiler/types.ts | 15 +++-- src/compiler/utilities.ts | 2 +- src/services/symbolDisplay.ts | 5 +- 8 files changed, 90 insertions(+), 59 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e1c185360d..689d3e44a7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -47,6 +47,7 @@ namespace ts { let typeCount = 0; let symbolCount = 0; + let enumCount = 0; let symbolInstantiationDepth = 0; const emptyArray: any[] = []; @@ -210,8 +211,7 @@ namespace ts { const tupleTypes: GenericType[] = []; const unionTypes = createMap(); const intersectionTypes = createMap(); - const stringLiteralTypes = createMap(); - const numericLiteralTypes = createMap(); + const literalTypes = createMap(); const indexedAccessTypes = createMap(); const evolvingArrayTypes: EvolvingArrayType[] = []; @@ -4904,34 +4904,36 @@ namespace ts { return links.declaredType; } - function isLiteralEnumMember(symbol: Symbol, member: EnumMember) { + function isLiteralEnumMember(member: EnumMember) { const expr = member.initializer; if (!expr) { return !isInAmbientContext(member); } - return expr.kind === SyntaxKind.NumericLiteral || + return expr.kind === SyntaxKind.StringLiteral || expr.kind === SyntaxKind.NumericLiteral || expr.kind === SyntaxKind.PrefixUnaryExpression && (expr).operator === SyntaxKind.MinusToken && (expr).operand.kind === SyntaxKind.NumericLiteral || - expr.kind === SyntaxKind.Identifier && !!symbol.exports.get((expr).text); + expr.kind === SyntaxKind.Identifier && (nodeIsMissing(expr) || !!getSymbolOfNode(member.parent).exports.get((expr).text)); } - function enumHasLiteralMembers(symbol: Symbol) { + function getEnumKind(symbol: Symbol): EnumKind { + const links = getSymbolLinks(symbol); + if (links.enumKind !== undefined) { + return links.enumKind; + } + let hasNonLiteralMember = false; for (const declaration of symbol.declarations) { if (declaration.kind === SyntaxKind.EnumDeclaration) { for (const member of (declaration).members) { - if (!isLiteralEnumMember(symbol, member)) { - return false; + if (member.initializer && member.initializer.kind === SyntaxKind.StringLiteral) { + return links.enumKind = EnumKind.Literal; + } + if (!isLiteralEnumMember(member)) { + hasNonLiteralMember = true; } } } } - return true; - } - - function createEnumLiteralType(symbol: Symbol, value: number) { - const type = createLiteralType(TypeFlags.NumberLiteral | TypeFlags.EnumLiteral, value); - type.symbol = symbol; - return type; + return links.enumKind = hasNonLiteralMember ? EnumKind.Numeric : EnumKind.Literal; } function getBaseTypeOfEnumLiteralType(type: Type) { @@ -4943,17 +4945,14 @@ namespace ts { if (links.declaredType) { return links.declaredType; } - if (enumHasLiteralMembers(symbol)) { + if (getEnumKind(symbol) === EnumKind.Literal) { + enumCount++; const memberTypeList: Type[] = []; - const memberTypes: LiteralType[] = []; for (const declaration of symbol.declarations) { if (declaration.kind === SyntaxKind.EnumDeclaration) { - computeEnumMemberValues(declaration); for (const member of (declaration).members) { - const memberSymbol = getSymbolOfNode(member); - const value = getEnumMemberValue(member); - if (!memberTypes[value]) { - const memberType = memberTypes[value] = createEnumLiteralType(memberSymbol, value); + const memberType = getLiteralType(getEnumMemberValue(member), enumCount, getSymbolOfNode(member)); + if (!contains(memberTypeList, memberType)) { memberTypeList.push(memberType); } } @@ -4963,7 +4962,7 @@ namespace ts { for (const declaration of symbol.declarations) { if (declaration.kind === SyntaxKind.EnumDeclaration) { for (const member of (declaration).members) { - getSymbolLinks(getSymbolOfNode(member)).declaredType = memberTypes[getEnumMemberValue(member)]; + getSymbolLinks(getSymbolOfNode(member)).declaredType = getLiteralType(getEnumMemberValue(member), enumCount, getSymbolOfNode(member)); } } } @@ -7517,8 +7516,9 @@ namespace ts { return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent)); } - function createLiteralType(flags: TypeFlags, value: string | number) { + function createLiteralType(flags: TypeFlags, value: string | number, symbol: Symbol) { const type = createType(flags); + type.symbol = symbol; type.value = value; return type; } @@ -7526,7 +7526,7 @@ namespace ts { function getFreshTypeOfLiteralType(type: Type) { if (type.flags & TypeFlags.StringOrNumberLiteral && !(type.flags & TypeFlags.FreshLiteral)) { if (!(type).freshType) { - const freshType = createLiteralType(type.flags | TypeFlags.FreshLiteral, (type).value); + const freshType = createLiteralType(type.flags | TypeFlags.FreshLiteral, (type).value, (type).symbol); freshType.regularType = type; (type).freshType = freshType; } @@ -7539,12 +7539,17 @@ namespace ts { return type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral ? (type).regularType : type; } - function getLiteralType(value: string | number) { - const map = typeof value === "number" ? numericLiteralTypes : stringLiteralTypes; - const text = "" + value; - let type = map.get(text); + function getLiteralType(value: string | number, enumId?: number, symbol?: Symbol) { + // We store all literal types in a single map with keys of the form '#NNN' and '@SSS', + // where NNN is the text representation of a numeric literal and SSS are the characters + // of a string literal. For literal enum members we use 'EEE#NNN' and 'EEE@SSS', where + // EEE is a unique id for the containing enum type. + const qualifier = typeof value === "number" ? "#" : "@"; + const key = enumId ? enumId + qualifier + value : qualifier + value; + let type = literalTypes.get(key); if (!type) { - map.set(text, type = createLiteralType(typeof value === "number" ? TypeFlags.NumberLiteral : TypeFlags.StringLiteral, value)); + const flags = (typeof value === "number" ? TypeFlags.NumberLiteral : TypeFlags.StringLiteral) | (enumId ? TypeFlags.EnumLiteral : 0); + literalTypes.set(key, type = createLiteralType(flags, value, symbol)); } return type; } @@ -20716,17 +20721,22 @@ namespace ts { return undefined; } - function computeConstantValue(member: EnumMember): number { + function computeConstantValue(member: EnumMember): string | number { + const enumKind = getEnumKind(getSymbolOfNode(member.parent)); const isConstEnum = isConst(member.parent); const initializer = member.initializer; - const value = evaluate(member.initializer); + const value = enumKind === EnumKind.Literal && !isLiteralEnumMember(member) ? undefined : evaluate(initializer); if (value !== undefined) { - if (isConstEnum && !isFinite(value)) { + if (isConstEnum && typeof value === "number" && !isFinite(value)) { error(initializer, isNaN(value) ? Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN : Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value); } } + else if (enumKind === EnumKind.Literal) { + error(initializer, Diagnostics.Computed_values_are_not_permitted_in_an_enum_with_string_valued_members); + return 0; + } else if (isConstEnum) { error(initializer, Diagnostics.In_const_enum_declarations_member_initializer_must_be_constant_expression); } @@ -20739,7 +20749,7 @@ namespace ts { } return value; - function evaluate(expr: Expression): number { + function evaluate(expr: Expression): string | number { switch (expr.kind) { case SyntaxKind.PrefixUnaryExpression: const value = evaluate((expr).operand); @@ -20770,13 +20780,15 @@ namespace ts { } } break; + case SyntaxKind.StringLiteral: + return (expr).text; case SyntaxKind.NumericLiteral: checkGrammarNumericLiteral(expr); return +(expr).text; case SyntaxKind.ParenthesizedExpression: return evaluate((expr).expression); case SyntaxKind.Identifier: - return evaluateEnumMember(expr, getSymbolOfNode(member.parent), (expr).text); + return nodeIsMissing(expr) ? 0 : evaluateEnumMember(expr, getSymbolOfNode(member.parent), (expr).text); case SyntaxKind.ElementAccessExpression: case SyntaxKind.PropertyAccessExpression: if (isConstantMemberAccess(expr)) { @@ -22476,7 +22488,7 @@ namespace ts { return getNodeLinks(node).flags; } - function getEnumMemberValue(node: EnumMember): number { + function getEnumMemberValue(node: EnumMember): string | number { computeEnumMemberValues(node.parent); return getNodeLinks(node).enumMemberValue; } @@ -22491,7 +22503,7 @@ namespace ts { return false; } - function getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number { + function getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number { if (node.kind === SyntaxKind.EnumMember) { return getEnumMemberValue(node); } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index b69adf708f..43c1c6334c 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1843,6 +1843,10 @@ "category": "Error", "code": 2550 }, + "Computed values are not permitted in an enum with string valued members.": { + "category": "Error", + "code": 2551 + }, "JSX element attributes type '{0}' may not be a union type.": { "category": "Error", "code": 2600 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 669c9f5dd3..0f00f664e0 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1128,7 +1128,7 @@ namespace ts { // check if constant enum value is integer const constantValue = getConstantValue(expression); // isFinite handles cases when constantValue is undefined - return isFinite(constantValue) + return typeof constantValue === "number" && isFinite(constantValue) && Math.floor(constantValue) === constantValue && printerOptions.removeComments; } diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 5c7486debe..074e6489a7 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2248,7 +2248,7 @@ namespace ts { /** * Sets the constant value to emit for an expression. */ - export function setConstantValue(node: PropertyAccessExpression | ElementAccessExpression, value: number) { + export function setConstantValue(node: PropertyAccessExpression | ElementAccessExpression, value: string | number) { const emitNode = getOrCreateEmitNode(node); emitNode.constantValue = value; return node; diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 780e519bb5..5b0623094c 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2498,22 +2498,27 @@ namespace ts { // we pass false as 'generateNameForComputedPropertyName' for a backward compatibility purposes // old emitter always generate 'expression' part of the name as-is. const name = getExpressionForPropertyName(member, /*generateNameForComputedPropertyName*/ false); + const valueExpression = transformEnumMemberDeclarationValue(member); + const innerAssignment = createAssignment( + createElementAccess( + currentNamespaceContainerName, + name + ), + valueExpression + ); + const outerAssignment = valueExpression.kind === SyntaxKind.StringLiteral ? + innerAssignment : + createAssignment( + createElementAccess( + currentNamespaceContainerName, + innerAssignment + ), + name + ); return setTextRange( createStatement( setTextRange( - createAssignment( - createElementAccess( - currentNamespaceContainerName, - createAssignment( - createElementAccess( - currentNamespaceContainerName, - name - ), - transformEnumMemberDeclarationValue(member) - ) - ), - name - ), + outerAssignment, member ) ), @@ -3351,7 +3356,7 @@ namespace ts { return node; } - function tryGetConstEnumValue(node: Node): number { + function tryGetConstEnumValue(node: Node): string | number { if (compilerOptions.isolatedModules) { return undefined; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f17dec4bd1..da69d64e04 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2528,7 +2528,7 @@ namespace ts { isUnknownSymbol(symbol: Symbol): boolean; /* @internal */ getMergedSymbol(symbol: Symbol): Symbol; - getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; + getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number; isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean; /** Follow all aliases to get the original symbol. */ getAliasedSymbol(symbol: Symbol): Symbol; @@ -2731,7 +2731,7 @@ namespace ts { isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult; isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult; // Returns the constant value this property access resolves to, or 'undefined' for a non-constant - getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; + getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number; getReferencedValueDeclaration(reference: Identifier): Declaration; getTypeReferenceSerializationKind(typeName: EntityName, location?: Node): TypeReferenceSerializationKind; isOptionalParameter(node: ParameterDeclaration): boolean; @@ -2869,6 +2869,13 @@ namespace ts { isDeclarationWithCollidingName?: boolean; // True if symbol is block scoped redeclaration bindingElement?: BindingElement; // Binding element associated with property symbol exportsSomeValue?: boolean; // True if module exports some value (not just types) + enumKind?: EnumKind; // Enum declaration classification + } + + /* @internal */ + export const enum EnumKind { + Numeric, // Numeric enum (each member has a TypeFlags.Enum type) + Literal // Literal enum (each member has a TypeFlags.EnumLiteral type) } /* @internal */ @@ -2941,7 +2948,7 @@ namespace ts { resolvedSymbol?: Symbol; // Cached name resolution result resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result maybeTypePredicate?: boolean; // Cached check whether call expression might reference a type predicate - enumMemberValue?: number; // Constant value of enum member + enumMemberValue?: string | number; // Constant value of enum member isVisible?: boolean; // Is this node visible containsArgumentsReference?: boolean; // Whether a function-like declaration contains an 'arguments' reference hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context @@ -3918,7 +3925,7 @@ namespace ts { commentRange?: TextRange; // The text range to use when emitting leading or trailing comments sourceMapRange?: TextRange; // The text range to use when emitting leading or trailing source mappings tokenSourceMapRanges?: TextRange[]; // The text range to use when emitting source mappings for tokens - constantValue?: number; // The constant value of an expression + constantValue?: string | number; // The constant value of an expression externalHelpersModuleName?: Identifier; // The local name for an imported helpers module helpers?: EmitHelper[]; // Emit helpers for the node } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 646a7b22e3..8080f6985e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -349,7 +349,7 @@ namespace ts { Debug.fail(`Literal kind '${node.kind}' not accounted for.`); } - function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) { + export function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) { return leftQuote + escapeNonAsciiCharacters(escapeString(text)) + rightQuote; } diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 41bdf4d8ad..8f61ca9c91 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -330,7 +330,10 @@ namespace ts.SymbolDisplay { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); displayParts.push(spacePart()); - displayParts.push(displayPart(constantValue.toString(), SymbolDisplayPartKind.numericLiteral)); + const valuePart = typeof constantValue === "number" ? + displayPart("" + constantValue, SymbolDisplayPartKind.numericLiteral) : + displayPart(getQuotedEscapedLiteralText('"', constantValue, '"'), SymbolDisplayPartKind.stringLiteral); + displayParts.push(valuePart); } } } From 1f1af2735e26ae73ebf97b29f94245693d1a1430 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 29 Apr 2017 10:13:35 -0700 Subject: [PATCH 13/83] Update test --- tests/cases/conformance/enums/enumErrors.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/cases/conformance/enums/enumErrors.ts b/tests/cases/conformance/enums/enumErrors.ts index ed438bb3ed..99de3d4bc0 100644 --- a/tests/cases/conformance/enums/enumErrors.ts +++ b/tests/cases/conformance/enums/enumErrors.ts @@ -23,8 +23,17 @@ enum E10 { // Enum with computed member intializer of other types enum E11 { - A = '', + A = true, B = new Date(), C = window, D = {} } + +// Enum with string valued member and computed member initializers +enum E12 { + A = '', + B = new Date(), + C = window, + D = {}, + E = 1 + 1, +} From be0fc3bc986b25db417f66131b00508a9959ce86 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 29 Apr 2017 10:13:52 -0700 Subject: [PATCH 14/83] Accept new baselines --- .../baselines/reference/enumErrors.errors.txt | 31 ++++++++++++++++--- tests/baselines/reference/enumErrors.js | 22 +++++++++++-- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/tests/baselines/reference/enumErrors.errors.txt b/tests/baselines/reference/enumErrors.errors.txt index 3efa042ff3..096722fc4b 100644 --- a/tests/baselines/reference/enumErrors.errors.txt +++ b/tests/baselines/reference/enumErrors.errors.txt @@ -3,13 +3,17 @@ tests/cases/conformance/enums/enumErrors.ts(3,6): error TS2431: Enum name cannot tests/cases/conformance/enums/enumErrors.ts(4,6): error TS2431: Enum name cannot be 'string'. tests/cases/conformance/enums/enumErrors.ts(5,6): error TS2431: Enum name cannot be 'boolean'. tests/cases/conformance/enums/enumErrors.ts(9,9): error TS2322: Type 'Number' is not assignable to type 'E5'. -tests/cases/conformance/enums/enumErrors.ts(26,9): error TS2322: Type '""' is not assignable to type 'E11'. +tests/cases/conformance/enums/enumErrors.ts(26,9): error TS2322: Type 'true' is not assignable to type 'E11'. tests/cases/conformance/enums/enumErrors.ts(27,9): error TS2322: Type 'Date' is not assignable to type 'E11'. tests/cases/conformance/enums/enumErrors.ts(28,9): error TS2304: Cannot find name 'window'. tests/cases/conformance/enums/enumErrors.ts(29,9): error TS2322: Type '{}' is not assignable to type 'E11'. +tests/cases/conformance/enums/enumErrors.ts(35,9): error TS2551: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumErrors.ts(36,9): error TS2551: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumErrors.ts(37,9): error TS2551: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumErrors.ts(38,9): error TS2551: Computed values are not permitted in an enum with string valued members. -==== tests/cases/conformance/enums/enumErrors.ts (9 errors) ==== +==== tests/cases/conformance/enums/enumErrors.ts (13 errors) ==== // Enum named with PredefinedTypes enum any { } ~~~ @@ -45,9 +49,9 @@ tests/cases/conformance/enums/enumErrors.ts(29,9): error TS2322: Type '{}' is no // Enum with computed member intializer of other types enum E11 { - A = '', - ~~ -!!! error TS2322: Type '""' is not assignable to type 'E11'. + A = true, + ~~~~ +!!! error TS2322: Type 'true' is not assignable to type 'E11'. B = new Date(), ~~~~~~~~~~ !!! error TS2322: Type 'Date' is not assignable to type 'E11'. @@ -58,4 +62,21 @@ tests/cases/conformance/enums/enumErrors.ts(29,9): error TS2322: Type '{}' is no ~~ !!! error TS2322: Type '{}' is not assignable to type 'E11'. } + + // Enum with string valued member and computed member initializers + enum E12 { + A = '', + B = new Date(), + ~~~~~~~~~~ +!!! error TS2551: Computed values are not permitted in an enum with string valued members. + C = window, + ~~~~~~ +!!! error TS2551: Computed values are not permitted in an enum with string valued members. + D = {}, + ~~ +!!! error TS2551: Computed values are not permitted in an enum with string valued members. + E = 1 + 1, + ~~~~~ +!!! error TS2551: Computed values are not permitted in an enum with string valued members. + } \ No newline at end of file diff --git a/tests/baselines/reference/enumErrors.js b/tests/baselines/reference/enumErrors.js index a8ecdf2470..17b67864c7 100644 --- a/tests/baselines/reference/enumErrors.js +++ b/tests/baselines/reference/enumErrors.js @@ -24,11 +24,20 @@ enum E10 { // Enum with computed member intializer of other types enum E11 { - A = '', + A = true, B = new Date(), C = window, D = {} } + +// Enum with string valued member and computed member initializers +enum E12 { + A = '', + B = new Date(), + C = window, + D = {}, + E = 1 + 1, +} //// [enumErrors.js] @@ -65,8 +74,17 @@ var E10; // Enum with computed member intializer of other types var E11; (function (E11) { - E11[E11["A"] = ''] = "A"; + E11[E11["A"] = true] = "A"; E11[E11["B"] = new Date()] = "B"; E11[E11["C"] = window] = "C"; E11[E11["D"] = {}] = "D"; })(E11 || (E11 = {})); +// Enum with string valued member and computed member initializers +var E12; +(function (E12) { + E12["A"] = ""; + E12[E12["B"] = 0] = "B"; + E12[E12["C"] = 0] = "C"; + E12[E12["D"] = 0] = "D"; + E12[E12["E"] = 0] = "E"; +})(E12 || (E12 = {})); From 63319d1ed99fd7f2a4c5deb7f7599310c757a161 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 29 Apr 2017 15:27:25 -0700 Subject: [PATCH 15/83] Treat enums with a single literal member as literal enums --- src/compiler/checker.ts | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 689d3e44a7..ebc5c0677b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3047,9 +3047,14 @@ namespace ts { writeTypeReference(type, nextFlags); } else if (type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union)) { - buildSymbolDisplay(getParentOfSymbol(type.symbol), writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags); - writePunctuation(writer, SyntaxKind.DotToken); - appendSymbolNameOnly(type.symbol, writer); + const parent = getParentOfSymbol(type.symbol); + buildSymbolDisplay(parent, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags); + // In a literal enum type with a single member E { A }, E and E.A denote the + // same type. We always display this type simply as E. + if (getDeclaredTypeOfSymbol(parent).flags & TypeFlags.Union) { + writePunctuation(writer, SyntaxKind.DotToken); + appendSymbolNameOnly(type.symbol, writer); + } } else if (getObjectFlags(type) & ObjectFlags.ClassOrInterface || type.flags & (TypeFlags.EnumLike | TypeFlags.TypeParameter)) { // The specified symbol flags need to be reinterpreted as type flags @@ -4952,23 +4957,19 @@ namespace ts { if (declaration.kind === SyntaxKind.EnumDeclaration) { for (const member of (declaration).members) { const memberType = getLiteralType(getEnumMemberValue(member), enumCount, getSymbolOfNode(member)); + getSymbolLinks(getSymbolOfNode(member)).declaredType = memberType; if (!contains(memberTypeList, memberType)) { memberTypeList.push(memberType); } } } } - if (memberTypeList.length > 1) { - for (const declaration of symbol.declarations) { - if (declaration.kind === SyntaxKind.EnumDeclaration) { - for (const member of (declaration).members) { - getSymbolLinks(getSymbolOfNode(member)).declaredType = getLiteralType(getEnumMemberValue(member), enumCount, getSymbolOfNode(member)); - } - } - } + if (memberTypeList.length) { const enumType = getUnionType(memberTypeList, /*subtypeReduction*/ false, symbol, /*aliasTypeArguments*/ undefined); - enumType.flags |= TypeFlags.EnumLiteral; - enumType.symbol = symbol; + if (enumType.flags & TypeFlags.Union) { + enumType.flags |= TypeFlags.EnumLiteral; + enumType.symbol = symbol; + } return links.declaredType = enumType; } } From 72e77a80e81e66594a8f024a21c09336c97d59aa Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 29 Apr 2017 15:27:42 -0700 Subject: [PATCH 16/83] Accept new baselines --- tests/baselines/reference/bestCommonTypeOfTuple.types | 4 ++-- tests/baselines/reference/computedPropertyNames47_ES5.types | 2 +- tests/baselines/reference/computedPropertyNames47_ES6.types | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/bestCommonTypeOfTuple.types b/tests/baselines/reference/bestCommonTypeOfTuple.types index 82c96ecb86..d62503b57d 100644 --- a/tests/baselines/reference/bestCommonTypeOfTuple.types +++ b/tests/baselines/reference/bestCommonTypeOfTuple.types @@ -98,8 +98,8 @@ var e3 = t3[2]; // any >2 : 2 var e4 = t4[3]; // number ->e4 : number | E1 | E2 ->t4[3] : number | E1 | E2 +>e4 : number +>t4[3] : number >t4 : [E1, E2, number] >3 : 3 diff --git a/tests/baselines/reference/computedPropertyNames47_ES5.types b/tests/baselines/reference/computedPropertyNames47_ES5.types index 19811ae8ec..137f3d63d3 100644 --- a/tests/baselines/reference/computedPropertyNames47_ES5.types +++ b/tests/baselines/reference/computedPropertyNames47_ES5.types @@ -12,7 +12,7 @@ var o = { >{ [E1.x || E2.x]: 0} : { [x: number]: number; } [E1.x || E2.x]: 0 ->E1.x || E2.x : E1 | E2 +>E1.x || E2.x : E2 >E1.x : E1 >E1 : typeof E1 >x : E1 diff --git a/tests/baselines/reference/computedPropertyNames47_ES6.types b/tests/baselines/reference/computedPropertyNames47_ES6.types index 46edecb450..04c18df83a 100644 --- a/tests/baselines/reference/computedPropertyNames47_ES6.types +++ b/tests/baselines/reference/computedPropertyNames47_ES6.types @@ -12,7 +12,7 @@ var o = { >{ [E1.x || E2.x]: 0} : { [x: number]: number; } [E1.x || E2.x]: 0 ->E1.x || E2.x : E1 | E2 +>E1.x || E2.x : E2 >E1.x : E1 >E1 : typeof E1 >x : E1 From 106214a0e4022732ff3d7ae052be82259de3d941 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 29 Apr 2017 17:57:12 -0700 Subject: [PATCH 17/83] Enum literal type is assignable to regular literal type with same value --- src/compiler/checker.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ebc5c0677b..90ca808342 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8432,7 +8432,13 @@ namespace ts { if (target.flags & TypeFlags.Never) return false; if (target.flags & TypeFlags.Any || source.flags & TypeFlags.Never) return true; if (source.flags & TypeFlags.StringLike && target.flags & TypeFlags.String) return true; + if (source.flags & TypeFlags.StringLiteral && source.flags & TypeFlags.EnumLiteral && + target.flags & TypeFlags.StringLiteral && !(target.flags & TypeFlags.EnumLiteral) && + (source).value === (target).value) return true; if (source.flags & TypeFlags.NumberLike && target.flags & TypeFlags.Number) return true; + if (source.flags & TypeFlags.NumberLiteral && source.flags & TypeFlags.EnumLiteral && + target.flags & TypeFlags.NumberLiteral && !(target.flags & TypeFlags.EnumLiteral) && + (source).value === (target).value) return true; if (source.flags & TypeFlags.BooleanLike && target.flags & TypeFlags.Boolean) return true; if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; if (source.flags & TypeFlags.EnumLiteral && target.flags & TypeFlags.EnumLiteral) { @@ -8446,7 +8452,11 @@ namespace ts { if (source.flags & TypeFlags.Object && target.flags & TypeFlags.NonPrimitive) return true; if (relation === assignableRelation || relation === comparableRelation) { if (source.flags & TypeFlags.Any) return true; - if (source.flags & (TypeFlags.Number | TypeFlags.NumberLiteral) && !(source.flags & TypeFlags.EnumLiteral) && target.flags & TypeFlags.EnumLike) return true; + // Type number or any numeric literal type is assignable to any numeric enum type or any + // numeric enum literal type. This rule exists for backwards compatibility reasons because + // bit-flag enum types sometimes look like literal enum types with numeric literal values. + if (source.flags & (TypeFlags.Number | TypeFlags.NumberLiteral) && !(source.flags & TypeFlags.EnumLiteral) && ( + target.flags & TypeFlags.Enum || target.flags & TypeFlags.NumberLiteral && target.flags & TypeFlags.EnumLiteral)) return true; } return false; } From 68036c57b6381a7980b3e4eddcf8b2f5eea31d66 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 29 Apr 2017 17:58:16 -0700 Subject: [PATCH 18/83] Accept new baselines --- .../typeArgumentInferenceWithObjectLiteral.errors.txt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/baselines/reference/typeArgumentInferenceWithObjectLiteral.errors.txt b/tests/baselines/reference/typeArgumentInferenceWithObjectLiteral.errors.txt index e82e7e020d..c1352bedb9 100644 --- a/tests/baselines/reference/typeArgumentInferenceWithObjectLiteral.errors.txt +++ b/tests/baselines/reference/typeArgumentInferenceWithObjectLiteral.errors.txt @@ -1,10 +1,8 @@ -tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithObjectLiteral.ts(30,10): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly. - Type argument candidate 'E1' is not a valid type argument because it is not a supertype of candidate '0'. tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithObjectLiteral.ts(35,10): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly. Type argument candidate 'E1' is not a valid type argument because it is not a supertype of candidate 'E2'. -==== tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithObjectLiteral.ts (2 errors) ==== +==== tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithObjectLiteral.ts (1 errors) ==== interface Computed { read(): T; write(value: T); @@ -35,9 +33,6 @@ tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithObjec var v1 = f1({ w: x => x, r: () => 0 }, 0); var v1 = f1({ w: x => x, r: () => 0 }, E1.X); var v1 = f1({ w: x => x, r: () => E1.X }, 0); - ~~ -!!! error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly. -!!! error TS2453: Type argument candidate 'E1' is not a valid type argument because it is not a supertype of candidate '0'. var v2: E1; var v2 = f1({ w: x => x, r: () => E1.X }, E1.X); From 925d97dc25a22f6f4284d2721deb8fe6aee9934d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 29 Apr 2017 18:09:36 -0700 Subject: [PATCH 19/83] Cache source and target flags in local variables --- src/compiler/checker.ts | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 90ca808342..c88951d8f2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8429,34 +8429,36 @@ namespace ts { } function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map, errorReporter?: ErrorReporter) { - if (target.flags & TypeFlags.Never) return false; - if (target.flags & TypeFlags.Any || source.flags & TypeFlags.Never) return true; - if (source.flags & TypeFlags.StringLike && target.flags & TypeFlags.String) return true; - if (source.flags & TypeFlags.StringLiteral && source.flags & TypeFlags.EnumLiteral && - target.flags & TypeFlags.StringLiteral && !(target.flags & TypeFlags.EnumLiteral) && + const s = source.flags; + const t = target.flags; + if (t & TypeFlags.Never) return false; + if (t & TypeFlags.Any || s & TypeFlags.Never) return true; + if (s & TypeFlags.StringLike && t & TypeFlags.String) return true; + if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral && + t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) && (source).value === (target).value) return true; - if (source.flags & TypeFlags.NumberLike && target.flags & TypeFlags.Number) return true; - if (source.flags & TypeFlags.NumberLiteral && source.flags & TypeFlags.EnumLiteral && - target.flags & TypeFlags.NumberLiteral && !(target.flags & TypeFlags.EnumLiteral) && + if (s & TypeFlags.NumberLike && t & TypeFlags.Number) return true; + if (s & TypeFlags.NumberLiteral && s & TypeFlags.EnumLiteral && + t & TypeFlags.NumberLiteral && !(t & TypeFlags.EnumLiteral) && (source).value === (target).value) return true; - if (source.flags & TypeFlags.BooleanLike && target.flags & TypeFlags.Boolean) return true; - if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; - if (source.flags & TypeFlags.EnumLiteral && target.flags & TypeFlags.EnumLiteral) { - if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; - if (source.flags & TypeFlags.Literal && target.flags & TypeFlags.Literal && + if (s & TypeFlags.BooleanLike && t & TypeFlags.Boolean) return true; + if (s & TypeFlags.Enum && t & TypeFlags.Enum && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; + if (s & TypeFlags.EnumLiteral && t & TypeFlags.EnumLiteral) { + if (s & TypeFlags.Union && t & TypeFlags.Union && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; + if (s & TypeFlags.Literal && t & TypeFlags.Literal && (source).value === (target).value && isEnumTypeRelatedTo(getParentOfSymbol(source.symbol), getParentOfSymbol(target.symbol), errorReporter)) return true; } - if (source.flags & TypeFlags.Undefined && (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void))) return true; - if (source.flags & TypeFlags.Null && (!strictNullChecks || target.flags & TypeFlags.Null)) return true; - if (source.flags & TypeFlags.Object && target.flags & TypeFlags.NonPrimitive) return true; + if (s & TypeFlags.Undefined && (!strictNullChecks || t & (TypeFlags.Undefined | TypeFlags.Void))) return true; + if (s & TypeFlags.Null && (!strictNullChecks || t & TypeFlags.Null)) return true; + if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive) return true; if (relation === assignableRelation || relation === comparableRelation) { - if (source.flags & TypeFlags.Any) return true; + if (s & TypeFlags.Any) return true; // Type number or any numeric literal type is assignable to any numeric enum type or any // numeric enum literal type. This rule exists for backwards compatibility reasons because // bit-flag enum types sometimes look like literal enum types with numeric literal values. - if (source.flags & (TypeFlags.Number | TypeFlags.NumberLiteral) && !(source.flags & TypeFlags.EnumLiteral) && ( - target.flags & TypeFlags.Enum || target.flags & TypeFlags.NumberLiteral && target.flags & TypeFlags.EnumLiteral)) return true; + if (s & (TypeFlags.Number | TypeFlags.NumberLiteral) && !(s & TypeFlags.EnumLiteral) && ( + t & TypeFlags.Enum || t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral)) return true; } return false; } From 3a96b245315ec6e15da6d306b79b760a2fa15816 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 30 Apr 2017 15:49:14 -0700 Subject: [PATCH 20/83] Update comment --- src/compiler/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index da69d64e04..55b5492b43 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2968,7 +2968,7 @@ namespace ts { StringLiteral = 1 << 5, NumberLiteral = 1 << 6, BooleanLiteral = 1 << 7, - EnumLiteral = 1 << 8, // Enum literal or union of enum literals + EnumLiteral = 1 << 8, // Always combined with StringLiteral, NumberLiteral, or Union ESSymbol = 1 << 9, // Type of symbol primitive introduced in ES6 Void = 1 << 10, Undefined = 1 << 11, From 21d8e9a6fdabb37136aacf185a05ad53a76d06bd Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 30 Apr 2017 16:06:07 -0700 Subject: [PATCH 21/83] Update old test --- .../baselines/reference/enumBasics.errors.txt | 86 -------------- tests/baselines/reference/enumBasics.js | 6 +- tests/baselines/reference/enumBasics.symbols | 13 +- tests/baselines/reference/enumBasics.types | 111 +++++++++--------- tests/cases/conformance/enums/enumBasics.ts | 6 +- 5 files changed, 71 insertions(+), 151 deletions(-) delete mode 100644 tests/baselines/reference/enumBasics.errors.txt diff --git a/tests/baselines/reference/enumBasics.errors.txt b/tests/baselines/reference/enumBasics.errors.txt deleted file mode 100644 index 4d82402b8e..0000000000 --- a/tests/baselines/reference/enumBasics.errors.txt +++ /dev/null @@ -1,86 +0,0 @@ -tests/cases/conformance/enums/enumBasics.ts(13,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'e' must be of type 'typeof E1', but here has type '{ readonly [n: number]: string; readonly A: E1; readonly B: E1; readonly C: E1; }'. - - -==== tests/cases/conformance/enums/enumBasics.ts (1 errors) ==== - // Enum without initializers have first member = 0 and successive members = N + 1 - enum E1 { - A, - B, - C - } - - // Enum type is a subtype of Number - var x: number = E1.A; - - // Enum object type is anonymous with properties of the enum type and numeric indexer - var e = E1; - var e: { - ~ -!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'e' must be of type 'typeof E1', but here has type '{ readonly [n: number]: string; readonly A: E1; readonly B: E1; readonly C: E1; }'. - readonly A: E1; - readonly B: E1; - readonly C: E1; - readonly [n: number]: string; - }; - var e: typeof E1; - - // Reverse mapping of enum returns string name of property - var s = E1[e.A]; - var s: string; - - - // Enum with only constant members - enum E2 { - A = 1, B = 2, C = 3 - } - - // Enum with only computed members - enum E3 { - X = 'foo'.length, Y = 4 + 3, Z = +'foo' - } - - // Enum with constant members followed by computed members - enum E4 { - X = 0, Y, Z = 'foo'.length - } - - // Enum with > 2 constant members with no initializer for first member, non zero initializer for second element - enum E5 { - A, - B = 3, - C // 4 - } - - enum E6 { - A, - B = 0, - C // 1 - } - - // Enum with computed member initializer of type 'any' - enum E7 { - A = 'foo'['foo'] - } - - // Enum with computed member initializer of type number - enum E8 { - B = 'foo'['foo'] - } - - //Enum with computed member intializer of same enum type - enum E9 { - A, - B = A - } - - // (refer to .js to validate) - // Enum constant members are propagated - var doNotPropagate = [ - E8.B, E7.A, E4.Z, E3.X, E3.Y, E3.Z - ]; - // Enum computed members are not propagated - var doPropagate = [ - E9.A, E9.B, E6.B, E6.C, E6.A, E5.A, E5.B, E5.C - ]; - - \ No newline at end of file diff --git a/tests/baselines/reference/enumBasics.js b/tests/baselines/reference/enumBasics.js index 4ac41c0f3d..3db9bc566c 100644 --- a/tests/baselines/reference/enumBasics.js +++ b/tests/baselines/reference/enumBasics.js @@ -12,9 +12,9 @@ var x: number = E1.A; // Enum object type is anonymous with properties of the enum type and numeric indexer var e = E1; var e: { - readonly A: E1; - readonly B: E1; - readonly C: E1; + readonly A: E1.A; + readonly B: E1.B; + readonly C: E1.C; readonly [n: number]: string; }; var e: typeof E1; diff --git a/tests/baselines/reference/enumBasics.symbols b/tests/baselines/reference/enumBasics.symbols index ce81a80ca5..948c171183 100644 --- a/tests/baselines/reference/enumBasics.symbols +++ b/tests/baselines/reference/enumBasics.symbols @@ -28,17 +28,20 @@ var e = E1; var e: { >e : Symbol(e, Decl(enumBasics.ts, 11, 3), Decl(enumBasics.ts, 12, 3), Decl(enumBasics.ts, 18, 3)) - readonly A: E1; + readonly A: E1.A; >A : Symbol(A, Decl(enumBasics.ts, 12, 8)) >E1 : Symbol(E1, Decl(enumBasics.ts, 0, 0)) +>A : Symbol(E1.A, Decl(enumBasics.ts, 1, 9)) - readonly B: E1; ->B : Symbol(B, Decl(enumBasics.ts, 13, 19)) + readonly B: E1.B; +>B : Symbol(B, Decl(enumBasics.ts, 13, 21)) >E1 : Symbol(E1, Decl(enumBasics.ts, 0, 0)) +>B : Symbol(E1.B, Decl(enumBasics.ts, 2, 6)) - readonly C: E1; ->C : Symbol(C, Decl(enumBasics.ts, 14, 19)) + readonly C: E1.C; +>C : Symbol(C, Decl(enumBasics.ts, 14, 21)) >E1 : Symbol(E1, Decl(enumBasics.ts, 0, 0)) +>C : Symbol(E1.C, Decl(enumBasics.ts, 3, 6)) readonly [n: number]: string; >n : Symbol(n, Decl(enumBasics.ts, 16, 14)) diff --git a/tests/baselines/reference/enumBasics.types b/tests/baselines/reference/enumBasics.types index 9e68b06bc3..c2e1ac94fd 100644 --- a/tests/baselines/reference/enumBasics.types +++ b/tests/baselines/reference/enumBasics.types @@ -4,21 +4,21 @@ enum E1 { >E1 : E1 A, ->A : E1 +>A : E1.A B, ->B : E1 +>B : E1.B C ->C : E1 +>C : E1.C } // Enum type is a subtype of Number var x: number = E1.A; >x : number ->E1.A : E1 +>E1.A : E1.A >E1 : typeof E1 ->A : E1 +>A : E1.A // Enum object type is anonymous with properties of the enum type and numeric indexer var e = E1; @@ -28,17 +28,20 @@ var e = E1; var e: { >e : typeof E1 - readonly A: E1; ->A : E1 ->E1 : E1 + readonly A: E1.A; +>A : E1.A +>E1 : any +>A : E1.A - readonly B: E1; ->B : E1 ->E1 : E1 + readonly B: E1.B; +>B : E1.B +>E1 : any +>B : E1.B - readonly C: E1; ->C : E1 ->E1 : E1 + readonly C: E1.C; +>C : E1.C +>E1 : any +>C : E1.C readonly [n: number]: string; >n : number @@ -53,9 +56,9 @@ var s = E1[e.A]; >s : string >E1[e.A] : string >E1 : typeof E1 ->e.A : E1 +>e.A : E1.A >e : typeof E1 ->A : E1 +>A : E1.A var s: string; >s : string @@ -66,12 +69,12 @@ enum E2 { >E2 : E2 A = 1, B = 2, C = 3 ->A : E2 ->1 : number ->B : E2 ->2 : number ->C : E2 ->3 : number +>A : E2.A +>1 : 1 +>B : E2.B +>2 : 2 +>C : E2.C +>3 : 3 } // Enum with only computed members @@ -81,15 +84,15 @@ enum E3 { X = 'foo'.length, Y = 4 + 3, Z = +'foo' >X : E3 >'foo'.length : number ->'foo' : string +>'foo' : "foo" >length : number >Y : E3 >4 + 3 : number ->4 : number ->3 : number +>4 : 4 +>3 : 3 >Z : E3 >+'foo' : number ->'foo' : string +>'foo' : "foo" } // Enum with constant members followed by computed members @@ -98,11 +101,11 @@ enum E4 { X = 0, Y, Z = 'foo'.length >X : E4 ->0 : number +>0 : 0 >Y : E4 >Z : E4 >'foo'.length : number ->'foo' : string +>'foo' : "foo" >length : number } @@ -111,28 +114,28 @@ enum E5 { >E5 : E5 A, ->A : E5 +>A : E5.A B = 3, ->B : E5 ->3 : number +>B : E5.B +>3 : 3 C // 4 ->C : E5 +>C : E5.C } enum E6 { >E6 : E6 A, ->A : E6 +>A : E6.A B = 0, ->B : E6 ->0 : number +>B : E6.A +>0 : 0 C // 1 ->C : E6 +>C : E6.C } // Enum with computed member initializer of type 'any' @@ -142,8 +145,8 @@ enum E7 { A = 'foo'['foo'] >A : E7 >'foo'['foo'] : any ->'foo' : string ->'foo' : string +>'foo' : "foo" +>'foo' : "foo" } // Enum with computed member initializer of type number @@ -153,8 +156,8 @@ enum E8 { B = 'foo'['foo'] >B : E8 >'foo'['foo'] : any ->'foo' : string ->'foo' : string +>'foo' : "foo" +>'foo' : "foo" } //Enum with computed member intializer of same enum type @@ -198,8 +201,8 @@ var doNotPropagate = [ ]; // Enum computed members are not propagated var doPropagate = [ ->doPropagate : (E5 | E6 | E9)[] ->[ E9.A, E9.B, E6.B, E6.C, E6.A, E5.A, E5.B, E5.C] : (E5 | E6 | E9)[] +>doPropagate : (E9 | E6 | E5)[] +>[ E9.A, E9.B, E6.B, E6.C, E6.A, E5.A, E5.B, E5.C] : (E9 | E6 | E5)[] E9.A, E9.B, E6.B, E6.C, E6.A, E5.A, E5.B, E5.C >E9.A : E9 @@ -208,24 +211,24 @@ var doPropagate = [ >E9.B : E9 >E9 : typeof E9 >B : E9 ->E6.B : E6 +>E6.B : E6.A >E6 : typeof E6 ->B : E6 ->E6.C : E6 +>B : E6.A +>E6.C : E6.C >E6 : typeof E6 ->C : E6 ->E6.A : E6 +>C : E6.C +>E6.A : E6.A >E6 : typeof E6 ->A : E6 ->E5.A : E5 +>A : E6.A +>E5.A : E5.A >E5 : typeof E5 ->A : E5 ->E5.B : E5 +>A : E5.A +>E5.B : E5.B >E5 : typeof E5 ->B : E5 ->E5.C : E5 +>B : E5.B +>E5.C : E5.C >E5 : typeof E5 ->C : E5 +>C : E5.C ]; diff --git a/tests/cases/conformance/enums/enumBasics.ts b/tests/cases/conformance/enums/enumBasics.ts index 1e13454071..0a0f9d920c 100644 --- a/tests/cases/conformance/enums/enumBasics.ts +++ b/tests/cases/conformance/enums/enumBasics.ts @@ -11,9 +11,9 @@ var x: number = E1.A; // Enum object type is anonymous with properties of the enum type and numeric indexer var e = E1; var e: { - readonly A: E1; - readonly B: E1; - readonly C: E1; + readonly A: E1.A; + readonly B: E1.B; + readonly C: E1.C; readonly [n: number]: string; }; var e: typeof E1; From 6548bcf104d608740ba37d179f6d0290f63e7301 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 30 Apr 2017 16:06:26 -0700 Subject: [PATCH 22/83] Add new tests --- .../baselines/reference/enumClassification.js | 308 ++++++++++++++ .../reference/enumClassification.symbols | 167 ++++++++ .../reference/enumClassification.types | 196 +++++++++ .../reference/stringEnumLiteralTypes1.js | 178 ++++++++ .../reference/stringEnumLiteralTypes1.symbols | 353 ++++++++++++++++ .../reference/stringEnumLiteralTypes1.types | 383 ++++++++++++++++++ .../reference/stringEnumLiteralTypes2.js | 178 ++++++++ .../reference/stringEnumLiteralTypes2.symbols | 353 ++++++++++++++++ .../reference/stringEnumLiteralTypes2.types | 383 ++++++++++++++++++ .../stringEnumLiteralTypes3.errors.txt | 166 ++++++++ .../reference/stringEnumLiteralTypes3.js | 225 ++++++++++ .../conformance/enums/enumClassification.ts | 80 ++++ .../types/literal/stringEnumLiteralTypes1.ts | 99 +++++ .../types/literal/stringEnumLiteralTypes2.ts | 101 +++++ .../types/literal/stringEnumLiteralTypes3.ts | 119 ++++++ 15 files changed, 3289 insertions(+) create mode 100644 tests/baselines/reference/enumClassification.js create mode 100644 tests/baselines/reference/enumClassification.symbols create mode 100644 tests/baselines/reference/enumClassification.types create mode 100644 tests/baselines/reference/stringEnumLiteralTypes1.js create mode 100644 tests/baselines/reference/stringEnumLiteralTypes1.symbols create mode 100644 tests/baselines/reference/stringEnumLiteralTypes1.types create mode 100644 tests/baselines/reference/stringEnumLiteralTypes2.js create mode 100644 tests/baselines/reference/stringEnumLiteralTypes2.symbols create mode 100644 tests/baselines/reference/stringEnumLiteralTypes2.types create mode 100644 tests/baselines/reference/stringEnumLiteralTypes3.errors.txt create mode 100644 tests/baselines/reference/stringEnumLiteralTypes3.js create mode 100644 tests/cases/conformance/enums/enumClassification.ts create mode 100644 tests/cases/conformance/types/literal/stringEnumLiteralTypes1.ts create mode 100644 tests/cases/conformance/types/literal/stringEnumLiteralTypes2.ts create mode 100644 tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts diff --git a/tests/baselines/reference/enumClassification.js b/tests/baselines/reference/enumClassification.js new file mode 100644 index 0000000000..f153230002 --- /dev/null +++ b/tests/baselines/reference/enumClassification.js @@ -0,0 +1,308 @@ +//// [enumClassification.ts] +// An enum type where each member has no initializer or an initializer that specififes +// a numeric literal, a string literal, or a single identifier naming another member in +// the enum type is classified as a literal enum type. An enum type that doesn't adhere +// to this pattern is classified as a numeric enum type. + +// Examples of literal enum types + +enum E01 { + A +} + +enum E02 { + A = 123 +} + +enum E03 { + A = "hello" +} + +enum E04 { + A, + B, + C +} + +enum E05 { + A, + B = 10, + C +} + +enum E06 { + A = "one", + B = "two", + C = "three" +} + +enum E07 { + A, + B, + C = "hi", + D = 10, + E, + F = "bye" +} + +enum E08 { + A = 10, + B = "hello", + C = A, + D = B, + E = C, +} + +// Examples of numeric enum types with only constant members + +enum E10 {} + +enum E11 { + A = +0, + B, + C +} + +enum E12 { + A = 1 << 0, + B = 1 << 1, + C = 1 << 2 +} + +// Examples of numeric enum types with constant and computed members + +enum E20 { + A = "foo".length, + B = A + 1, + C = +"123", + D = Math.sin(1) +} + + +//// [enumClassification.js] +// An enum type where each member has no initializer or an initializer that specififes +// a numeric literal, a string literal, or a single identifier naming another member in +// the enum type is classified as a literal enum type. An enum type that doesn't adhere +// to this pattern is classified as a numeric enum type. +// Examples of literal enum types +var E01; +(function (E01) { + E01[E01["A"] = 0] = "A"; +})(E01 || (E01 = {})); +var E02; +(function (E02) { + E02[E02["A"] = 123] = "A"; +})(E02 || (E02 = {})); +var E03; +(function (E03) { + E03["A"] = "hello"; +})(E03 || (E03 = {})); +var E04; +(function (E04) { + E04[E04["A"] = 0] = "A"; + E04[E04["B"] = 1] = "B"; + E04[E04["C"] = 2] = "C"; +})(E04 || (E04 = {})); +var E05; +(function (E05) { + E05[E05["A"] = 0] = "A"; + E05[E05["B"] = 10] = "B"; + E05[E05["C"] = 11] = "C"; +})(E05 || (E05 = {})); +var E06; +(function (E06) { + E06["A"] = "one"; + E06["B"] = "two"; + E06["C"] = "three"; +})(E06 || (E06 = {})); +var E07; +(function (E07) { + E07[E07["A"] = 0] = "A"; + E07[E07["B"] = 1] = "B"; + E07["C"] = "hi"; + E07[E07["D"] = 10] = "D"; + E07[E07["E"] = 11] = "E"; + E07["F"] = "bye"; +})(E07 || (E07 = {})); +var E08; +(function (E08) { + E08[E08["A"] = 10] = "A"; + E08["B"] = "hello"; + E08[E08["C"] = 10] = "C"; + E08["D"] = "hello"; + E08[E08["E"] = 10] = "E"; +})(E08 || (E08 = {})); +// Examples of numeric enum types with only constant members +var E10; +(function (E10) { +})(E10 || (E10 = {})); +var E11; +(function (E11) { + E11[E11["A"] = 0] = "A"; + E11[E11["B"] = 1] = "B"; + E11[E11["C"] = 2] = "C"; +})(E11 || (E11 = {})); +var E12; +(function (E12) { + E12[E12["A"] = 1] = "A"; + E12[E12["B"] = 2] = "B"; + E12[E12["C"] = 4] = "C"; +})(E12 || (E12 = {})); +// Examples of numeric enum types with constant and computed members +var E20; +(function (E20) { + E20[E20["A"] = "foo".length] = "A"; + E20[E20["B"] = E20.A + 1] = "B"; + E20[E20["C"] = +"123"] = "C"; + E20[E20["D"] = Math.sin(1)] = "D"; +})(E20 || (E20 = {})); + + +//// [enumClassification.d.ts] +declare enum E01 { + A = 0, +} +declare enum E02 { + A = 123, +} +declare enum E03 { + A = hello, +} +declare enum E04 { + A = 0, + B = 1, + C = 2, +} +declare enum E05 { + A = 0, + B = 10, + C = 11, +} +declare enum E06 { + A = one, + B = two, + C = three, +} +declare enum E07 { + A = 0, + B = 1, + C = hi, + D = 10, + E = 11, + F = bye, +} +declare enum E08 { + A = 10, + B = hello, + C = 10, + D = hello, + E = 10, +} +declare enum E10 { +} +declare enum E11 { + A = 0, + B = 1, + C = 2, +} +declare enum E12 { + A = 1, + B = 2, + C = 4, +} +declare enum E20 { + A, + B, + C, + D, +} + + +//// [DtsFileErrors] + + +tests/cases/conformance/enums/enumClassification.d.ts(8,9): error TS1066: In ambient enum declarations member initializer must be constant expression. +tests/cases/conformance/enums/enumClassification.d.ts(21,9): error TS1066: In ambient enum declarations member initializer must be constant expression. +tests/cases/conformance/enums/enumClassification.d.ts(22,9): error TS1066: In ambient enum declarations member initializer must be constant expression. +tests/cases/conformance/enums/enumClassification.d.ts(23,9): error TS1066: In ambient enum declarations member initializer must be constant expression. +tests/cases/conformance/enums/enumClassification.d.ts(28,9): error TS1066: In ambient enum declarations member initializer must be constant expression. +tests/cases/conformance/enums/enumClassification.d.ts(31,9): error TS1066: In ambient enum declarations member initializer must be constant expression. +tests/cases/conformance/enums/enumClassification.d.ts(35,9): error TS1066: In ambient enum declarations member initializer must be constant expression. +tests/cases/conformance/enums/enumClassification.d.ts(37,9): error TS1066: In ambient enum declarations member initializer must be constant expression. + + +==== tests/cases/conformance/enums/enumClassification.d.ts (8 errors) ==== + declare enum E01 { + A = 0, + } + declare enum E02 { + A = 123, + } + declare enum E03 { + A = hello, + ~~~~~ +!!! error TS1066: In ambient enum declarations member initializer must be constant expression. + } + declare enum E04 { + A = 0, + B = 1, + C = 2, + } + declare enum E05 { + A = 0, + B = 10, + C = 11, + } + declare enum E06 { + A = one, + ~~~ +!!! error TS1066: In ambient enum declarations member initializer must be constant expression. + B = two, + ~~~ +!!! error TS1066: In ambient enum declarations member initializer must be constant expression. + C = three, + ~~~~~ +!!! error TS1066: In ambient enum declarations member initializer must be constant expression. + } + declare enum E07 { + A = 0, + B = 1, + C = hi, + ~~ +!!! error TS1066: In ambient enum declarations member initializer must be constant expression. + D = 10, + E = 11, + F = bye, + ~~~ +!!! error TS1066: In ambient enum declarations member initializer must be constant expression. + } + declare enum E08 { + A = 10, + B = hello, + ~~~~~ +!!! error TS1066: In ambient enum declarations member initializer must be constant expression. + C = 10, + D = hello, + ~~~~~ +!!! error TS1066: In ambient enum declarations member initializer must be constant expression. + E = 10, + } + declare enum E10 { + } + declare enum E11 { + A = 0, + B = 1, + C = 2, + } + declare enum E12 { + A = 1, + B = 2, + C = 4, + } + declare enum E20 { + A, + B, + C, + D, + } + \ No newline at end of file diff --git a/tests/baselines/reference/enumClassification.symbols b/tests/baselines/reference/enumClassification.symbols new file mode 100644 index 0000000000..119162e26a --- /dev/null +++ b/tests/baselines/reference/enumClassification.symbols @@ -0,0 +1,167 @@ +=== tests/cases/conformance/enums/enumClassification.ts === +// An enum type where each member has no initializer or an initializer that specififes +// a numeric literal, a string literal, or a single identifier naming another member in +// the enum type is classified as a literal enum type. An enum type that doesn't adhere +// to this pattern is classified as a numeric enum type. + +// Examples of literal enum types + +enum E01 { +>E01 : Symbol(E01, Decl(enumClassification.ts, 0, 0)) + + A +>A : Symbol(E01.A, Decl(enumClassification.ts, 7, 10)) +} + +enum E02 { +>E02 : Symbol(E02, Decl(enumClassification.ts, 9, 1)) + + A = 123 +>A : Symbol(E02.A, Decl(enumClassification.ts, 11, 10)) +} + +enum E03 { +>E03 : Symbol(E03, Decl(enumClassification.ts, 13, 1)) + + A = "hello" +>A : Symbol(E03.A, Decl(enumClassification.ts, 15, 10)) +} + +enum E04 { +>E04 : Symbol(E04, Decl(enumClassification.ts, 17, 1)) + + A, +>A : Symbol(E04.A, Decl(enumClassification.ts, 19, 10)) + + B, +>B : Symbol(E04.B, Decl(enumClassification.ts, 20, 6)) + + C +>C : Symbol(E04.C, Decl(enumClassification.ts, 21, 6)) +} + +enum E05 { +>E05 : Symbol(E05, Decl(enumClassification.ts, 23, 1)) + + A, +>A : Symbol(E05.A, Decl(enumClassification.ts, 25, 10)) + + B = 10, +>B : Symbol(E05.B, Decl(enumClassification.ts, 26, 6)) + + C +>C : Symbol(E05.C, Decl(enumClassification.ts, 27, 11)) +} + +enum E06 { +>E06 : Symbol(E06, Decl(enumClassification.ts, 29, 1)) + + A = "one", +>A : Symbol(E06.A, Decl(enumClassification.ts, 31, 10)) + + B = "two", +>B : Symbol(E06.B, Decl(enumClassification.ts, 32, 14)) + + C = "three" +>C : Symbol(E06.C, Decl(enumClassification.ts, 33, 14)) +} + +enum E07 { +>E07 : Symbol(E07, Decl(enumClassification.ts, 35, 1)) + + A, +>A : Symbol(E07.A, Decl(enumClassification.ts, 37, 10)) + + B, +>B : Symbol(E07.B, Decl(enumClassification.ts, 38, 6)) + + C = "hi", +>C : Symbol(E07.C, Decl(enumClassification.ts, 39, 6)) + + D = 10, +>D : Symbol(E07.D, Decl(enumClassification.ts, 40, 13)) + + E, +>E : Symbol(E07.E, Decl(enumClassification.ts, 41, 11)) + + F = "bye" +>F : Symbol(E07.F, Decl(enumClassification.ts, 42, 6)) +} + +enum E08 { +>E08 : Symbol(E08, Decl(enumClassification.ts, 44, 1)) + + A = 10, +>A : Symbol(E08.A, Decl(enumClassification.ts, 46, 10)) + + B = "hello", +>B : Symbol(E08.B, Decl(enumClassification.ts, 47, 11)) + + C = A, +>C : Symbol(E08.C, Decl(enumClassification.ts, 48, 16)) +>A : Symbol(E08.A, Decl(enumClassification.ts, 46, 10)) + + D = B, +>D : Symbol(E08.D, Decl(enumClassification.ts, 49, 10)) +>B : Symbol(E08.B, Decl(enumClassification.ts, 47, 11)) + + E = C, +>E : Symbol(E08.E, Decl(enumClassification.ts, 50, 10)) +>C : Symbol(E08.C, Decl(enumClassification.ts, 48, 16)) +} + +// Examples of numeric enum types with only constant members + +enum E10 {} +>E10 : Symbol(E10, Decl(enumClassification.ts, 52, 1)) + +enum E11 { +>E11 : Symbol(E11, Decl(enumClassification.ts, 56, 11)) + + A = +0, +>A : Symbol(E11.A, Decl(enumClassification.ts, 58, 10)) + + B, +>B : Symbol(E11.B, Decl(enumClassification.ts, 59, 11)) + + C +>C : Symbol(E11.C, Decl(enumClassification.ts, 60, 6)) +} + +enum E12 { +>E12 : Symbol(E12, Decl(enumClassification.ts, 62, 1)) + + A = 1 << 0, +>A : Symbol(E12.A, Decl(enumClassification.ts, 64, 10)) + + B = 1 << 1, +>B : Symbol(E12.B, Decl(enumClassification.ts, 65, 15)) + + C = 1 << 2 +>C : Symbol(E12.C, Decl(enumClassification.ts, 66, 15)) +} + +// Examples of numeric enum types with constant and computed members + +enum E20 { +>E20 : Symbol(E20, Decl(enumClassification.ts, 68, 1)) + + A = "foo".length, +>A : Symbol(E20.A, Decl(enumClassification.ts, 72, 10)) +>"foo".length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + + B = A + 1, +>B : Symbol(E20.B, Decl(enumClassification.ts, 73, 21)) +>A : Symbol(E20.A, Decl(enumClassification.ts, 72, 10)) + + C = +"123", +>C : Symbol(E20.C, Decl(enumClassification.ts, 74, 14)) + + D = Math.sin(1) +>D : Symbol(E20.D, Decl(enumClassification.ts, 75, 15)) +>Math.sin : Symbol(Math.sin, Decl(lib.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>sin : Symbol(Math.sin, Decl(lib.d.ts, --, --)) +} + diff --git a/tests/baselines/reference/enumClassification.types b/tests/baselines/reference/enumClassification.types new file mode 100644 index 0000000000..d0581c7fca --- /dev/null +++ b/tests/baselines/reference/enumClassification.types @@ -0,0 +1,196 @@ +=== tests/cases/conformance/enums/enumClassification.ts === +// An enum type where each member has no initializer or an initializer that specififes +// a numeric literal, a string literal, or a single identifier naming another member in +// the enum type is classified as a literal enum type. An enum type that doesn't adhere +// to this pattern is classified as a numeric enum type. + +// Examples of literal enum types + +enum E01 { +>E01 : E01 + + A +>A : E01 +} + +enum E02 { +>E02 : E02 + + A = 123 +>A : E02 +>123 : 123 +} + +enum E03 { +>E03 : E03 + + A = "hello" +>A : E03 +>"hello" : "hello" +} + +enum E04 { +>E04 : E04 + + A, +>A : E04.A + + B, +>B : E04.B + + C +>C : E04.C +} + +enum E05 { +>E05 : E05 + + A, +>A : E05.A + + B = 10, +>B : E05.B +>10 : 10 + + C +>C : E05.C +} + +enum E06 { +>E06 : E06 + + A = "one", +>A : E06.A +>"one" : "one" + + B = "two", +>B : E06.B +>"two" : "two" + + C = "three" +>C : E06.C +>"three" : "three" +} + +enum E07 { +>E07 : E07 + + A, +>A : E07.A + + B, +>B : E07.B + + C = "hi", +>C : E07.C +>"hi" : "hi" + + D = 10, +>D : E07.D +>10 : 10 + + E, +>E : E07.E + + F = "bye" +>F : E07.F +>"bye" : "bye" +} + +enum E08 { +>E08 : E08 + + A = 10, +>A : E08.A +>10 : 10 + + B = "hello", +>B : E08.B +>"hello" : "hello" + + C = A, +>C : E08.A +>A : E08.A + + D = B, +>D : E08.B +>B : E08.B + + E = C, +>E : E08.A +>C : E08.A +} + +// Examples of numeric enum types with only constant members + +enum E10 {} +>E10 : E10 + +enum E11 { +>E11 : E11 + + A = +0, +>A : E11 +>+0 : number +>0 : 0 + + B, +>B : E11 + + C +>C : E11 +} + +enum E12 { +>E12 : E12 + + A = 1 << 0, +>A : E12 +>1 << 0 : number +>1 : 1 +>0 : 0 + + B = 1 << 1, +>B : E12 +>1 << 1 : number +>1 : 1 +>1 : 1 + + C = 1 << 2 +>C : E12 +>1 << 2 : number +>1 : 1 +>2 : 2 +} + +// Examples of numeric enum types with constant and computed members + +enum E20 { +>E20 : E20 + + A = "foo".length, +>A : E20 +>"foo".length : number +>"foo" : "foo" +>length : number + + B = A + 1, +>B : E20 +>A + 1 : number +>A : E20 +>1 : 1 + + C = +"123", +>C : E20 +>+"123" : number +>"123" : "123" + + D = Math.sin(1) +>D : E20 +>Math.sin(1) : number +>Math.sin : (x: number) => number +>Math : Math +>sin : (x: number) => number +>1 : 1 +} + diff --git a/tests/baselines/reference/stringEnumLiteralTypes1.js b/tests/baselines/reference/stringEnumLiteralTypes1.js new file mode 100644 index 0000000000..4acf2ada1a --- /dev/null +++ b/tests/baselines/reference/stringEnumLiteralTypes1.js @@ -0,0 +1,178 @@ +//// [stringEnumLiteralTypes1.ts] +const enum Choice { Unknown = "", Yes = "yes", No = "no" }; + +type YesNo = Choice.Yes | Choice.No; +type NoYes = Choice.No | Choice.Yes; +type UnknownYesNo = Choice.Unknown | Choice.Yes | Choice.No; + +function f1() { + var a: YesNo; + var a: NoYes; + var a: Choice.Yes | Choice.No; + var a: Choice.No | Choice.Yes; +} + +function f2(a: YesNo, b: UnknownYesNo, c: Choice) { + b = a; + c = a; + c = b; +} + +function f3(a: Choice.Yes, b: YesNo) { + var x = a + b; + var y = a == b; + var y = a != b; + var y = a === b; + var y = a !== b; + var y = a > b; + var y = a < b; + var y = a >= b; + var y = a <= b; + var y = !b; +} + +declare function g(x: Choice.Yes): string; +declare function g(x: Choice.No): boolean; +declare function g(x: Choice): number; + +function f5(a: YesNo, b: UnknownYesNo, c: Choice) { + var z1 = g(Choice.Yes); + var z2 = g(Choice.No); + var z3 = g(a); + var z4 = g(b); + var z5 = g(c); +} + +function assertNever(x: never): never { + throw new Error("Unexpected value"); +} + +function f10(x: YesNo) { + switch (x) { + case Choice.Yes: return "true"; + case Choice.No: return "false"; + } +} + +function f11(x: YesNo) { + switch (x) { + case Choice.Yes: return "true"; + case Choice.No: return "false"; + } + return assertNever(x); +} + +function f12(x: UnknownYesNo) { + if (x) { + x; + } + else { + x; + } +} + +function f13(x: UnknownYesNo) { + if (x === Choice.Yes) { + x; + } + else { + x; + } +} + +type Item = + { kind: Choice.Yes, a: string } | + { kind: Choice.No, b: string }; + +function f20(x: Item) { + switch (x.kind) { + case Choice.Yes: return x.a; + case Choice.No: return x.b; + } +} + +function f21(x: Item) { + switch (x.kind) { + case Choice.Yes: return x.a; + case Choice.No: return x.b; + } + return assertNever(x); +} + +//// [stringEnumLiteralTypes1.js] +; +function f1() { + var a; + var a; + var a; + var a; +} +function f2(a, b, c) { + b = a; + c = a; + c = b; +} +function f3(a, b) { + var x = a + b; + var y = a == b; + var y = a != b; + var y = a === b; + var y = a !== b; + var y = a > b; + var y = a < b; + var y = a >= b; + var y = a <= b; + var y = !b; +} +function f5(a, b, c) { + var z1 = g("yes" /* Yes */); + var z2 = g("no" /* No */); + var z3 = g(a); + var z4 = g(b); + var z5 = g(c); +} +function assertNever(x) { + throw new Error("Unexpected value"); +} +function f10(x) { + switch (x) { + case "yes" /* Yes */: return "true"; + case "no" /* No */: return "false"; + } +} +function f11(x) { + switch (x) { + case "yes" /* Yes */: return "true"; + case "no" /* No */: return "false"; + } + return assertNever(x); +} +function f12(x) { + if (x) { + x; + } + else { + x; + } +} +function f13(x) { + if (x === "yes" /* Yes */) { + x; + } + else { + x; + } +} +function f20(x) { + switch (x.kind) { + case "yes" /* Yes */: return x.a; + case "no" /* No */: return x.b; + } +} +function f21(x) { + switch (x.kind) { + case "yes" /* Yes */: return x.a; + case "no" /* No */: return x.b; + } + return assertNever(x); +} diff --git a/tests/baselines/reference/stringEnumLiteralTypes1.symbols b/tests/baselines/reference/stringEnumLiteralTypes1.symbols new file mode 100644 index 0000000000..66c25aab85 --- /dev/null +++ b/tests/baselines/reference/stringEnumLiteralTypes1.symbols @@ -0,0 +1,353 @@ +=== tests/cases/conformance/types/literal/stringEnumLiteralTypes1.ts === +const enum Choice { Unknown = "", Yes = "yes", No = "no" }; +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Unknown : Symbol(Choice.Unknown, Decl(stringEnumLiteralTypes1.ts, 0, 19)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) + +type YesNo = Choice.Yes | Choice.No; +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes1.ts, 0, 59)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) + +type NoYes = Choice.No | Choice.Yes; +>NoYes : Symbol(NoYes, Decl(stringEnumLiteralTypes1.ts, 2, 36)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) + +type UnknownYesNo = Choice.Unknown | Choice.Yes | Choice.No; +>UnknownYesNo : Symbol(UnknownYesNo, Decl(stringEnumLiteralTypes1.ts, 3, 36)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Unknown : Symbol(Choice.Unknown, Decl(stringEnumLiteralTypes1.ts, 0, 19)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) + +function f1() { +>f1 : Symbol(f1, Decl(stringEnumLiteralTypes1.ts, 4, 60)) + + var a: YesNo; +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 7, 7), Decl(stringEnumLiteralTypes1.ts, 8, 7), Decl(stringEnumLiteralTypes1.ts, 9, 7), Decl(stringEnumLiteralTypes1.ts, 10, 7)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes1.ts, 0, 59)) + + var a: NoYes; +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 7, 7), Decl(stringEnumLiteralTypes1.ts, 8, 7), Decl(stringEnumLiteralTypes1.ts, 9, 7), Decl(stringEnumLiteralTypes1.ts, 10, 7)) +>NoYes : Symbol(NoYes, Decl(stringEnumLiteralTypes1.ts, 2, 36)) + + var a: Choice.Yes | Choice.No; +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 7, 7), Decl(stringEnumLiteralTypes1.ts, 8, 7), Decl(stringEnumLiteralTypes1.ts, 9, 7), Decl(stringEnumLiteralTypes1.ts, 10, 7)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) + + var a: Choice.No | Choice.Yes; +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 7, 7), Decl(stringEnumLiteralTypes1.ts, 8, 7), Decl(stringEnumLiteralTypes1.ts, 9, 7), Decl(stringEnumLiteralTypes1.ts, 10, 7)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +} + +function f2(a: YesNo, b: UnknownYesNo, c: Choice) { +>f2 : Symbol(f2, Decl(stringEnumLiteralTypes1.ts, 11, 1)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 13, 12)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes1.ts, 0, 59)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 13, 21)) +>UnknownYesNo : Symbol(UnknownYesNo, Decl(stringEnumLiteralTypes1.ts, 3, 36)) +>c : Symbol(c, Decl(stringEnumLiteralTypes1.ts, 13, 38)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) + + b = a; +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 13, 21)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 13, 12)) + + c = a; +>c : Symbol(c, Decl(stringEnumLiteralTypes1.ts, 13, 38)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 13, 12)) + + c = b; +>c : Symbol(c, Decl(stringEnumLiteralTypes1.ts, 13, 38)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 13, 21)) +} + +function f3(a: Choice.Yes, b: YesNo) { +>f3 : Symbol(f3, Decl(stringEnumLiteralTypes1.ts, 17, 1)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 19, 12)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 19, 26)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes1.ts, 0, 59)) + + var x = a + b; +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 20, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 19, 26)) + + var y = a == b; +>y : Symbol(y, Decl(stringEnumLiteralTypes1.ts, 21, 7), Decl(stringEnumLiteralTypes1.ts, 22, 7), Decl(stringEnumLiteralTypes1.ts, 23, 7), Decl(stringEnumLiteralTypes1.ts, 24, 7), Decl(stringEnumLiteralTypes1.ts, 25, 7), Decl(stringEnumLiteralTypes1.ts, 26, 7), Decl(stringEnumLiteralTypes1.ts, 27, 7), Decl(stringEnumLiteralTypes1.ts, 28, 7), Decl(stringEnumLiteralTypes1.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 19, 26)) + + var y = a != b; +>y : Symbol(y, Decl(stringEnumLiteralTypes1.ts, 21, 7), Decl(stringEnumLiteralTypes1.ts, 22, 7), Decl(stringEnumLiteralTypes1.ts, 23, 7), Decl(stringEnumLiteralTypes1.ts, 24, 7), Decl(stringEnumLiteralTypes1.ts, 25, 7), Decl(stringEnumLiteralTypes1.ts, 26, 7), Decl(stringEnumLiteralTypes1.ts, 27, 7), Decl(stringEnumLiteralTypes1.ts, 28, 7), Decl(stringEnumLiteralTypes1.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 19, 26)) + + var y = a === b; +>y : Symbol(y, Decl(stringEnumLiteralTypes1.ts, 21, 7), Decl(stringEnumLiteralTypes1.ts, 22, 7), Decl(stringEnumLiteralTypes1.ts, 23, 7), Decl(stringEnumLiteralTypes1.ts, 24, 7), Decl(stringEnumLiteralTypes1.ts, 25, 7), Decl(stringEnumLiteralTypes1.ts, 26, 7), Decl(stringEnumLiteralTypes1.ts, 27, 7), Decl(stringEnumLiteralTypes1.ts, 28, 7), Decl(stringEnumLiteralTypes1.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 19, 26)) + + var y = a !== b; +>y : Symbol(y, Decl(stringEnumLiteralTypes1.ts, 21, 7), Decl(stringEnumLiteralTypes1.ts, 22, 7), Decl(stringEnumLiteralTypes1.ts, 23, 7), Decl(stringEnumLiteralTypes1.ts, 24, 7), Decl(stringEnumLiteralTypes1.ts, 25, 7), Decl(stringEnumLiteralTypes1.ts, 26, 7), Decl(stringEnumLiteralTypes1.ts, 27, 7), Decl(stringEnumLiteralTypes1.ts, 28, 7), Decl(stringEnumLiteralTypes1.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 19, 26)) + + var y = a > b; +>y : Symbol(y, Decl(stringEnumLiteralTypes1.ts, 21, 7), Decl(stringEnumLiteralTypes1.ts, 22, 7), Decl(stringEnumLiteralTypes1.ts, 23, 7), Decl(stringEnumLiteralTypes1.ts, 24, 7), Decl(stringEnumLiteralTypes1.ts, 25, 7), Decl(stringEnumLiteralTypes1.ts, 26, 7), Decl(stringEnumLiteralTypes1.ts, 27, 7), Decl(stringEnumLiteralTypes1.ts, 28, 7), Decl(stringEnumLiteralTypes1.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 19, 26)) + + var y = a < b; +>y : Symbol(y, Decl(stringEnumLiteralTypes1.ts, 21, 7), Decl(stringEnumLiteralTypes1.ts, 22, 7), Decl(stringEnumLiteralTypes1.ts, 23, 7), Decl(stringEnumLiteralTypes1.ts, 24, 7), Decl(stringEnumLiteralTypes1.ts, 25, 7), Decl(stringEnumLiteralTypes1.ts, 26, 7), Decl(stringEnumLiteralTypes1.ts, 27, 7), Decl(stringEnumLiteralTypes1.ts, 28, 7), Decl(stringEnumLiteralTypes1.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 19, 26)) + + var y = a >= b; +>y : Symbol(y, Decl(stringEnumLiteralTypes1.ts, 21, 7), Decl(stringEnumLiteralTypes1.ts, 22, 7), Decl(stringEnumLiteralTypes1.ts, 23, 7), Decl(stringEnumLiteralTypes1.ts, 24, 7), Decl(stringEnumLiteralTypes1.ts, 25, 7), Decl(stringEnumLiteralTypes1.ts, 26, 7), Decl(stringEnumLiteralTypes1.ts, 27, 7), Decl(stringEnumLiteralTypes1.ts, 28, 7), Decl(stringEnumLiteralTypes1.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 19, 26)) + + var y = a <= b; +>y : Symbol(y, Decl(stringEnumLiteralTypes1.ts, 21, 7), Decl(stringEnumLiteralTypes1.ts, 22, 7), Decl(stringEnumLiteralTypes1.ts, 23, 7), Decl(stringEnumLiteralTypes1.ts, 24, 7), Decl(stringEnumLiteralTypes1.ts, 25, 7), Decl(stringEnumLiteralTypes1.ts, 26, 7), Decl(stringEnumLiteralTypes1.ts, 27, 7), Decl(stringEnumLiteralTypes1.ts, 28, 7), Decl(stringEnumLiteralTypes1.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 19, 26)) + + var y = !b; +>y : Symbol(y, Decl(stringEnumLiteralTypes1.ts, 21, 7), Decl(stringEnumLiteralTypes1.ts, 22, 7), Decl(stringEnumLiteralTypes1.ts, 23, 7), Decl(stringEnumLiteralTypes1.ts, 24, 7), Decl(stringEnumLiteralTypes1.ts, 25, 7), Decl(stringEnumLiteralTypes1.ts, 26, 7), Decl(stringEnumLiteralTypes1.ts, 27, 7), Decl(stringEnumLiteralTypes1.ts, 28, 7), Decl(stringEnumLiteralTypes1.ts, 29, 7)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 19, 26)) +} + +declare function g(x: Choice.Yes): string; +>g : Symbol(g, Decl(stringEnumLiteralTypes1.ts, 30, 1), Decl(stringEnumLiteralTypes1.ts, 32, 42), Decl(stringEnumLiteralTypes1.ts, 33, 42)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 32, 19)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) + +declare function g(x: Choice.No): boolean; +>g : Symbol(g, Decl(stringEnumLiteralTypes1.ts, 30, 1), Decl(stringEnumLiteralTypes1.ts, 32, 42), Decl(stringEnumLiteralTypes1.ts, 33, 42)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 33, 19)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) + +declare function g(x: Choice): number; +>g : Symbol(g, Decl(stringEnumLiteralTypes1.ts, 30, 1), Decl(stringEnumLiteralTypes1.ts, 32, 42), Decl(stringEnumLiteralTypes1.ts, 33, 42)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 34, 19)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) + +function f5(a: YesNo, b: UnknownYesNo, c: Choice) { +>f5 : Symbol(f5, Decl(stringEnumLiteralTypes1.ts, 34, 38)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 36, 12)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes1.ts, 0, 59)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 36, 21)) +>UnknownYesNo : Symbol(UnknownYesNo, Decl(stringEnumLiteralTypes1.ts, 3, 36)) +>c : Symbol(c, Decl(stringEnumLiteralTypes1.ts, 36, 38)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) + + var z1 = g(Choice.Yes); +>z1 : Symbol(z1, Decl(stringEnumLiteralTypes1.ts, 37, 7)) +>g : Symbol(g, Decl(stringEnumLiteralTypes1.ts, 30, 1), Decl(stringEnumLiteralTypes1.ts, 32, 42), Decl(stringEnumLiteralTypes1.ts, 33, 42)) +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) + + var z2 = g(Choice.No); +>z2 : Symbol(z2, Decl(stringEnumLiteralTypes1.ts, 38, 7)) +>g : Symbol(g, Decl(stringEnumLiteralTypes1.ts, 30, 1), Decl(stringEnumLiteralTypes1.ts, 32, 42), Decl(stringEnumLiteralTypes1.ts, 33, 42)) +>Choice.No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) + + var z3 = g(a); +>z3 : Symbol(z3, Decl(stringEnumLiteralTypes1.ts, 39, 7)) +>g : Symbol(g, Decl(stringEnumLiteralTypes1.ts, 30, 1), Decl(stringEnumLiteralTypes1.ts, 32, 42), Decl(stringEnumLiteralTypes1.ts, 33, 42)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 36, 12)) + + var z4 = g(b); +>z4 : Symbol(z4, Decl(stringEnumLiteralTypes1.ts, 40, 7)) +>g : Symbol(g, Decl(stringEnumLiteralTypes1.ts, 30, 1), Decl(stringEnumLiteralTypes1.ts, 32, 42), Decl(stringEnumLiteralTypes1.ts, 33, 42)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 36, 21)) + + var z5 = g(c); +>z5 : Symbol(z5, Decl(stringEnumLiteralTypes1.ts, 41, 7)) +>g : Symbol(g, Decl(stringEnumLiteralTypes1.ts, 30, 1), Decl(stringEnumLiteralTypes1.ts, 32, 42), Decl(stringEnumLiteralTypes1.ts, 33, 42)) +>c : Symbol(c, Decl(stringEnumLiteralTypes1.ts, 36, 38)) +} + +function assertNever(x: never): never { +>assertNever : Symbol(assertNever, Decl(stringEnumLiteralTypes1.ts, 42, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 44, 21)) + + throw new Error("Unexpected value"); +>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +} + +function f10(x: YesNo) { +>f10 : Symbol(f10, Decl(stringEnumLiteralTypes1.ts, 46, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 48, 13)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes1.ts, 0, 59)) + + switch (x) { +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 48, 13)) + + case Choice.Yes: return "true"; +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) + + case Choice.No: return "false"; +>Choice.No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) + } +} + +function f11(x: YesNo) { +>f11 : Symbol(f11, Decl(stringEnumLiteralTypes1.ts, 53, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 55, 13)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes1.ts, 0, 59)) + + switch (x) { +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 55, 13)) + + case Choice.Yes: return "true"; +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) + + case Choice.No: return "false"; +>Choice.No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) + } + return assertNever(x); +>assertNever : Symbol(assertNever, Decl(stringEnumLiteralTypes1.ts, 42, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 55, 13)) +} + +function f12(x: UnknownYesNo) { +>f12 : Symbol(f12, Decl(stringEnumLiteralTypes1.ts, 61, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 63, 13)) +>UnknownYesNo : Symbol(UnknownYesNo, Decl(stringEnumLiteralTypes1.ts, 3, 36)) + + if (x) { +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 63, 13)) + + x; +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 63, 13)) + } + else { + x; +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 63, 13)) + } +} + +function f13(x: UnknownYesNo) { +>f13 : Symbol(f13, Decl(stringEnumLiteralTypes1.ts, 70, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 72, 13)) +>UnknownYesNo : Symbol(UnknownYesNo, Decl(stringEnumLiteralTypes1.ts, 3, 36)) + + if (x === Choice.Yes) { +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 72, 13)) +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) + + x; +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 72, 13)) + } + else { + x; +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 72, 13)) + } +} + +type Item = +>Item : Symbol(Item, Decl(stringEnumLiteralTypes1.ts, 79, 1)) + + { kind: Choice.Yes, a: string } | +>kind : Symbol(kind, Decl(stringEnumLiteralTypes1.ts, 82, 5)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 82, 23)) + + { kind: Choice.No, b: string }; +>kind : Symbol(kind, Decl(stringEnumLiteralTypes1.ts, 83, 5)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 83, 22)) + +function f20(x: Item) { +>f20 : Symbol(f20, Decl(stringEnumLiteralTypes1.ts, 83, 35)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 85, 13)) +>Item : Symbol(Item, Decl(stringEnumLiteralTypes1.ts, 79, 1)) + + switch (x.kind) { +>x.kind : Symbol(kind, Decl(stringEnumLiteralTypes1.ts, 82, 5), Decl(stringEnumLiteralTypes1.ts, 83, 5)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 85, 13)) +>kind : Symbol(kind, Decl(stringEnumLiteralTypes1.ts, 82, 5), Decl(stringEnumLiteralTypes1.ts, 83, 5)) + + case Choice.Yes: return x.a; +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>x.a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 82, 23)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 85, 13)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 82, 23)) + + case Choice.No: return x.b; +>Choice.No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) +>x.b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 83, 22)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 85, 13)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 83, 22)) + } +} + +function f21(x: Item) { +>f21 : Symbol(f21, Decl(stringEnumLiteralTypes1.ts, 90, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 92, 13)) +>Item : Symbol(Item, Decl(stringEnumLiteralTypes1.ts, 79, 1)) + + switch (x.kind) { +>x.kind : Symbol(kind, Decl(stringEnumLiteralTypes1.ts, 82, 5), Decl(stringEnumLiteralTypes1.ts, 83, 5)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 92, 13)) +>kind : Symbol(kind, Decl(stringEnumLiteralTypes1.ts, 82, 5), Decl(stringEnumLiteralTypes1.ts, 83, 5)) + + case Choice.Yes: return x.a; +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes1.ts, 0, 33)) +>x.a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 82, 23)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 92, 13)) +>a : Symbol(a, Decl(stringEnumLiteralTypes1.ts, 82, 23)) + + case Choice.No: return x.b; +>Choice.No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes1.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes1.ts, 0, 46)) +>x.b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 83, 22)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 92, 13)) +>b : Symbol(b, Decl(stringEnumLiteralTypes1.ts, 83, 22)) + } + return assertNever(x); +>assertNever : Symbol(assertNever, Decl(stringEnumLiteralTypes1.ts, 42, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes1.ts, 92, 13)) +} diff --git a/tests/baselines/reference/stringEnumLiteralTypes1.types b/tests/baselines/reference/stringEnumLiteralTypes1.types new file mode 100644 index 0000000000..b5d70ed501 --- /dev/null +++ b/tests/baselines/reference/stringEnumLiteralTypes1.types @@ -0,0 +1,383 @@ +=== tests/cases/conformance/types/literal/stringEnumLiteralTypes1.ts === +const enum Choice { Unknown = "", Yes = "yes", No = "no" }; +>Choice : Choice +>Unknown : Choice.Unknown +>"" : "" +>Yes : Choice.Yes +>"yes" : "yes" +>No : Choice.No +>"no" : "no" + +type YesNo = Choice.Yes | Choice.No; +>YesNo : YesNo +>Choice : any +>Yes : Choice.Yes +>Choice : any +>No : Choice.No + +type NoYes = Choice.No | Choice.Yes; +>NoYes : YesNo +>Choice : any +>No : Choice.No +>Choice : any +>Yes : Choice.Yes + +type UnknownYesNo = Choice.Unknown | Choice.Yes | Choice.No; +>UnknownYesNo : Choice +>Choice : any +>Unknown : Choice.Unknown +>Choice : any +>Yes : Choice.Yes +>Choice : any +>No : Choice.No + +function f1() { +>f1 : () => void + + var a: YesNo; +>a : YesNo +>YesNo : YesNo + + var a: NoYes; +>a : YesNo +>NoYes : YesNo + + var a: Choice.Yes | Choice.No; +>a : YesNo +>Choice : any +>Yes : Choice.Yes +>Choice : any +>No : Choice.No + + var a: Choice.No | Choice.Yes; +>a : YesNo +>Choice : any +>No : Choice.No +>Choice : any +>Yes : Choice.Yes +} + +function f2(a: YesNo, b: UnknownYesNo, c: Choice) { +>f2 : (a: YesNo, b: Choice, c: Choice) => void +>a : YesNo +>YesNo : YesNo +>b : Choice +>UnknownYesNo : Choice +>c : Choice +>Choice : Choice + + b = a; +>b = a : YesNo +>b : Choice +>a : YesNo + + c = a; +>c = a : YesNo +>c : Choice +>a : YesNo + + c = b; +>c = b : YesNo +>c : Choice +>b : YesNo +} + +function f3(a: Choice.Yes, b: YesNo) { +>f3 : (a: Choice.Yes, b: YesNo) => void +>a : Choice.Yes +>Choice : any +>Yes : Choice.Yes +>b : YesNo +>YesNo : YesNo + + var x = a + b; +>x : string +>a + b : string +>a : Choice.Yes +>b : YesNo + + var y = a == b; +>y : boolean +>a == b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a != b; +>y : boolean +>a != b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a === b; +>y : boolean +>a === b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a !== b; +>y : boolean +>a !== b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a > b; +>y : boolean +>a > b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a < b; +>y : boolean +>a < b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a >= b; +>y : boolean +>a >= b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a <= b; +>y : boolean +>a <= b : boolean +>a : Choice.Yes +>b : YesNo + + var y = !b; +>y : boolean +>!b : boolean +>b : YesNo +} + +declare function g(x: Choice.Yes): string; +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>x : Choice.Yes +>Choice : any +>Yes : Choice.Yes + +declare function g(x: Choice.No): boolean; +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>x : Choice.No +>Choice : any +>No : Choice.No + +declare function g(x: Choice): number; +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>x : Choice +>Choice : Choice + +function f5(a: YesNo, b: UnknownYesNo, c: Choice) { +>f5 : (a: YesNo, b: Choice, c: Choice) => void +>a : YesNo +>YesNo : YesNo +>b : Choice +>UnknownYesNo : Choice +>c : Choice +>Choice : Choice + + var z1 = g(Choice.Yes); +>z1 : string +>g(Choice.Yes) : string +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes + + var z2 = g(Choice.No); +>z2 : boolean +>g(Choice.No) : boolean +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>Choice.No : Choice.No +>Choice : typeof Choice +>No : Choice.No + + var z3 = g(a); +>z3 : number +>g(a) : number +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>a : YesNo + + var z4 = g(b); +>z4 : number +>g(b) : number +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>b : Choice + + var z5 = g(c); +>z5 : number +>g(c) : number +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>c : Choice +} + +function assertNever(x: never): never { +>assertNever : (x: never) => never +>x : never + + throw new Error("Unexpected value"); +>new Error("Unexpected value") : Error +>Error : ErrorConstructor +>"Unexpected value" : "Unexpected value" +} + +function f10(x: YesNo) { +>f10 : (x: YesNo) => "true" | "false" +>x : YesNo +>YesNo : YesNo + + switch (x) { +>x : YesNo + + case Choice.Yes: return "true"; +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes +>"true" : "true" + + case Choice.No: return "false"; +>Choice.No : Choice.No +>Choice : typeof Choice +>No : Choice.No +>"false" : "false" + } +} + +function f11(x: YesNo) { +>f11 : (x: YesNo) => "true" | "false" +>x : YesNo +>YesNo : YesNo + + switch (x) { +>x : YesNo + + case Choice.Yes: return "true"; +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes +>"true" : "true" + + case Choice.No: return "false"; +>Choice.No : Choice.No +>Choice : typeof Choice +>No : Choice.No +>"false" : "false" + } + return assertNever(x); +>assertNever(x) : never +>assertNever : (x: never) => never +>x : never +} + +function f12(x: UnknownYesNo) { +>f12 : (x: Choice) => void +>x : Choice +>UnknownYesNo : Choice + + if (x) { +>x : Choice + + x; +>x : YesNo + } + else { + x; +>x : Choice + } +} + +function f13(x: UnknownYesNo) { +>f13 : (x: Choice) => void +>x : Choice +>UnknownYesNo : Choice + + if (x === Choice.Yes) { +>x === Choice.Yes : boolean +>x : Choice +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes + + x; +>x : Choice.Yes + } + else { + x; +>x : Choice.Unknown | Choice.No + } +} + +type Item = +>Item : Item + + { kind: Choice.Yes, a: string } | +>kind : Choice.Yes +>Choice : any +>Yes : Choice.Yes +>a : string + + { kind: Choice.No, b: string }; +>kind : Choice.No +>Choice : any +>No : Choice.No +>b : string + +function f20(x: Item) { +>f20 : (x: Item) => string +>x : Item +>Item : Item + + switch (x.kind) { +>x.kind : YesNo +>x : Item +>kind : YesNo + + case Choice.Yes: return x.a; +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes +>x.a : string +>x : { kind: Choice.Yes; a: string; } +>a : string + + case Choice.No: return x.b; +>Choice.No : Choice.No +>Choice : typeof Choice +>No : Choice.No +>x.b : string +>x : { kind: Choice.No; b: string; } +>b : string + } +} + +function f21(x: Item) { +>f21 : (x: Item) => string +>x : Item +>Item : Item + + switch (x.kind) { +>x.kind : YesNo +>x : Item +>kind : YesNo + + case Choice.Yes: return x.a; +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes +>x.a : string +>x : { kind: Choice.Yes; a: string; } +>a : string + + case Choice.No: return x.b; +>Choice.No : Choice.No +>Choice : typeof Choice +>No : Choice.No +>x.b : string +>x : { kind: Choice.No; b: string; } +>b : string + } + return assertNever(x); +>assertNever(x) : never +>assertNever : (x: never) => never +>x : never +} diff --git a/tests/baselines/reference/stringEnumLiteralTypes2.js b/tests/baselines/reference/stringEnumLiteralTypes2.js new file mode 100644 index 0000000000..07a5de7a85 --- /dev/null +++ b/tests/baselines/reference/stringEnumLiteralTypes2.js @@ -0,0 +1,178 @@ +//// [stringEnumLiteralTypes2.ts] +const enum Choice { Unknown = "", Yes = "yes", No = "no" }; + +type YesNo = Choice.Yes | Choice.No; +type NoYes = Choice.No | Choice.Yes; +type UnknownYesNo = Choice.Unknown | Choice.Yes | Choice.No; + +function f1() { + var a: YesNo; + var a: NoYes; + var a: Choice.Yes | Choice.No; + var a: Choice.No | Choice.Yes; +} + +function f2(a: YesNo, b: UnknownYesNo, c: Choice) { + b = a; + c = a; + c = b; +} + +function f3(a: Choice.Yes, b: YesNo) { + var x = a + b; + var y = a == b; + var y = a != b; + var y = a === b; + var y = a !== b; + var y = a > b; + var y = a < b; + var y = a >= b; + var y = a <= b; + var y = !b; +} + +declare function g(x: Choice.Yes): string; +declare function g(x: Choice.No): boolean; +declare function g(x: Choice): number; + +function f5(a: YesNo, b: UnknownYesNo, c: Choice) { + var z1 = g(Choice.Yes); + var z2 = g(Choice.No); + var z3 = g(a); + var z4 = g(b); + var z5 = g(c); +} + +function assertNever(x: never): never { + throw new Error("Unexpected value"); +} + +function f10(x: YesNo) { + switch (x) { + case Choice.Yes: return "true"; + case Choice.No: return "false"; + } +} + +function f11(x: YesNo) { + switch (x) { + case Choice.Yes: return "true"; + case Choice.No: return "false"; + } + return assertNever(x); +} + +function f12(x: UnknownYesNo) { + if (x) { + x; + } + else { + x; + } +} + +function f13(x: UnknownYesNo) { + if (x === Choice.Yes) { + x; + } + else { + x; + } +} + +type Item = + { kind: Choice.Yes, a: string } | + { kind: Choice.No, b: string }; + +function f20(x: Item) { + switch (x.kind) { + case Choice.Yes: return x.a; + case Choice.No: return x.b; + } +} + +function f21(x: Item) { + switch (x.kind) { + case Choice.Yes: return x.a; + case Choice.No: return x.b; + } + return assertNever(x); +} + +//// [stringEnumLiteralTypes2.js] +; +function f1() { + var a; + var a; + var a; + var a; +} +function f2(a, b, c) { + b = a; + c = a; + c = b; +} +function f3(a, b) { + var x = a + b; + var y = a == b; + var y = a != b; + var y = a === b; + var y = a !== b; + var y = a > b; + var y = a < b; + var y = a >= b; + var y = a <= b; + var y = !b; +} +function f5(a, b, c) { + var z1 = g("yes" /* Yes */); + var z2 = g("no" /* No */); + var z3 = g(a); + var z4 = g(b); + var z5 = g(c); +} +function assertNever(x) { + throw new Error("Unexpected value"); +} +function f10(x) { + switch (x) { + case "yes" /* Yes */: return "true"; + case "no" /* No */: return "false"; + } +} +function f11(x) { + switch (x) { + case "yes" /* Yes */: return "true"; + case "no" /* No */: return "false"; + } + return assertNever(x); +} +function f12(x) { + if (x) { + x; + } + else { + x; + } +} +function f13(x) { + if (x === "yes" /* Yes */) { + x; + } + else { + x; + } +} +function f20(x) { + switch (x.kind) { + case "yes" /* Yes */: return x.a; + case "no" /* No */: return x.b; + } +} +function f21(x) { + switch (x.kind) { + case "yes" /* Yes */: return x.a; + case "no" /* No */: return x.b; + } + return assertNever(x); +} diff --git a/tests/baselines/reference/stringEnumLiteralTypes2.symbols b/tests/baselines/reference/stringEnumLiteralTypes2.symbols new file mode 100644 index 0000000000..f746c0430c --- /dev/null +++ b/tests/baselines/reference/stringEnumLiteralTypes2.symbols @@ -0,0 +1,353 @@ +=== tests/cases/conformance/types/literal/stringEnumLiteralTypes2.ts === +const enum Choice { Unknown = "", Yes = "yes", No = "no" }; +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Unknown : Symbol(Choice.Unknown, Decl(stringEnumLiteralTypes2.ts, 0, 19)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) + +type YesNo = Choice.Yes | Choice.No; +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes2.ts, 0, 59)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) + +type NoYes = Choice.No | Choice.Yes; +>NoYes : Symbol(NoYes, Decl(stringEnumLiteralTypes2.ts, 2, 36)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) + +type UnknownYesNo = Choice.Unknown | Choice.Yes | Choice.No; +>UnknownYesNo : Symbol(UnknownYesNo, Decl(stringEnumLiteralTypes2.ts, 3, 36)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Unknown : Symbol(Choice.Unknown, Decl(stringEnumLiteralTypes2.ts, 0, 19)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) + +function f1() { +>f1 : Symbol(f1, Decl(stringEnumLiteralTypes2.ts, 4, 60)) + + var a: YesNo; +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 7, 7), Decl(stringEnumLiteralTypes2.ts, 8, 7), Decl(stringEnumLiteralTypes2.ts, 9, 7), Decl(stringEnumLiteralTypes2.ts, 10, 7)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes2.ts, 0, 59)) + + var a: NoYes; +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 7, 7), Decl(stringEnumLiteralTypes2.ts, 8, 7), Decl(stringEnumLiteralTypes2.ts, 9, 7), Decl(stringEnumLiteralTypes2.ts, 10, 7)) +>NoYes : Symbol(NoYes, Decl(stringEnumLiteralTypes2.ts, 2, 36)) + + var a: Choice.Yes | Choice.No; +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 7, 7), Decl(stringEnumLiteralTypes2.ts, 8, 7), Decl(stringEnumLiteralTypes2.ts, 9, 7), Decl(stringEnumLiteralTypes2.ts, 10, 7)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) + + var a: Choice.No | Choice.Yes; +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 7, 7), Decl(stringEnumLiteralTypes2.ts, 8, 7), Decl(stringEnumLiteralTypes2.ts, 9, 7), Decl(stringEnumLiteralTypes2.ts, 10, 7)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +} + +function f2(a: YesNo, b: UnknownYesNo, c: Choice) { +>f2 : Symbol(f2, Decl(stringEnumLiteralTypes2.ts, 11, 1)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 13, 12)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes2.ts, 0, 59)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 13, 21)) +>UnknownYesNo : Symbol(UnknownYesNo, Decl(stringEnumLiteralTypes2.ts, 3, 36)) +>c : Symbol(c, Decl(stringEnumLiteralTypes2.ts, 13, 38)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) + + b = a; +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 13, 21)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 13, 12)) + + c = a; +>c : Symbol(c, Decl(stringEnumLiteralTypes2.ts, 13, 38)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 13, 12)) + + c = b; +>c : Symbol(c, Decl(stringEnumLiteralTypes2.ts, 13, 38)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 13, 21)) +} + +function f3(a: Choice.Yes, b: YesNo) { +>f3 : Symbol(f3, Decl(stringEnumLiteralTypes2.ts, 17, 1)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 19, 12)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 19, 26)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes2.ts, 0, 59)) + + var x = a + b; +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 20, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 19, 26)) + + var y = a == b; +>y : Symbol(y, Decl(stringEnumLiteralTypes2.ts, 21, 7), Decl(stringEnumLiteralTypes2.ts, 22, 7), Decl(stringEnumLiteralTypes2.ts, 23, 7), Decl(stringEnumLiteralTypes2.ts, 24, 7), Decl(stringEnumLiteralTypes2.ts, 25, 7), Decl(stringEnumLiteralTypes2.ts, 26, 7), Decl(stringEnumLiteralTypes2.ts, 27, 7), Decl(stringEnumLiteralTypes2.ts, 28, 7), Decl(stringEnumLiteralTypes2.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 19, 26)) + + var y = a != b; +>y : Symbol(y, Decl(stringEnumLiteralTypes2.ts, 21, 7), Decl(stringEnumLiteralTypes2.ts, 22, 7), Decl(stringEnumLiteralTypes2.ts, 23, 7), Decl(stringEnumLiteralTypes2.ts, 24, 7), Decl(stringEnumLiteralTypes2.ts, 25, 7), Decl(stringEnumLiteralTypes2.ts, 26, 7), Decl(stringEnumLiteralTypes2.ts, 27, 7), Decl(stringEnumLiteralTypes2.ts, 28, 7), Decl(stringEnumLiteralTypes2.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 19, 26)) + + var y = a === b; +>y : Symbol(y, Decl(stringEnumLiteralTypes2.ts, 21, 7), Decl(stringEnumLiteralTypes2.ts, 22, 7), Decl(stringEnumLiteralTypes2.ts, 23, 7), Decl(stringEnumLiteralTypes2.ts, 24, 7), Decl(stringEnumLiteralTypes2.ts, 25, 7), Decl(stringEnumLiteralTypes2.ts, 26, 7), Decl(stringEnumLiteralTypes2.ts, 27, 7), Decl(stringEnumLiteralTypes2.ts, 28, 7), Decl(stringEnumLiteralTypes2.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 19, 26)) + + var y = a !== b; +>y : Symbol(y, Decl(stringEnumLiteralTypes2.ts, 21, 7), Decl(stringEnumLiteralTypes2.ts, 22, 7), Decl(stringEnumLiteralTypes2.ts, 23, 7), Decl(stringEnumLiteralTypes2.ts, 24, 7), Decl(stringEnumLiteralTypes2.ts, 25, 7), Decl(stringEnumLiteralTypes2.ts, 26, 7), Decl(stringEnumLiteralTypes2.ts, 27, 7), Decl(stringEnumLiteralTypes2.ts, 28, 7), Decl(stringEnumLiteralTypes2.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 19, 26)) + + var y = a > b; +>y : Symbol(y, Decl(stringEnumLiteralTypes2.ts, 21, 7), Decl(stringEnumLiteralTypes2.ts, 22, 7), Decl(stringEnumLiteralTypes2.ts, 23, 7), Decl(stringEnumLiteralTypes2.ts, 24, 7), Decl(stringEnumLiteralTypes2.ts, 25, 7), Decl(stringEnumLiteralTypes2.ts, 26, 7), Decl(stringEnumLiteralTypes2.ts, 27, 7), Decl(stringEnumLiteralTypes2.ts, 28, 7), Decl(stringEnumLiteralTypes2.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 19, 26)) + + var y = a < b; +>y : Symbol(y, Decl(stringEnumLiteralTypes2.ts, 21, 7), Decl(stringEnumLiteralTypes2.ts, 22, 7), Decl(stringEnumLiteralTypes2.ts, 23, 7), Decl(stringEnumLiteralTypes2.ts, 24, 7), Decl(stringEnumLiteralTypes2.ts, 25, 7), Decl(stringEnumLiteralTypes2.ts, 26, 7), Decl(stringEnumLiteralTypes2.ts, 27, 7), Decl(stringEnumLiteralTypes2.ts, 28, 7), Decl(stringEnumLiteralTypes2.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 19, 26)) + + var y = a >= b; +>y : Symbol(y, Decl(stringEnumLiteralTypes2.ts, 21, 7), Decl(stringEnumLiteralTypes2.ts, 22, 7), Decl(stringEnumLiteralTypes2.ts, 23, 7), Decl(stringEnumLiteralTypes2.ts, 24, 7), Decl(stringEnumLiteralTypes2.ts, 25, 7), Decl(stringEnumLiteralTypes2.ts, 26, 7), Decl(stringEnumLiteralTypes2.ts, 27, 7), Decl(stringEnumLiteralTypes2.ts, 28, 7), Decl(stringEnumLiteralTypes2.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 19, 26)) + + var y = a <= b; +>y : Symbol(y, Decl(stringEnumLiteralTypes2.ts, 21, 7), Decl(stringEnumLiteralTypes2.ts, 22, 7), Decl(stringEnumLiteralTypes2.ts, 23, 7), Decl(stringEnumLiteralTypes2.ts, 24, 7), Decl(stringEnumLiteralTypes2.ts, 25, 7), Decl(stringEnumLiteralTypes2.ts, 26, 7), Decl(stringEnumLiteralTypes2.ts, 27, 7), Decl(stringEnumLiteralTypes2.ts, 28, 7), Decl(stringEnumLiteralTypes2.ts, 29, 7)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 19, 12)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 19, 26)) + + var y = !b; +>y : Symbol(y, Decl(stringEnumLiteralTypes2.ts, 21, 7), Decl(stringEnumLiteralTypes2.ts, 22, 7), Decl(stringEnumLiteralTypes2.ts, 23, 7), Decl(stringEnumLiteralTypes2.ts, 24, 7), Decl(stringEnumLiteralTypes2.ts, 25, 7), Decl(stringEnumLiteralTypes2.ts, 26, 7), Decl(stringEnumLiteralTypes2.ts, 27, 7), Decl(stringEnumLiteralTypes2.ts, 28, 7), Decl(stringEnumLiteralTypes2.ts, 29, 7)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 19, 26)) +} + +declare function g(x: Choice.Yes): string; +>g : Symbol(g, Decl(stringEnumLiteralTypes2.ts, 30, 1), Decl(stringEnumLiteralTypes2.ts, 32, 42), Decl(stringEnumLiteralTypes2.ts, 33, 42)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 32, 19)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) + +declare function g(x: Choice.No): boolean; +>g : Symbol(g, Decl(stringEnumLiteralTypes2.ts, 30, 1), Decl(stringEnumLiteralTypes2.ts, 32, 42), Decl(stringEnumLiteralTypes2.ts, 33, 42)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 33, 19)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) + +declare function g(x: Choice): number; +>g : Symbol(g, Decl(stringEnumLiteralTypes2.ts, 30, 1), Decl(stringEnumLiteralTypes2.ts, 32, 42), Decl(stringEnumLiteralTypes2.ts, 33, 42)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 34, 19)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) + +function f5(a: YesNo, b: UnknownYesNo, c: Choice) { +>f5 : Symbol(f5, Decl(stringEnumLiteralTypes2.ts, 34, 38)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 36, 12)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes2.ts, 0, 59)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 36, 21)) +>UnknownYesNo : Symbol(UnknownYesNo, Decl(stringEnumLiteralTypes2.ts, 3, 36)) +>c : Symbol(c, Decl(stringEnumLiteralTypes2.ts, 36, 38)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) + + var z1 = g(Choice.Yes); +>z1 : Symbol(z1, Decl(stringEnumLiteralTypes2.ts, 37, 7)) +>g : Symbol(g, Decl(stringEnumLiteralTypes2.ts, 30, 1), Decl(stringEnumLiteralTypes2.ts, 32, 42), Decl(stringEnumLiteralTypes2.ts, 33, 42)) +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) + + var z2 = g(Choice.No); +>z2 : Symbol(z2, Decl(stringEnumLiteralTypes2.ts, 38, 7)) +>g : Symbol(g, Decl(stringEnumLiteralTypes2.ts, 30, 1), Decl(stringEnumLiteralTypes2.ts, 32, 42), Decl(stringEnumLiteralTypes2.ts, 33, 42)) +>Choice.No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) + + var z3 = g(a); +>z3 : Symbol(z3, Decl(stringEnumLiteralTypes2.ts, 39, 7)) +>g : Symbol(g, Decl(stringEnumLiteralTypes2.ts, 30, 1), Decl(stringEnumLiteralTypes2.ts, 32, 42), Decl(stringEnumLiteralTypes2.ts, 33, 42)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 36, 12)) + + var z4 = g(b); +>z4 : Symbol(z4, Decl(stringEnumLiteralTypes2.ts, 40, 7)) +>g : Symbol(g, Decl(stringEnumLiteralTypes2.ts, 30, 1), Decl(stringEnumLiteralTypes2.ts, 32, 42), Decl(stringEnumLiteralTypes2.ts, 33, 42)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 36, 21)) + + var z5 = g(c); +>z5 : Symbol(z5, Decl(stringEnumLiteralTypes2.ts, 41, 7)) +>g : Symbol(g, Decl(stringEnumLiteralTypes2.ts, 30, 1), Decl(stringEnumLiteralTypes2.ts, 32, 42), Decl(stringEnumLiteralTypes2.ts, 33, 42)) +>c : Symbol(c, Decl(stringEnumLiteralTypes2.ts, 36, 38)) +} + +function assertNever(x: never): never { +>assertNever : Symbol(assertNever, Decl(stringEnumLiteralTypes2.ts, 42, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 44, 21)) + + throw new Error("Unexpected value"); +>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +} + +function f10(x: YesNo) { +>f10 : Symbol(f10, Decl(stringEnumLiteralTypes2.ts, 46, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 48, 13)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes2.ts, 0, 59)) + + switch (x) { +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 48, 13)) + + case Choice.Yes: return "true"; +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) + + case Choice.No: return "false"; +>Choice.No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) + } +} + +function f11(x: YesNo) { +>f11 : Symbol(f11, Decl(stringEnumLiteralTypes2.ts, 53, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 55, 13)) +>YesNo : Symbol(YesNo, Decl(stringEnumLiteralTypes2.ts, 0, 59)) + + switch (x) { +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 55, 13)) + + case Choice.Yes: return "true"; +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) + + case Choice.No: return "false"; +>Choice.No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) + } + return assertNever(x); +>assertNever : Symbol(assertNever, Decl(stringEnumLiteralTypes2.ts, 42, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 55, 13)) +} + +function f12(x: UnknownYesNo) { +>f12 : Symbol(f12, Decl(stringEnumLiteralTypes2.ts, 61, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 63, 13)) +>UnknownYesNo : Symbol(UnknownYesNo, Decl(stringEnumLiteralTypes2.ts, 3, 36)) + + if (x) { +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 63, 13)) + + x; +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 63, 13)) + } + else { + x; +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 63, 13)) + } +} + +function f13(x: UnknownYesNo) { +>f13 : Symbol(f13, Decl(stringEnumLiteralTypes2.ts, 70, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 72, 13)) +>UnknownYesNo : Symbol(UnknownYesNo, Decl(stringEnumLiteralTypes2.ts, 3, 36)) + + if (x === Choice.Yes) { +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 72, 13)) +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) + + x; +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 72, 13)) + } + else { + x; +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 72, 13)) + } +} + +type Item = +>Item : Symbol(Item, Decl(stringEnumLiteralTypes2.ts, 79, 1)) + + { kind: Choice.Yes, a: string } | +>kind : Symbol(kind, Decl(stringEnumLiteralTypes2.ts, 82, 5)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 82, 23)) + + { kind: Choice.No, b: string }; +>kind : Symbol(kind, Decl(stringEnumLiteralTypes2.ts, 83, 5)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 83, 22)) + +function f20(x: Item) { +>f20 : Symbol(f20, Decl(stringEnumLiteralTypes2.ts, 83, 35)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 85, 13)) +>Item : Symbol(Item, Decl(stringEnumLiteralTypes2.ts, 79, 1)) + + switch (x.kind) { +>x.kind : Symbol(kind, Decl(stringEnumLiteralTypes2.ts, 82, 5), Decl(stringEnumLiteralTypes2.ts, 83, 5)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 85, 13)) +>kind : Symbol(kind, Decl(stringEnumLiteralTypes2.ts, 82, 5), Decl(stringEnumLiteralTypes2.ts, 83, 5)) + + case Choice.Yes: return x.a; +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>x.a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 82, 23)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 85, 13)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 82, 23)) + + case Choice.No: return x.b; +>Choice.No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) +>x.b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 83, 22)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 85, 13)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 83, 22)) + } +} + +function f21(x: Item) { +>f21 : Symbol(f21, Decl(stringEnumLiteralTypes2.ts, 90, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 92, 13)) +>Item : Symbol(Item, Decl(stringEnumLiteralTypes2.ts, 79, 1)) + + switch (x.kind) { +>x.kind : Symbol(kind, Decl(stringEnumLiteralTypes2.ts, 82, 5), Decl(stringEnumLiteralTypes2.ts, 83, 5)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 92, 13)) +>kind : Symbol(kind, Decl(stringEnumLiteralTypes2.ts, 82, 5), Decl(stringEnumLiteralTypes2.ts, 83, 5)) + + case Choice.Yes: return x.a; +>Choice.Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>Yes : Symbol(Choice.Yes, Decl(stringEnumLiteralTypes2.ts, 0, 33)) +>x.a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 82, 23)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 92, 13)) +>a : Symbol(a, Decl(stringEnumLiteralTypes2.ts, 82, 23)) + + case Choice.No: return x.b; +>Choice.No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) +>Choice : Symbol(Choice, Decl(stringEnumLiteralTypes2.ts, 0, 0)) +>No : Symbol(Choice.No, Decl(stringEnumLiteralTypes2.ts, 0, 46)) +>x.b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 83, 22)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 92, 13)) +>b : Symbol(b, Decl(stringEnumLiteralTypes2.ts, 83, 22)) + } + return assertNever(x); +>assertNever : Symbol(assertNever, Decl(stringEnumLiteralTypes2.ts, 42, 1)) +>x : Symbol(x, Decl(stringEnumLiteralTypes2.ts, 92, 13)) +} diff --git a/tests/baselines/reference/stringEnumLiteralTypes2.types b/tests/baselines/reference/stringEnumLiteralTypes2.types new file mode 100644 index 0000000000..7e4a51d9ae --- /dev/null +++ b/tests/baselines/reference/stringEnumLiteralTypes2.types @@ -0,0 +1,383 @@ +=== tests/cases/conformance/types/literal/stringEnumLiteralTypes2.ts === +const enum Choice { Unknown = "", Yes = "yes", No = "no" }; +>Choice : Choice +>Unknown : Choice.Unknown +>"" : "" +>Yes : Choice.Yes +>"yes" : "yes" +>No : Choice.No +>"no" : "no" + +type YesNo = Choice.Yes | Choice.No; +>YesNo : YesNo +>Choice : any +>Yes : Choice.Yes +>Choice : any +>No : Choice.No + +type NoYes = Choice.No | Choice.Yes; +>NoYes : YesNo +>Choice : any +>No : Choice.No +>Choice : any +>Yes : Choice.Yes + +type UnknownYesNo = Choice.Unknown | Choice.Yes | Choice.No; +>UnknownYesNo : Choice +>Choice : any +>Unknown : Choice.Unknown +>Choice : any +>Yes : Choice.Yes +>Choice : any +>No : Choice.No + +function f1() { +>f1 : () => void + + var a: YesNo; +>a : YesNo +>YesNo : YesNo + + var a: NoYes; +>a : YesNo +>NoYes : YesNo + + var a: Choice.Yes | Choice.No; +>a : YesNo +>Choice : any +>Yes : Choice.Yes +>Choice : any +>No : Choice.No + + var a: Choice.No | Choice.Yes; +>a : YesNo +>Choice : any +>No : Choice.No +>Choice : any +>Yes : Choice.Yes +} + +function f2(a: YesNo, b: UnknownYesNo, c: Choice) { +>f2 : (a: YesNo, b: Choice, c: Choice) => void +>a : YesNo +>YesNo : YesNo +>b : Choice +>UnknownYesNo : Choice +>c : Choice +>Choice : Choice + + b = a; +>b = a : YesNo +>b : Choice +>a : YesNo + + c = a; +>c = a : YesNo +>c : Choice +>a : YesNo + + c = b; +>c = b : YesNo +>c : Choice +>b : YesNo +} + +function f3(a: Choice.Yes, b: YesNo) { +>f3 : (a: Choice.Yes, b: YesNo) => void +>a : Choice.Yes +>Choice : any +>Yes : Choice.Yes +>b : YesNo +>YesNo : YesNo + + var x = a + b; +>x : string +>a + b : string +>a : Choice.Yes +>b : YesNo + + var y = a == b; +>y : boolean +>a == b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a != b; +>y : boolean +>a != b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a === b; +>y : boolean +>a === b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a !== b; +>y : boolean +>a !== b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a > b; +>y : boolean +>a > b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a < b; +>y : boolean +>a < b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a >= b; +>y : boolean +>a >= b : boolean +>a : Choice.Yes +>b : YesNo + + var y = a <= b; +>y : boolean +>a <= b : boolean +>a : Choice.Yes +>b : YesNo + + var y = !b; +>y : boolean +>!b : false +>b : YesNo +} + +declare function g(x: Choice.Yes): string; +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>x : Choice.Yes +>Choice : any +>Yes : Choice.Yes + +declare function g(x: Choice.No): boolean; +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>x : Choice.No +>Choice : any +>No : Choice.No + +declare function g(x: Choice): number; +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>x : Choice +>Choice : Choice + +function f5(a: YesNo, b: UnknownYesNo, c: Choice) { +>f5 : (a: YesNo, b: Choice, c: Choice) => void +>a : YesNo +>YesNo : YesNo +>b : Choice +>UnknownYesNo : Choice +>c : Choice +>Choice : Choice + + var z1 = g(Choice.Yes); +>z1 : string +>g(Choice.Yes) : string +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes + + var z2 = g(Choice.No); +>z2 : boolean +>g(Choice.No) : boolean +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>Choice.No : Choice.No +>Choice : typeof Choice +>No : Choice.No + + var z3 = g(a); +>z3 : number +>g(a) : number +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>a : YesNo + + var z4 = g(b); +>z4 : number +>g(b) : number +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>b : Choice + + var z5 = g(c); +>z5 : number +>g(c) : number +>g : { (x: Choice.Yes): string; (x: Choice.No): boolean; (x: Choice): number; } +>c : Choice +} + +function assertNever(x: never): never { +>assertNever : (x: never) => never +>x : never + + throw new Error("Unexpected value"); +>new Error("Unexpected value") : Error +>Error : ErrorConstructor +>"Unexpected value" : "Unexpected value" +} + +function f10(x: YesNo) { +>f10 : (x: YesNo) => "true" | "false" +>x : YesNo +>YesNo : YesNo + + switch (x) { +>x : YesNo + + case Choice.Yes: return "true"; +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes +>"true" : "true" + + case Choice.No: return "false"; +>Choice.No : Choice.No +>Choice : typeof Choice +>No : Choice.No +>"false" : "false" + } +} + +function f11(x: YesNo) { +>f11 : (x: YesNo) => "true" | "false" +>x : YesNo +>YesNo : YesNo + + switch (x) { +>x : YesNo + + case Choice.Yes: return "true"; +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes +>"true" : "true" + + case Choice.No: return "false"; +>Choice.No : Choice.No +>Choice : typeof Choice +>No : Choice.No +>"false" : "false" + } + return assertNever(x); +>assertNever(x) : never +>assertNever : (x: never) => never +>x : never +} + +function f12(x: UnknownYesNo) { +>f12 : (x: Choice) => void +>x : Choice +>UnknownYesNo : Choice + + if (x) { +>x : Choice + + x; +>x : YesNo + } + else { + x; +>x : Choice.Unknown + } +} + +function f13(x: UnknownYesNo) { +>f13 : (x: Choice) => void +>x : Choice +>UnknownYesNo : Choice + + if (x === Choice.Yes) { +>x === Choice.Yes : boolean +>x : Choice +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes + + x; +>x : Choice.Yes + } + else { + x; +>x : Choice.Unknown | Choice.No + } +} + +type Item = +>Item : Item + + { kind: Choice.Yes, a: string } | +>kind : Choice.Yes +>Choice : any +>Yes : Choice.Yes +>a : string + + { kind: Choice.No, b: string }; +>kind : Choice.No +>Choice : any +>No : Choice.No +>b : string + +function f20(x: Item) { +>f20 : (x: Item) => string +>x : Item +>Item : Item + + switch (x.kind) { +>x.kind : YesNo +>x : Item +>kind : YesNo + + case Choice.Yes: return x.a; +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes +>x.a : string +>x : { kind: Choice.Yes; a: string; } +>a : string + + case Choice.No: return x.b; +>Choice.No : Choice.No +>Choice : typeof Choice +>No : Choice.No +>x.b : string +>x : { kind: Choice.No; b: string; } +>b : string + } +} + +function f21(x: Item) { +>f21 : (x: Item) => string +>x : Item +>Item : Item + + switch (x.kind) { +>x.kind : YesNo +>x : Item +>kind : YesNo + + case Choice.Yes: return x.a; +>Choice.Yes : Choice.Yes +>Choice : typeof Choice +>Yes : Choice.Yes +>x.a : string +>x : { kind: Choice.Yes; a: string; } +>a : string + + case Choice.No: return x.b; +>Choice.No : Choice.No +>Choice : typeof Choice +>No : Choice.No +>x.b : string +>x : { kind: Choice.No; b: string; } +>b : string + } + return assertNever(x); +>assertNever(x) : never +>assertNever : (x: never) => never +>x : never +} diff --git a/tests/baselines/reference/stringEnumLiteralTypes3.errors.txt b/tests/baselines/reference/stringEnumLiteralTypes3.errors.txt new file mode 100644 index 0000000000..7feed87d82 --- /dev/null +++ b/tests/baselines/reference/stringEnumLiteralTypes3.errors.txt @@ -0,0 +1,166 @@ +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(10,5): error TS2322: Type 'YesNo' is not assignable to type 'Choice.Yes'. + Type 'Choice.No' is not assignable to type 'Choice.Yes'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(11,5): error TS2322: Type 'Choice' is not assignable to type 'Choice.Yes'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(12,5): error TS2322: Type 'Choice' is not assignable to type 'Choice.Yes'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(18,5): error TS2322: Type 'Choice' is not assignable to type 'YesNo'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(19,5): error TS2322: Type 'Choice' is not assignable to type 'YesNo'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(37,5): error TS2322: Type 'Choice.Unknown' is not assignable to type 'Choice.Yes'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(39,5): error TS2322: Type 'Choice.No' is not assignable to type 'Choice.Yes'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(40,5): error TS2322: Type 'Choice.Unknown' is not assignable to type 'YesNo'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(52,5): error TS2365: Operator '===' cannot be applied to types 'Choice.Yes' and 'Choice.Unknown'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(54,5): error TS2365: Operator '===' cannot be applied to types 'Choice.Yes' and 'Choice.No'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(55,5): error TS2365: Operator '===' cannot be applied to types 'YesNo' and 'Choice.Unknown'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(87,14): error TS2678: Type 'Choice.Unknown' is not comparable to type 'Choice.Yes'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(89,14): error TS2678: Type 'Choice.No' is not comparable to type 'Choice.Yes'. +tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts(96,14): error TS2678: Type 'Choice.Unknown' is not comparable to type 'YesNo'. + + +==== tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts (14 errors) ==== + const enum Choice { Unknown = "", Yes = "yes", No = "no" }; + + type Yes = Choice.Yes; + type YesNo = Choice.Yes | Choice.No; + type NoYes = Choice.No | Choice.Yes; + type UnknownYesNo = Choice.Unknown | Choice.Yes | Choice.No; + + function f1(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a = a; + a = b; + ~ +!!! error TS2322: Type 'YesNo' is not assignable to type 'Choice.Yes'. +!!! error TS2322: Type 'Choice.No' is not assignable to type 'Choice.Yes'. + a = c; + ~ +!!! error TS2322: Type 'Choice' is not assignable to type 'Choice.Yes'. + a = d; + ~ +!!! error TS2322: Type 'Choice' is not assignable to type 'Choice.Yes'. + } + + function f2(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + b = a; + b = b; + b = c; + ~ +!!! error TS2322: Type 'Choice' is not assignable to type 'YesNo'. + b = d; + ~ +!!! error TS2322: Type 'Choice' is not assignable to type 'YesNo'. + } + + function f3(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + c = a; + c = b; + c = c; + c = d; + } + + function f4(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + d = a; + d = b; + d = c; + d = d; + } + + function f5(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a = Choice.Unknown; + ~ +!!! error TS2322: Type 'Choice.Unknown' is not assignable to type 'Choice.Yes'. + a = Choice.Yes; + a = Choice.No; + ~ +!!! error TS2322: Type 'Choice.No' is not assignable to type 'Choice.Yes'. + b = Choice.Unknown; + ~ +!!! error TS2322: Type 'Choice.Unknown' is not assignable to type 'YesNo'. + b = Choice.Yes; + b = Choice.No; + c = Choice.Unknown; + c = Choice.Yes; + c = Choice.No; + d = Choice.Unknown; + d = Choice.Yes; + d = Choice.No; + } + + function f6(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a === Choice.Unknown; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2365: Operator '===' cannot be applied to types 'Choice.Yes' and 'Choice.Unknown'. + a === Choice.Yes; + a === Choice.No; + ~~~~~~~~~~~~~~~ +!!! error TS2365: Operator '===' cannot be applied to types 'Choice.Yes' and 'Choice.No'. + b === Choice.Unknown; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2365: Operator '===' cannot be applied to types 'YesNo' and 'Choice.Unknown'. + b === Choice.Yes; + b === Choice.No; + c === Choice.Unknown; + c === Choice.Yes; + c === Choice.No; + d === Choice.Unknown; + d === Choice.Yes; + d === Choice.No; + } + + function f7(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a === a; + a === b; + a === c; + a === d; + b === a; + b === b; + b === c; + b === d; + c === a; + c === b; + c === c; + c === d; + d === a; + d === b; + d === c; + d === d; + } + + function f10(x: Yes): Yes { + switch (x) { + case Choice.Unknown: return x; + ~~~~~~~~~~~~~~ +!!! error TS2678: Type 'Choice.Unknown' is not comparable to type 'Choice.Yes'. + case Choice.Yes: return x; + case Choice.No: return x; + ~~~~~~~~~ +!!! error TS2678: Type 'Choice.No' is not comparable to type 'Choice.Yes'. + } + return x; + } + + function f11(x: YesNo): YesNo { + switch (x) { + case Choice.Unknown: return x; + ~~~~~~~~~~~~~~ +!!! error TS2678: Type 'Choice.Unknown' is not comparable to type 'YesNo'. + case Choice.Yes: return x; + case Choice.No: return x; + } + return x; + } + + function f12(x: UnknownYesNo): UnknownYesNo { + switch (x) { + case Choice.Unknown: return x; + case Choice.Yes: return x; + case Choice.No: return x; + } + return x; + } + + function f13(x: Choice): Choice { + switch (x) { + case Choice.Unknown: return x; + case Choice.Yes: return x; + case Choice.No: return x; + } + return x; + } \ No newline at end of file diff --git a/tests/baselines/reference/stringEnumLiteralTypes3.js b/tests/baselines/reference/stringEnumLiteralTypes3.js new file mode 100644 index 0000000000..7e2699460b --- /dev/null +++ b/tests/baselines/reference/stringEnumLiteralTypes3.js @@ -0,0 +1,225 @@ +//// [stringEnumLiteralTypes3.ts] +const enum Choice { Unknown = "", Yes = "yes", No = "no" }; + +type Yes = Choice.Yes; +type YesNo = Choice.Yes | Choice.No; +type NoYes = Choice.No | Choice.Yes; +type UnknownYesNo = Choice.Unknown | Choice.Yes | Choice.No; + +function f1(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a = a; + a = b; + a = c; + a = d; +} + +function f2(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + b = a; + b = b; + b = c; + b = d; +} + +function f3(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + c = a; + c = b; + c = c; + c = d; +} + +function f4(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + d = a; + d = b; + d = c; + d = d; +} + +function f5(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a = Choice.Unknown; + a = Choice.Yes; + a = Choice.No; + b = Choice.Unknown; + b = Choice.Yes; + b = Choice.No; + c = Choice.Unknown; + c = Choice.Yes; + c = Choice.No; + d = Choice.Unknown; + d = Choice.Yes; + d = Choice.No; +} + +function f6(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a === Choice.Unknown; + a === Choice.Yes; + a === Choice.No; + b === Choice.Unknown; + b === Choice.Yes; + b === Choice.No; + c === Choice.Unknown; + c === Choice.Yes; + c === Choice.No; + d === Choice.Unknown; + d === Choice.Yes; + d === Choice.No; +} + +function f7(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a === a; + a === b; + a === c; + a === d; + b === a; + b === b; + b === c; + b === d; + c === a; + c === b; + c === c; + c === d; + d === a; + d === b; + d === c; + d === d; +} + +function f10(x: Yes): Yes { + switch (x) { + case Choice.Unknown: return x; + case Choice.Yes: return x; + case Choice.No: return x; + } + return x; +} + +function f11(x: YesNo): YesNo { + switch (x) { + case Choice.Unknown: return x; + case Choice.Yes: return x; + case Choice.No: return x; + } + return x; +} + +function f12(x: UnknownYesNo): UnknownYesNo { + switch (x) { + case Choice.Unknown: return x; + case Choice.Yes: return x; + case Choice.No: return x; + } + return x; +} + +function f13(x: Choice): Choice { + switch (x) { + case Choice.Unknown: return x; + case Choice.Yes: return x; + case Choice.No: return x; + } + return x; +} + +//// [stringEnumLiteralTypes3.js] +; +function f1(a, b, c, d) { + a = a; + a = b; + a = c; + a = d; +} +function f2(a, b, c, d) { + b = a; + b = b; + b = c; + b = d; +} +function f3(a, b, c, d) { + c = a; + c = b; + c = c; + c = d; +} +function f4(a, b, c, d) { + d = a; + d = b; + d = c; + d = d; +} +function f5(a, b, c, d) { + a = "" /* Unknown */; + a = "yes" /* Yes */; + a = "no" /* No */; + b = "" /* Unknown */; + b = "yes" /* Yes */; + b = "no" /* No */; + c = "" /* Unknown */; + c = "yes" /* Yes */; + c = "no" /* No */; + d = "" /* Unknown */; + d = "yes" /* Yes */; + d = "no" /* No */; +} +function f6(a, b, c, d) { + a === "" /* Unknown */; + a === "yes" /* Yes */; + a === "no" /* No */; + b === "" /* Unknown */; + b === "yes" /* Yes */; + b === "no" /* No */; + c === "" /* Unknown */; + c === "yes" /* Yes */; + c === "no" /* No */; + d === "" /* Unknown */; + d === "yes" /* Yes */; + d === "no" /* No */; +} +function f7(a, b, c, d) { + a === a; + a === b; + a === c; + a === d; + b === a; + b === b; + b === c; + b === d; + c === a; + c === b; + c === c; + c === d; + d === a; + d === b; + d === c; + d === d; +} +function f10(x) { + switch (x) { + case "" /* Unknown */: return x; + case "yes" /* Yes */: return x; + case "no" /* No */: return x; + } + return x; +} +function f11(x) { + switch (x) { + case "" /* Unknown */: return x; + case "yes" /* Yes */: return x; + case "no" /* No */: return x; + } + return x; +} +function f12(x) { + switch (x) { + case "" /* Unknown */: return x; + case "yes" /* Yes */: return x; + case "no" /* No */: return x; + } + return x; +} +function f13(x) { + switch (x) { + case "" /* Unknown */: return x; + case "yes" /* Yes */: return x; + case "no" /* No */: return x; + } + return x; +} diff --git a/tests/cases/conformance/enums/enumClassification.ts b/tests/cases/conformance/enums/enumClassification.ts new file mode 100644 index 0000000000..bbb0598408 --- /dev/null +++ b/tests/cases/conformance/enums/enumClassification.ts @@ -0,0 +1,80 @@ +// @declaration: true + +// An enum type where each member has no initializer or an initializer that specififes +// a numeric literal, a string literal, or a single identifier naming another member in +// the enum type is classified as a literal enum type. An enum type that doesn't adhere +// to this pattern is classified as a numeric enum type. + +// Examples of literal enum types + +enum E01 { + A +} + +enum E02 { + A = 123 +} + +enum E03 { + A = "hello" +} + +enum E04 { + A, + B, + C +} + +enum E05 { + A, + B = 10, + C +} + +enum E06 { + A = "one", + B = "two", + C = "three" +} + +enum E07 { + A, + B, + C = "hi", + D = 10, + E, + F = "bye" +} + +enum E08 { + A = 10, + B = "hello", + C = A, + D = B, + E = C, +} + +// Examples of numeric enum types with only constant members + +enum E10 {} + +enum E11 { + A = +0, + B, + C +} + +enum E12 { + A = 1 << 0, + B = 1 << 1, + C = 1 << 2 +} + +// Examples of numeric enum types with constant and computed members + +enum E20 { + A = "foo".length, + B = A + 1, + C = +"123", + D = Math.sin(1) +} diff --git a/tests/cases/conformance/types/literal/stringEnumLiteralTypes1.ts b/tests/cases/conformance/types/literal/stringEnumLiteralTypes1.ts new file mode 100644 index 0000000000..11be7c9060 --- /dev/null +++ b/tests/cases/conformance/types/literal/stringEnumLiteralTypes1.ts @@ -0,0 +1,99 @@ +const enum Choice { Unknown = "", Yes = "yes", No = "no" }; + +type YesNo = Choice.Yes | Choice.No; +type NoYes = Choice.No | Choice.Yes; +type UnknownYesNo = Choice.Unknown | Choice.Yes | Choice.No; + +function f1() { + var a: YesNo; + var a: NoYes; + var a: Choice.Yes | Choice.No; + var a: Choice.No | Choice.Yes; +} + +function f2(a: YesNo, b: UnknownYesNo, c: Choice) { + b = a; + c = a; + c = b; +} + +function f3(a: Choice.Yes, b: YesNo) { + var x = a + b; + var y = a == b; + var y = a != b; + var y = a === b; + var y = a !== b; + var y = a > b; + var y = a < b; + var y = a >= b; + var y = a <= b; + var y = !b; +} + +declare function g(x: Choice.Yes): string; +declare function g(x: Choice.No): boolean; +declare function g(x: Choice): number; + +function f5(a: YesNo, b: UnknownYesNo, c: Choice) { + var z1 = g(Choice.Yes); + var z2 = g(Choice.No); + var z3 = g(a); + var z4 = g(b); + var z5 = g(c); +} + +function assertNever(x: never): never { + throw new Error("Unexpected value"); +} + +function f10(x: YesNo) { + switch (x) { + case Choice.Yes: return "true"; + case Choice.No: return "false"; + } +} + +function f11(x: YesNo) { + switch (x) { + case Choice.Yes: return "true"; + case Choice.No: return "false"; + } + return assertNever(x); +} + +function f12(x: UnknownYesNo) { + if (x) { + x; + } + else { + x; + } +} + +function f13(x: UnknownYesNo) { + if (x === Choice.Yes) { + x; + } + else { + x; + } +} + +type Item = + { kind: Choice.Yes, a: string } | + { kind: Choice.No, b: string }; + +function f20(x: Item) { + switch (x.kind) { + case Choice.Yes: return x.a; + case Choice.No: return x.b; + } +} + +function f21(x: Item) { + switch (x.kind) { + case Choice.Yes: return x.a; + case Choice.No: return x.b; + } + return assertNever(x); +} \ No newline at end of file diff --git a/tests/cases/conformance/types/literal/stringEnumLiteralTypes2.ts b/tests/cases/conformance/types/literal/stringEnumLiteralTypes2.ts new file mode 100644 index 0000000000..f6a71fcaa7 --- /dev/null +++ b/tests/cases/conformance/types/literal/stringEnumLiteralTypes2.ts @@ -0,0 +1,101 @@ +// @strictNullChecks: true + +const enum Choice { Unknown = "", Yes = "yes", No = "no" }; + +type YesNo = Choice.Yes | Choice.No; +type NoYes = Choice.No | Choice.Yes; +type UnknownYesNo = Choice.Unknown | Choice.Yes | Choice.No; + +function f1() { + var a: YesNo; + var a: NoYes; + var a: Choice.Yes | Choice.No; + var a: Choice.No | Choice.Yes; +} + +function f2(a: YesNo, b: UnknownYesNo, c: Choice) { + b = a; + c = a; + c = b; +} + +function f3(a: Choice.Yes, b: YesNo) { + var x = a + b; + var y = a == b; + var y = a != b; + var y = a === b; + var y = a !== b; + var y = a > b; + var y = a < b; + var y = a >= b; + var y = a <= b; + var y = !b; +} + +declare function g(x: Choice.Yes): string; +declare function g(x: Choice.No): boolean; +declare function g(x: Choice): number; + +function f5(a: YesNo, b: UnknownYesNo, c: Choice) { + var z1 = g(Choice.Yes); + var z2 = g(Choice.No); + var z3 = g(a); + var z4 = g(b); + var z5 = g(c); +} + +function assertNever(x: never): never { + throw new Error("Unexpected value"); +} + +function f10(x: YesNo) { + switch (x) { + case Choice.Yes: return "true"; + case Choice.No: return "false"; + } +} + +function f11(x: YesNo) { + switch (x) { + case Choice.Yes: return "true"; + case Choice.No: return "false"; + } + return assertNever(x); +} + +function f12(x: UnknownYesNo) { + if (x) { + x; + } + else { + x; + } +} + +function f13(x: UnknownYesNo) { + if (x === Choice.Yes) { + x; + } + else { + x; + } +} + +type Item = + { kind: Choice.Yes, a: string } | + { kind: Choice.No, b: string }; + +function f20(x: Item) { + switch (x.kind) { + case Choice.Yes: return x.a; + case Choice.No: return x.b; + } +} + +function f21(x: Item) { + switch (x.kind) { + case Choice.Yes: return x.a; + case Choice.No: return x.b; + } + return assertNever(x); +} \ No newline at end of file diff --git a/tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts b/tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts new file mode 100644 index 0000000000..f296fd875f --- /dev/null +++ b/tests/cases/conformance/types/literal/stringEnumLiteralTypes3.ts @@ -0,0 +1,119 @@ +const enum Choice { Unknown = "", Yes = "yes", No = "no" }; + +type Yes = Choice.Yes; +type YesNo = Choice.Yes | Choice.No; +type NoYes = Choice.No | Choice.Yes; +type UnknownYesNo = Choice.Unknown | Choice.Yes | Choice.No; + +function f1(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a = a; + a = b; + a = c; + a = d; +} + +function f2(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + b = a; + b = b; + b = c; + b = d; +} + +function f3(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + c = a; + c = b; + c = c; + c = d; +} + +function f4(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + d = a; + d = b; + d = c; + d = d; +} + +function f5(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a = Choice.Unknown; + a = Choice.Yes; + a = Choice.No; + b = Choice.Unknown; + b = Choice.Yes; + b = Choice.No; + c = Choice.Unknown; + c = Choice.Yes; + c = Choice.No; + d = Choice.Unknown; + d = Choice.Yes; + d = Choice.No; +} + +function f6(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a === Choice.Unknown; + a === Choice.Yes; + a === Choice.No; + b === Choice.Unknown; + b === Choice.Yes; + b === Choice.No; + c === Choice.Unknown; + c === Choice.Yes; + c === Choice.No; + d === Choice.Unknown; + d === Choice.Yes; + d === Choice.No; +} + +function f7(a: Yes, b: YesNo, c: UnknownYesNo, d: Choice) { + a === a; + a === b; + a === c; + a === d; + b === a; + b === b; + b === c; + b === d; + c === a; + c === b; + c === c; + c === d; + d === a; + d === b; + d === c; + d === d; +} + +function f10(x: Yes): Yes { + switch (x) { + case Choice.Unknown: return x; + case Choice.Yes: return x; + case Choice.No: return x; + } + return x; +} + +function f11(x: YesNo): YesNo { + switch (x) { + case Choice.Unknown: return x; + case Choice.Yes: return x; + case Choice.No: return x; + } + return x; +} + +function f12(x: UnknownYesNo): UnknownYesNo { + switch (x) { + case Choice.Unknown: return x; + case Choice.Yes: return x; + case Choice.No: return x; + } + return x; +} + +function f13(x: Choice): Choice { + switch (x) { + case Choice.Unknown: return x; + case Choice.Yes: return x; + case Choice.No: return x; + } + return x; +} \ No newline at end of file From 640e8f5255844b3a29597b0631ce083dbc31b953 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 1 May 2017 07:12:27 -0700 Subject: [PATCH 23/83] Fix declaration emit for string valued enum members --- src/compiler/declarationEmitter.ts | 2 +- src/compiler/utilities.ts | 6 +++++- src/services/symbolDisplay.ts | 6 ++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 2bd8d5971f..495713ac07 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -985,7 +985,7 @@ namespace ts { const enumMemberValue = resolver.getConstantValue(node); if (enumMemberValue !== undefined) { write(" = "); - write(enumMemberValue.toString()); + write(getTextOfConstantValue(enumMemberValue)); } write(","); writeLine(); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 8080f6985e..624136b26a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -349,7 +349,11 @@ namespace ts { Debug.fail(`Literal kind '${node.kind}' not accounted for.`); } - export function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) { + export function getTextOfConstantValue(value: string | number) { + return typeof value === "string" ? getQuotedEscapedLiteralText('"', value, '"') : "" + value; + } + + function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) { return leftQuote + escapeNonAsciiCharacters(escapeString(text)) + rightQuote; } diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 8f61ca9c91..43eb07b343 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -330,10 +330,8 @@ namespace ts.SymbolDisplay { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); displayParts.push(spacePart()); - const valuePart = typeof constantValue === "number" ? - displayPart("" + constantValue, SymbolDisplayPartKind.numericLiteral) : - displayPart(getQuotedEscapedLiteralText('"', constantValue, '"'), SymbolDisplayPartKind.stringLiteral); - displayParts.push(valuePart); + displayParts.push(displayPart(getTextOfConstantValue(constantValue), + typeof constantValue === "number" ? SymbolDisplayPartKind.numericLiteral : SymbolDisplayPartKind.stringLiteral)); } } } From 25a01c04235cb6d33225b3dda2a5d604cfb0fae6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 1 May 2017 07:12:38 -0700 Subject: [PATCH 24/83] Accept new baselines --- .../baselines/reference/enumClassification.js | 106 ++---------------- 1 file changed, 8 insertions(+), 98 deletions(-) diff --git a/tests/baselines/reference/enumClassification.js b/tests/baselines/reference/enumClassification.js index f153230002..0a046dc60d 100644 --- a/tests/baselines/reference/enumClassification.js +++ b/tests/baselines/reference/enumClassification.js @@ -166,7 +166,7 @@ declare enum E02 { A = 123, } declare enum E03 { - A = hello, + A = "hello", } declare enum E04 { A = 0, @@ -179,23 +179,23 @@ declare enum E05 { C = 11, } declare enum E06 { - A = one, - B = two, - C = three, + A = "one", + B = "two", + C = "three", } declare enum E07 { A = 0, B = 1, - C = hi, + C = "hi", D = 10, E = 11, - F = bye, + F = "bye", } declare enum E08 { A = 10, - B = hello, + B = "hello", C = 10, - D = hello, + D = "hello", E = 10, } declare enum E10 { @@ -216,93 +216,3 @@ declare enum E20 { C, D, } - - -//// [DtsFileErrors] - - -tests/cases/conformance/enums/enumClassification.d.ts(8,9): error TS1066: In ambient enum declarations member initializer must be constant expression. -tests/cases/conformance/enums/enumClassification.d.ts(21,9): error TS1066: In ambient enum declarations member initializer must be constant expression. -tests/cases/conformance/enums/enumClassification.d.ts(22,9): error TS1066: In ambient enum declarations member initializer must be constant expression. -tests/cases/conformance/enums/enumClassification.d.ts(23,9): error TS1066: In ambient enum declarations member initializer must be constant expression. -tests/cases/conformance/enums/enumClassification.d.ts(28,9): error TS1066: In ambient enum declarations member initializer must be constant expression. -tests/cases/conformance/enums/enumClassification.d.ts(31,9): error TS1066: In ambient enum declarations member initializer must be constant expression. -tests/cases/conformance/enums/enumClassification.d.ts(35,9): error TS1066: In ambient enum declarations member initializer must be constant expression. -tests/cases/conformance/enums/enumClassification.d.ts(37,9): error TS1066: In ambient enum declarations member initializer must be constant expression. - - -==== tests/cases/conformance/enums/enumClassification.d.ts (8 errors) ==== - declare enum E01 { - A = 0, - } - declare enum E02 { - A = 123, - } - declare enum E03 { - A = hello, - ~~~~~ -!!! error TS1066: In ambient enum declarations member initializer must be constant expression. - } - declare enum E04 { - A = 0, - B = 1, - C = 2, - } - declare enum E05 { - A = 0, - B = 10, - C = 11, - } - declare enum E06 { - A = one, - ~~~ -!!! error TS1066: In ambient enum declarations member initializer must be constant expression. - B = two, - ~~~ -!!! error TS1066: In ambient enum declarations member initializer must be constant expression. - C = three, - ~~~~~ -!!! error TS1066: In ambient enum declarations member initializer must be constant expression. - } - declare enum E07 { - A = 0, - B = 1, - C = hi, - ~~ -!!! error TS1066: In ambient enum declarations member initializer must be constant expression. - D = 10, - E = 11, - F = bye, - ~~~ -!!! error TS1066: In ambient enum declarations member initializer must be constant expression. - } - declare enum E08 { - A = 10, - B = hello, - ~~~~~ -!!! error TS1066: In ambient enum declarations member initializer must be constant expression. - C = 10, - D = hello, - ~~~~~ -!!! error TS1066: In ambient enum declarations member initializer must be constant expression. - E = 10, - } - declare enum E10 { - } - declare enum E11 { - A = 0, - B = 1, - C = 2, - } - declare enum E12 { - A = 1, - B = 2, - C = 4, - } - declare enum E20 { - A, - B, - C, - D, - } - \ No newline at end of file From ceb78f9607832b321dbd9bb9d2c086a65db5aa15 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 1 May 2017 09:10:51 -0700 Subject: [PATCH 25/83] A couple of small simplifications --- src/compiler/checker.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c88951d8f2..ee46e78774 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3051,7 +3051,7 @@ namespace ts { buildSymbolDisplay(parent, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags); // In a literal enum type with a single member E { A }, E and E.A denote the // same type. We always display this type simply as E. - if (getDeclaredTypeOfSymbol(parent).flags & TypeFlags.Union) { + if (getDeclaredTypeOfSymbol(parent) !== type) { writePunctuation(writer, SyntaxKind.DotToken); appendSymbolNameOnly(type.symbol, writer); } @@ -4958,9 +4958,7 @@ namespace ts { for (const member of (declaration).members) { const memberType = getLiteralType(getEnumMemberValue(member), enumCount, getSymbolOfNode(member)); getSymbolLinks(getSymbolOfNode(member)).declaredType = memberType; - if (!contains(memberTypeList, memberType)) { - memberTypeList.push(memberType); - } + memberTypeList.push(memberType); } } } From 384d54603f00db19d32045bca29645e6ca8aea4d Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 4 May 2017 15:27:50 -0700 Subject: [PATCH 26/83] Basic parens handling and stubbed TypeFormatFlags --- src/compiler/checker.ts | 74 +++++++++++++++++++++++++------ src/compiler/emitter.ts | 3 +- src/compiler/factory.ts | 12 +++++ src/compiler/types.ts | 38 ++++++++++++---- src/compiler/visitor.ts | 3 +- src/services/codefixes/helpers.ts | 2 +- 6 files changed, 107 insertions(+), 25 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 91eee774ee..fc067d63d5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2287,8 +2287,16 @@ namespace ts { interface NodeBuilderContext { readonly enclosingDeclaration: Node | undefined; readonly flags: NodeBuilderFlags | undefined; + + // State encounteredError: boolean; inObjectTypeLiteral: boolean; + // TODO: needed for part of parens handling + InElementType: boolean; // Writing an array or union element type + // TODO: ??? + InFirstTypeArgument: boolean; // Writing first type argument of the instantiated type + // TODO: ??? + InTypeAlias: boolean; // Writing type in type alias declaration checkAlias: boolean; symbolStack: Symbol[] | undefined; } @@ -2299,18 +2307,28 @@ namespace ts { flags, encounteredError: false, inObjectTypeLiteral: false, + InElementType: false, + InFirstTypeArgument: false, + InTypeAlias: false, checkAlias: true, symbolStack: undefined }; } function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { + const InElementType = context.InElementType; + // TODO: why doesn't tts unset the flag? + context.InElementType = false; + + // TODO: should be assert? if (!type) { context.encounteredError = true; // TODO(aozgaa): should we return implict any (undefined) or explicit any (keywordtypenode)? return undefined; } + + if (type.flags & TypeFlags.Any) { return createKeywordTypeNode(SyntaxKind.AnyKeyword); } @@ -2390,16 +2408,17 @@ namespace ts { if (context.checkAlias && type.aliasSymbol) { const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, context); - const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments); + const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, /*addInElementTypeFlag*/ false); return createTypeReferenceNode(name, typeArgumentNodes); } context.checkAlias = false; - if (type.flags & TypeFlags.Union) { - const formattedUnionTypes = formatUnionTypes((type).types); - const unionTypeNodes = formattedUnionTypes && mapToTypeNodeArray(formattedUnionTypes); - if (unionTypeNodes && unionTypeNodes.length > 0) { - return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, unionTypeNodes); + if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { + const types = type.flags & TypeFlags.Union ? formatUnionTypes((type).types) : (type).types; + const typeNodes = types && mapToTypeNodeArray(types, /*addInElementTypeFlag*/ true); + if (typeNodes && typeNodes.length > 0) { + const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes); + return InElementType ? createParenthesizedTypeNode(unionOrIntersectionTypeNode) : unionOrIntersectionTypeNode; } else { if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyUnionOrIntersection)) { @@ -2409,10 +2428,6 @@ namespace ts { } } - if (type.flags & TypeFlags.Intersection) { - return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, mapToTypeNodeArray((type as UnionType).types)); - } - if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) { Debug.assert(!!(type.flags & TypeFlags.Object)); // The type is an object literal type. @@ -2421,25 +2436,33 @@ namespace ts { if (type.flags & TypeFlags.Index) { const indexedType = (type).type; + context.InElementType = true; const indexTypeNode = typeToTypeNodeHelper(indexedType, context); + Debug.assert(context.InElementType === false); return createTypeOperatorNode(indexTypeNode); } + if (type.flags & TypeFlags.IndexedAccess) { + context.InElementType = true; const objectTypeNode = typeToTypeNodeHelper((type).objectType, context); + Debug.assert(context.InElementType === false); const indexTypeNode = typeToTypeNodeHelper((type).indexType, context); return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); } Debug.fail("Should be unreachable."); - function mapToTypeNodeArray(types: Type[]): TypeNode[] { + function mapToTypeNodeArray(types: Type[], addInElementTypeFlag: boolean): TypeNode[] { const result = []; + Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper"); for (const type of types) { + context.InElementType = addInElementTypeFlag; const typeNode = typeToTypeNodeHelper(type, context); if (typeNode) { result.push(typeNode); } } + Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper"); return result; } @@ -2523,6 +2546,7 @@ namespace ts { if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { const signature = resolved.callSignatures[0]; + shouldAddParenthesisAroundFunctionType(signature, context); return signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context); } if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { @@ -2538,6 +2562,20 @@ namespace ts { return createTypeLiteralNode(members); } + + function shouldAddParenthesisAroundFunctionType(callSignature: Signature, context: NodeBuilderContext) { + if (context.InElementType) { + return true; + } + else if (context.InFirstTypeArgument) { + // Add parenthesis around function type for the first type argument to avoid ambiguity + const typeParameters = callSignature.target && (context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature) ? + callSignature.target.typeParameters : callSignature.typeParameters; + return typeParameters && typeParameters.length !== 0; + } + return false; + } + function createTypeQueryNodeFromSymbol(symbol: Symbol) { const entityName = symbolToName(symbol, /*expectsIdentifier*/ false, context); return createTypeQueryNode(entityName); @@ -2546,12 +2584,14 @@ namespace ts { function typeReferenceToTypeNode(type: TypeReference) { const typeArguments: Type[] = type.typeArguments || emptyArray; if (type.target === globalArrayType) { + context.InElementType = true; const elementType = typeToTypeNodeHelper(typeArguments[0], context); + context.InElementType = false; return createArrayTypeNode(elementType); } else if (type.target.objectFlags & ObjectFlags.Tuple) { if (typeArguments.length > 0) { - const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type))); + const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)), /*addInElementTypeFlag*/ false); if (tupleConstituentNodes && tupleConstituentNodes.length > 0) { return createTupleTypeNode(tupleConstituentNodes); } @@ -2566,6 +2606,7 @@ namespace ts { let i = 0; let qualifiedName: QualifiedName | undefined = undefined; if (outerTypeParameters) { + let inFirstTypeArgument = true; const length = outerTypeParameters.length; while (i < length) { // Find group of type arguments for type parameters with the same declaring container. @@ -2577,6 +2618,7 @@ namespace ts { // When type parameters are their own type arguments for the whole group (i.e. we have // the default outer type arguments), we don't show the group. if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { + // inFirstTypeArgument??? const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true, context); if (!qualifiedName) { qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined); @@ -2587,6 +2629,7 @@ namespace ts { qualifiedName = createQualifiedName(qualifiedName, /*right*/ undefined); } } + inFirstTypeArgument = false; } } let entityName: EntityName = undefined; @@ -2600,7 +2643,7 @@ namespace ts { entityName = nameIdentifier; } const typeParameterCount = (type.target.typeParameters || emptyArray).length; - const typeArgumentNodes = some(typeArguments) ? mapToTypeNodeArray(typeArguments.slice(i, typeParameterCount - i)) : undefined; + const typeArgumentNodes = some(typeArguments) ? mapToTypeNodeArray(typeArguments.slice(i, typeParameterCount - i), /*addInElementTypeFlag*/ false) : undefined; return createTypeReferenceNode(entityName, typeArgumentNodes); } } @@ -2695,7 +2738,7 @@ namespace ts { const returnType = getReturnTypeOfSignature(signature); returnTypeNode = returnType && typeToTypeNodeHelper(returnType, context); } - if(context.flags & NodeBuilderFlags.suppressAnyReturnType) { + if(context.flags & NodeBuilderFlags.SuppressAnyReturnType) { if(returnTypeNode && returnTypeNode.kind === SyntaxKind.AnyKeyword) { returnTypeNode = undefined; } @@ -2733,6 +2776,8 @@ namespace ts { return parameterNode; } + // TODO: add meaning: SymbolFlags argument. + // TODO: add SymbolFormatFlags?? Yes to add outer type parameters. Defer UseOnlyExternalAliasing until a separate symbolbuilder PR. function symbolToName(symbol: Symbol, expectsIdentifier: true, context: NodeBuilderContext): Identifier; function symbolToName(symbol: Symbol, expectsIdentifier: false, context: NodeBuilderContext): EntityName; function symbolToName(symbol: Symbol, expectsIdentifier: boolean, context: NodeBuilderContext): EntityName { @@ -2826,6 +2871,7 @@ namespace ts { } } } + function getNameOfSymbol(symbol: Symbol, context: NodeBuilderContext): string { const declaration = firstOrUndefined(symbol.declarations); if (declaration) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index afafee51bf..eebbe30289 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2947,8 +2947,9 @@ namespace ts { // Precomputed Formats Modifiers = SingleLine | SpaceBetweenSiblings, HeritageClauses = SingleLine | SpaceBetweenSiblings, - SingleLineTypeLiteralMembers = SpaceBetweenBraces | SpaceBetweenSiblings | Indented, // MultiLine | Indented, + SingleLineTypeLiteralMembers = SingleLine | SpaceBetweenBraces | SpaceBetweenSiblings | Indented, // MultiLine | Indented, MultiLineTypeLiteralMembers = MultiLine | Indented, + TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented, UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine, IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine, diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 9dfd38a0a5..172710f39a 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -393,6 +393,18 @@ namespace ts { : node; } + export function createParenthesizedTypeNode(type: TypeNode) { + const parenthesizedTypeNode = createSynthesizedNode(SyntaxKind.ParenthesizedType) as ParenthesizedTypeNode; + parenthesizedTypeNode.type = type; + return parenthesizedTypeNode; + } + + export function updateParenthesizedTypeNode(node: ParenthesizedTypeNode, type: TypeNode) { + return node.type !== type + ? updateNode(createParenthesizedTypeNode(type), node) + : node; + } + export function createTypeLiteralNode(members: TypeElement[]) { const typeLiteralNode = createSynthesizedNode(SyntaxKind.TypeLiteral) as TypeLiteralNode; typeLiteralNode.members = createNodeArray(members); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 53507e3aa3..17df0243a1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2559,14 +2559,36 @@ namespace ts { export enum NodeBuilderFlags { None = 0, - allowThisInObjectLiteral = 1 << 0, - allowQualifedNameInPlaceOfIdentifier = 1 << 1, - allowTypeParameterInQualifiedName = 1 << 2, - allowAnonymousIdentifier = 1 << 3, - allowEmptyUnionOrIntersection = 1 << 4, - allowEmptyTuple = 1 << 5, - suppressAnyReturnType = 1 << 6, - ignoreErrors = allowThisInObjectLiteral | allowQualifedNameInPlaceOfIdentifier | allowTypeParameterInQualifiedName | allowAnonymousIdentifier | allowEmptyUnionOrIntersection | allowEmptyTuple + // Options + NoTruncation = 1 << 0, // Don't truncate result + // TODO: part of emit. + WriteArrayAsGenericType = 1 << 1, // Write Array instead T[] + // TODO: part of emit. + UseTypeOfFunction = 1 << 2, // Write typeof instead of function type literal + // TODO: part of emit. + WriteArrowStyleSignature = 1 << 3, // Write arrow style signature + // TODO: turn it into a failing type reference? + WriteOwnNameForAnyLike = 1 << 4, // Write symbol's own name instead of 'any' for any like types (eg. unknown, __resolving__ etc) + // TODO + WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature + // TODO + UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type) + // TODO + UseTypeAliasValue = 1 << 7, // Serialize the type instead of using type-alias. This is needed when we emit declaration file. + SuppressAnyReturnType = 1 << 8, // If the return type is any-like, don't offer a return type. + // TODO + AddUndefined = 1 << 9, // Add undefined to types of initialized, non-optional parameters + + // Error handling + allowThisInObjectLiteral = 1 << 10, + allowQualifedNameInPlaceOfIdentifier = 1 << 11, + allowTypeParameterInQualifiedName = 1 << 12, + allowAnonymousIdentifier = 1 << 13, + allowEmptyUnionOrIntersection = 1 << 14, + allowEmptyTuple = 1 << 15, + + ignoreErrors = allowThisInObjectLiteral | allowQualifedNameInPlaceOfIdentifier | allowTypeParameterInQualifiedName | allowAnonymousIdentifier | allowEmptyUnionOrIntersection | allowEmptyTuple, + } export interface SymbolDisplayBuilder { diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 262520292e..1e196a925f 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -322,7 +322,8 @@ namespace ts { nodesVisitor((node).types, visitor, isTypeNode)); case SyntaxKind.ParenthesizedType: - throw Debug.fail("not implemented."); + return updateParenthesizedTypeNode(node, + visitNode((node).type, visitor, isTypeNode)); case SyntaxKind.TypeOperator: return updateTypeOperatorNode(node, visitNode((node).type, visitor, isTypeNode)); diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 0f636bb09c..7c1a8c407f 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -130,7 +130,7 @@ namespace ts.codefix { } function signatureToMethodDeclaration(signature: Signature, enclosingDeclaration: Node, body?: Block) { - const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration, NodeBuilderFlags.suppressAnyReturnType); + const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration, NodeBuilderFlags.SuppressAnyReturnType); if (signatureDeclaration) { signatureDeclaration.decorators = undefined; signatureDeclaration.modifiers = modifiers; From c0adf99f3510092ea190b34d7bdb5526f5187e6b Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 5 May 2017 10:54:53 -0700 Subject: [PATCH 27/83] Add aliasing test --- .../codeFixClassImplementInterfaceMemberTypeAlias.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts new file mode 100644 index 0000000000..eab4c80c78 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts @@ -0,0 +1,12 @@ +/// + +//// type MyType = [string, number]; +//// interface I { test(a: MyType): void; } +//// class C implements I {[| |]} + +verify.rangeAfterCodeFix(` + test(a: MyType): void { + throw new Error("Method not implemented."); + } +`); + From 1774c67afaa79abb0cba5b36fbf16bb20c7d2e3a Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 5 May 2017 11:00:00 -0700 Subject: [PATCH 28/83] parens and this param for function type --- src/compiler/checker.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fc067d63d5..6ee3377d88 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2406,7 +2406,7 @@ namespace ts { return createTypeReferenceNode(name, /*typeArguments*/ undefined); } - if (context.checkAlias && type.aliasSymbol) { + if (!context.InTypeAlias && context.checkAlias && type.aliasSymbol) { const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, context); const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, /*addInElementTypeFlag*/ false); return createTypeReferenceNode(name, typeArgumentNodes); @@ -2546,8 +2546,11 @@ namespace ts { if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { const signature = resolved.callSignatures[0]; - shouldAddParenthesisAroundFunctionType(signature, context); - return signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context); + const functionTypeNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context); + return shouldAddParenthesisAroundFunctionType(signature, context) ? + createParenthesizedTypeNode(functionTypeNode) : + functionTypeNode; + } if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { const signature = resolved.constructSignatures[0]; @@ -2564,7 +2567,7 @@ namespace ts { function shouldAddParenthesisAroundFunctionType(callSignature: Signature, context: NodeBuilderContext) { - if (context.InElementType) { + if (InElementType) { return true; } else if (context.InFirstTypeArgument) { @@ -2727,6 +2730,10 @@ namespace ts { const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context)); const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter, context)); + if (signature.thisParameter) { + const thisParameter = symbolToParameterDeclaration(signature.thisParameter, context); + parameters.unshift(thisParameter); + } let returnTypeNode: TypeNode; if (signature.typePredicate) { const typePredicate = signature.typePredicate; From d2bda47e80f94b60cc8971a55c39e86f1f6455ab Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 5 May 2017 12:39:47 -0700 Subject: [PATCH 29/83] fix inTypeAlias logic --- src/compiler/checker.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6ee3377d88..5e7ce03afe 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2297,7 +2297,6 @@ namespace ts { InFirstTypeArgument: boolean; // Writing first type argument of the instantiated type // TODO: ??? InTypeAlias: boolean; // Writing type in type alias declaration - checkAlias: boolean; symbolStack: Symbol[] | undefined; } @@ -2310,7 +2309,6 @@ namespace ts { InElementType: false, InFirstTypeArgument: false, InTypeAlias: false, - checkAlias: true, symbolStack: undefined }; } @@ -2319,6 +2317,8 @@ namespace ts { const InElementType = context.InElementType; // TODO: why doesn't tts unset the flag? context.InElementType = false; + const inTypeAlias = context.InTypeAlias; + context.InTypeAlias = false; // TODO: should be assert? if (!type) { @@ -2406,12 +2406,11 @@ namespace ts { return createTypeReferenceNode(name, /*typeArguments*/ undefined); } - if (!context.InTypeAlias && context.checkAlias && type.aliasSymbol) { + if (!inTypeAlias && type.aliasSymbol) { const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, context); const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, /*addInElementTypeFlag*/ false); return createTypeReferenceNode(name, typeArgumentNodes); } - context.checkAlias = false; if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { const types = type.flags & TypeFlags.Union ? formatUnionTypes((type).types) : (type).types; From a5bef216aea8b871f7f23a78b260a4d635cffb74 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 5 May 2017 13:47:51 -0700 Subject: [PATCH 30/83] Use `symbolToName` instead of copying --- src/compiler/checker.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5e7ce03afe..18a6c03c6d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2287,7 +2287,7 @@ namespace ts { interface NodeBuilderContext { readonly enclosingDeclaration: Node | undefined; readonly flags: NodeBuilderFlags | undefined; - + // State encounteredError: boolean; inObjectTypeLiteral: boolean; @@ -2564,7 +2564,6 @@ namespace ts { return createTypeLiteralNode(members); } - function shouldAddParenthesisAroundFunctionType(callSignature: Signature, context: NodeBuilderContext) { if (InElementType) { return true; @@ -2670,13 +2669,10 @@ namespace ts { return typeElements; } + // TODO: make logic mirror that of writeObjectLiteralType for (const propertySymbol of properties) { const propertyType = getTypeOfSymbol(propertySymbol); - const oldDeclaration = propertySymbol.declarations && propertySymbol.declarations[0] as TypeElement; - if (!oldDeclaration) { - return; - } - const propertyName = getDeepSynthesizedClone(oldDeclaration.name); + const propertyName = symbolToName(propertySymbol, /*expectsIdentifier*/ true, context); const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined; if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) { const signatures = getSignaturesOfType(propertyType, SignatureKind.Call); @@ -2697,7 +2693,7 @@ namespace ts { propertyName, optionalToken, propertyTypeNode, - /*initializer*/undefined); + /*initializer*/ undefined); typeElements.push(propertySignature); } } @@ -2744,8 +2740,8 @@ namespace ts { const returnType = getReturnTypeOfSignature(signature); returnTypeNode = returnType && typeToTypeNodeHelper(returnType, context); } - if(context.flags & NodeBuilderFlags.SuppressAnyReturnType) { - if(returnTypeNode && returnTypeNode.kind === SyntaxKind.AnyKeyword) { + if (context.flags & NodeBuilderFlags.SuppressAnyReturnType) { + if (returnTypeNode && returnTypeNode.kind === SyntaxKind.AnyKeyword) { returnTypeNode = undefined; } } From b8bb0c22f3261a28d05e3d3aaae15d652d9d6087 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 5 May 2017 14:47:57 -0700 Subject: [PATCH 31/83] emit type parameter's default --- src/compiler/emitter.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index eebbe30289..cd16074d57 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -814,6 +814,7 @@ namespace ts { function emitTypeParameter(node: TypeParameterDeclaration) { emit(node.name); emitWithPrefix(" extends ", node.constraint); + emitWithPrefix(" = ", node.default); } function emitParameter(node: ParameterDeclaration) { From a1d2049c29af925f3bc6d8ff09dee299d250edb2 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 5 May 2017 14:48:20 -0700 Subject: [PATCH 32/83] convert type format flags --- src/compiler/checker.ts | 49 +++++++++++++++++++++++++++++++++++++++-- src/compiler/types.ts | 2 +- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 18a6c03c6d..6496b191ea 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2242,10 +2242,49 @@ namespace ts { return result; } + function typeFormatFlagsToNodeBuilderFlags(flags: TypeFormatFlags): NodeBuilderFlags { + let result = NodeBuilderFlags.None; + if (flags & TypeFormatFlags.WriteArrayAsGenericType) { + result |= NodeBuilderFlags.WriteArrayAsGenericType; + } + if (flags & TypeFormatFlags.UseTypeOfFunction) { + result |= NodeBuilderFlags.UseTypeOfFunction; + } + if (flags & TypeFormatFlags.NoTruncation) { + result |= NodeBuilderFlags.NoTruncation; + } + if (flags & TypeFormatFlags.WriteArrowStyleSignature) { + result |= NodeBuilderFlags.WriteArrowStyleSignature; + } + if (flags & TypeFormatFlags.WriteOwnNameForAnyLike) { + result |= NodeBuilderFlags.WriteOwnNameForAnyLike; + } + if (flags & TypeFormatFlags.WriteArrayAsGenericType) { + result |= NodeBuilderFlags.WriteArrayAsGenericType; + } + if (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature) { + result |= NodeBuilderFlags.WriteTypeArgumentsOfSignature; + } + if (flags & TypeFormatFlags.UseFullyQualifiedType) { + result |= NodeBuilderFlags.UseFullyQualifiedType; + } + if (flags & TypeFormatFlags.UseTypeAliasValue) { + result |= NodeBuilderFlags.UseTypeAliasValue; + } + if (flags & TypeFormatFlags.SuppressAnyReturnType) { + result |= NodeBuilderFlags.SuppressAnyReturnType; + } + if (flags & TypeFormatFlags.AddUndefined) { + result |= NodeBuilderFlags.AddUndefined; + } + + return result; + } + function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { const str = oldTypeToString(type, enclosingDeclaration, flags); str; const str2 = oldTypeToString(type, enclosingDeclaration, flags); str2; - const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, NodeBuilderFlags.ignoreErrors); + const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, typeFormatFlagsToNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors, !!(flags & TypeFormatFlags.InTypeAlias)); Debug.assert(typeNode !== undefined, "should always get typenode?"); const newLine = NewLineKind.None; const options = { newLine, removeComments: true }; @@ -2264,8 +2303,9 @@ namespace ts { function createNodeBuilder() { return { - typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { + typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, inTypeAlias?: boolean) => { const context = createNodeBuilderContext(enclosingDeclaration, flags); + context.InTypeAlias = inTypeAlias; const resultingNode = typeToTypeNodeHelper(type, context); const result = context.encounteredError ? undefined : resultingNode; return result; @@ -2403,6 +2443,7 @@ namespace ts { if (type.flags & TypeFlags.TypeParameter) { const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, context); // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. + // TODO: add constraint here? return createTypeReferenceNode(name, /*typeArguments*/ undefined); } @@ -2585,6 +2626,10 @@ namespace ts { function typeReferenceToTypeNode(type: TypeReference) { const typeArguments: Type[] = type.typeArguments || emptyArray; if (type.target === globalArrayType) { + if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) { + const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context); + return createTypeReferenceNode("Array", [typeArgumentNode]); + } context.InElementType = true; const elementType = typeToTypeNodeHelper(typeArguments[0], context); context.InElementType = false; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 17df0243a1..48c4b2cd4a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2496,7 +2496,7 @@ namespace ts { /** Note that the resulting nodes cannot be checked. */ - typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode; + typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, inTypeAlias?: boolean): TypeNode; /** Note that the resulting nodes cannot be checked. */ signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration; /** Note that the resulting nodes cannot be checked. */ From 818bfdcd88c798e2b6141e9f1cfd8082d7b9d710 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 5 May 2017 15:08:02 -0700 Subject: [PATCH 33/83] accessibility check --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6496b191ea..5302f43bcc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2443,11 +2443,11 @@ namespace ts { if (type.flags & TypeFlags.TypeParameter) { const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, context); // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. - // TODO: add constraint here? return createTypeReferenceNode(name, /*typeArguments*/ undefined); } - if (!inTypeAlias && type.aliasSymbol) { + if (!inTypeAlias && type.aliasSymbol && + isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, context); const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, /*addInElementTypeFlag*/ false); return createTypeReferenceNode(name, typeArgumentNodes); From e43377db55ff23c43b773cce787cbe3195dfc316 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 5 May 2017 17:12:58 -0700 Subject: [PATCH 34/83] Better qualified name handling --- src/compiler/checker.ts | 42 +++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5302f43bcc..64adede088 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2278,7 +2278,7 @@ namespace ts { result |= NodeBuilderFlags.AddUndefined; } - return result; + return result; } function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { @@ -2325,7 +2325,7 @@ namespace ts { }; interface NodeBuilderContext { - readonly enclosingDeclaration: Node | undefined; + enclosingDeclaration: Node | undefined; readonly flags: NodeBuilderFlags | undefined; // State @@ -2382,7 +2382,7 @@ namespace ts { return createKeywordTypeNode(SyntaxKind.BooleanKeyword); } if (type.flags & TypeFlags.Enum) { - const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, context); + const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context); return createTypeReferenceNode(name, /*typeArguments*/ undefined); } if (type.flags & (TypeFlags.StringLiteral)) { @@ -2396,7 +2396,7 @@ namespace ts { } if (type.flags & TypeFlags.EnumLiteral) { const parentSymbol = getParentOfSymbol(type.symbol); - const parentName = symbolToName(parentSymbol, /*expectsIdentifier*/ false, context); + const parentName = symbolToName(parentSymbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context); const name = getNameOfSymbol(type.symbol, context); const enumLiteralName = createQualifiedName(parentName, name); return createTypeReferenceNode(enumLiteralName, /*typeArguments*/ undefined); @@ -2436,19 +2436,19 @@ namespace ts { } if (objectFlags & ObjectFlags.ClassOrInterface) { Debug.assert(!!(type.flags & TypeFlags.Object)); - const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, context); + const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context); // TODO(aozgaa): handle type arguments. return createTypeReferenceNode(name, /*typeArguments*/ undefined); } if (type.flags & TypeFlags.TypeParameter) { - const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, context); + const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context); // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. return createTypeReferenceNode(name, /*typeArguments*/ undefined); } if (!inTypeAlias && type.aliasSymbol && isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { - const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, context); + const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context); const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, /*addInElementTypeFlag*/ false); return createTypeReferenceNode(name, typeArgumentNodes); } @@ -2526,14 +2526,14 @@ namespace ts { if (symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) || symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) || shouldWriteTypeOfFunctionSymbol()) { - return createTypeQueryNodeFromSymbol(symbol); + return createTypeQueryNodeFromSymbol(symbol, SymbolFlags.Value); } else if (contains(context.symbolStack, symbol)) { // If type is an anonymous type literal in a type alias declaration, use type alias name const typeAlias = getTypeAliasForTypeLiteral(type); if (typeAlias) { // The specified symbol flags need to be reinterpreted as type flags - const entityName = symbolToName(typeAlias, /*expectsIdentifier*/ false, context); + const entityName = symbolToName(typeAlias, /*expectsIdentifier*/ false, SymbolFlags.Type, context); return createTypeReferenceNode(entityName, /*typeArguments*/ undefined); } else { @@ -2618,8 +2618,8 @@ namespace ts { return false; } - function createTypeQueryNodeFromSymbol(symbol: Symbol) { - const entityName = symbolToName(symbol, /*expectsIdentifier*/ false, context); + function createTypeQueryNodeFromSymbol(symbol: Symbol, symbolFlags: SymbolFlags) { + const entityName = symbolToName(symbol, /*expectsIdentifier*/ false, symbolFlags, context); return createTypeQueryNode(entityName); } @@ -2665,7 +2665,7 @@ namespace ts { // the default outer type arguments), we don't show the group. if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { // inFirstTypeArgument??? - const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true, context); + const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true, SymbolFlags.Type, context); if (!qualifiedName) { qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined); } @@ -2679,7 +2679,7 @@ namespace ts { } } let entityName: EntityName = undefined; - const nameIdentifier = symbolToName(type.symbol, /*expectsIdentifier*/ true, context); + const nameIdentifier = symbolToName(type.symbol, /*expectsIdentifier*/ true, SymbolFlags.Type, context); if (qualifiedName) { Debug.assert(!qualifiedName.right); qualifiedName.right = nameIdentifier; @@ -2717,7 +2717,10 @@ namespace ts { // TODO: make logic mirror that of writeObjectLiteralType for (const propertySymbol of properties) { const propertyType = getTypeOfSymbol(propertySymbol); - const propertyName = symbolToName(propertySymbol, /*expectsIdentifier*/ true, context); + const saveEnclosingDeclaration = context.enclosingDeclaration; + context.enclosingDeclaration = undefined; + const propertyName = symbolToName(propertySymbol, /*expectsIdentifier*/ true, SymbolFlags.Value, context); + context.enclosingDeclaration = saveEnclosingDeclaration; const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined; if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) { const signatures = getSignaturesOfType(propertyType, SignatureKind.Call); @@ -2767,7 +2770,6 @@ namespace ts { } function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind, context: NodeBuilderContext): SignatureDeclaration { - const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context)); const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter, context)); if (signature.thisParameter) { @@ -2801,7 +2803,7 @@ namespace ts { const constraintNode = constraint && typeToTypeNodeHelper(constraint, context); const defaultParameter = getDefaultFromTypeParameter(type); const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, context); - const name = symbolToName(type.symbol, /*expectsIdentifier*/ true, context); + const name = symbolToName(type.symbol, /*expectsIdentifier*/ true, SymbolFlags.Type, context); return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode); } @@ -2825,15 +2827,15 @@ namespace ts { // TODO: add meaning: SymbolFlags argument. // TODO: add SymbolFormatFlags?? Yes to add outer type parameters. Defer UseOnlyExternalAliasing until a separate symbolbuilder PR. - function symbolToName(symbol: Symbol, expectsIdentifier: true, context: NodeBuilderContext): Identifier; - function symbolToName(symbol: Symbol, expectsIdentifier: false, context: NodeBuilderContext): EntityName; - function symbolToName(symbol: Symbol, expectsIdentifier: boolean, context: NodeBuilderContext): EntityName { + function symbolToName(symbol: Symbol, expectsIdentifier: true, meaning: SymbolFlags, context: NodeBuilderContext): Identifier; + function symbolToName(symbol: Symbol, expectsIdentifier: false, meaning: SymbolFlags, context: NodeBuilderContext): EntityName; + function symbolToName(symbol: Symbol, expectsIdentifier: boolean, meaning: SymbolFlags, context: NodeBuilderContext): EntityName { // Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration. let chain: Symbol[]; const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter; if (!isTypeParameter && context.enclosingDeclaration) { - chain = getSymbolChain(symbol, SymbolFlags.None, /*endOfChain*/ true); + chain = getSymbolChain(symbol, meaning, /*endOfChain*/ true); Debug.assert(chain && chain.length > 0); } else { From 965b98f6cbaa7c23246a3bb59d5d707bd6b5164e Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 8 May 2017 11:10:47 -0700 Subject: [PATCH 35/83] `UseFullyQualifiedType` --- src/compiler/checker.ts | 2 +- src/compiler/types.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 64adede088..8a84fe4251 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2834,7 +2834,7 @@ namespace ts { // Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration. let chain: Symbol[]; const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter; - if (!isTypeParameter && context.enclosingDeclaration) { + if (!isTypeParameter && (context.enclosingDeclaration || context.flags & NodeBuilderFlags.UseFullyQualifiedType)) { chain = getSymbolChain(symbol, meaning, /*endOfChain*/ true); Debug.assert(chain && chain.length > 0); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 48c4b2cd4a..6c1861a589 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2571,7 +2571,6 @@ namespace ts { WriteOwnNameForAnyLike = 1 << 4, // Write symbol's own name instead of 'any' for any like types (eg. unknown, __resolving__ etc) // TODO WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature - // TODO UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type) // TODO UseTypeAliasValue = 1 << 7, // Serialize the type instead of using type-alias. This is needed when we emit declaration file. From b00aea5c7cb5ada80bce995a34bc83eb394e1dad Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 8 May 2017 11:45:02 -0700 Subject: [PATCH 36/83] Parameter improvements --- src/compiler/checker.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8a84fe4251..1fae8206f4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2812,16 +2812,26 @@ namespace ts { const parameterType = getTypeOfSymbol(parameterSymbol); const parameterTypeNode = typeToTypeNodeHelper(parameterType, context); const name = getDeepSynthesizedClone(parameterDeclaration.name); + + let questionToken: Token | undefined; + let initializer: Expression | undefined; + if (isOptionalParameter(parameterDeclaration)) { + questionToken = createToken(SyntaxKind.QuestionToken); + } + else { // TODO(aozgaa): In the future, check initializer accessibility. + initializer = parameterDeclaration.initializer; + } const parameterNode = createParameter( parameterDeclaration.decorators, parameterDeclaration.modifiers, - parameterDeclaration.dotDotDotToken && createToken(SyntaxKind.DotDotDotToken), - // Clone name to remove trivia. + (parameterDeclaration ? isRestParameter(parameterDeclaration) : isTransientSymbol(parameterSymbol) && parameterSymbol.isRestParameter) ? + createToken(SyntaxKind.DotDotDotToken) : + undefined, name, - parameterDeclaration.questionToken && createToken(SyntaxKind.QuestionToken), + questionToken, parameterTypeNode, - parameterDeclaration.initializer); + initializer); return parameterNode; } From d9b68e92138faea04316356875bca8e9630f0042 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 8 May 2017 16:26:57 -0700 Subject: [PATCH 37/83] Type Literal and Binding Name formatting --- src/compiler/checker.ts | 25 ++++++++++++++++++++++--- src/compiler/emitter.ts | 9 +++++---- src/compiler/types.ts | 2 ++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1fae8206f4..658bad82f8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2602,7 +2602,8 @@ namespace ts { context.inObjectTypeLiteral = true; const members = createTypeNodesFromResolvedType(resolved); context.inObjectTypeLiteral = saveInObjectTypeLiteral; - return createTypeLiteralNode(members); + const typeLiteralNode = createTypeLiteralNode(members); + return setEmitFlags(typeLiteralNode, EmitFlags.ToStringFormatting); } function shouldAddParenthesisAroundFunctionType(callSignature: Signature, context: NodeBuilderContext) { @@ -2811,8 +2812,14 @@ namespace ts { const parameterDeclaration = getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter); const parameterType = getTypeOfSymbol(parameterSymbol); const parameterTypeNode = typeToTypeNodeHelper(parameterType, context); - const name = getDeepSynthesizedClone(parameterDeclaration.name); - + let name: BindingName; + if (parameterDeclaration.name.kind === SyntaxKind.Identifier) { + name = getSynthesizedClone(parameterDeclaration.name); + } + else { + Debug.assert(parameterDeclaration.name.kind === SyntaxKind.ArrayBindingPattern || parameterDeclaration.name.kind === SyntaxKind.ObjectBindingPattern); + name = cloneBindingName(parameterDeclaration.name); + } let questionToken: Token | undefined; let initializer: Expression | undefined; if (isOptionalParameter(parameterDeclaration)) { @@ -2833,6 +2840,18 @@ namespace ts { parameterTypeNode, initializer); return parameterNode; + + function cloneBindingName(node: BindingName): BindingName { + return elideInitializerAndSetEmitFlags(node); + function elideInitializerAndSetEmitFlags(node: Node): Node { + const visited = visitEachChild(node, elideInitializerAndSetEmitFlags, nullTransformationContext, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags); + const clone = nodeIsSynthesized(visited) ? visited : getSynthesizedClone(visited); + if (clone.kind === SyntaxKind.BindingElement) { + (clone).initializer = undefined; + } + return setEmitFlags(clone, EmitFlags.ToStringFormatting); + } + } } // TODO: add meaning: SymbolFlags argument. diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index cd16074d57..70c9688b60 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -956,7 +956,7 @@ namespace ts { function emitTypeLiteral(node: TypeLiteralNode) { write("{"); if (node.members.length > 0) { - emitList(node, node.members, ListFormat.SingleLineTypeLiteralMembers); + emitList(node, node.members, getEmitFlags(node) & EmitFlags.ToStringFormatting ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers); } write("}"); } @@ -1037,7 +1037,7 @@ namespace ts { } else { write("{"); - emitList(node, elements, ListFormat.ObjectBindingPatternElements); + emitList(node, elements, getEmitFlags(node) & EmitFlags.ToStringFormatting ? ListFormat.ObjectBindingPatternElements : ListFormat.ObjectBindingPatternElementsWithSpaceBetweenBraces); write("}"); } } @@ -2948,13 +2948,14 @@ namespace ts { // Precomputed Formats Modifiers = SingleLine | SpaceBetweenSiblings, HeritageClauses = SingleLine | SpaceBetweenSiblings, - SingleLineTypeLiteralMembers = SingleLine | SpaceBetweenBraces | SpaceBetweenSiblings | Indented, // MultiLine | Indented, + SingleLineTypeLiteralMembers = SingleLine | SpaceBetweenBraces | SpaceBetweenSiblings | Indented, MultiLineTypeLiteralMembers = MultiLine | Indented, TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented, UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine, IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine, - ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings, + ObjectBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings, + ObjectBindingPatternElementsWithSpaceBetweenBraces = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings, ArrayBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings, ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces, ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | Indented | SquareBrackets, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6c1861a589..67b73cdbda 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3943,6 +3943,7 @@ namespace ts { } export const enum EmitFlags { + None = 0, SingleLine = 1 << 0, // The contents of this node should be emitted on a single line. AdviseOnEmitNode = 1 << 1, // The printer should invoke the onEmitNode callback when printing this node. NoSubstitution = 1 << 2, // Disables further substitution of an expression. @@ -3969,6 +3970,7 @@ namespace ts { NoHoisting = 1 << 20, // Do not hoist this declaration in --module system HasEndOfDeclarationMarker = 1 << 21, // Declaration has an associated NotEmittedStatement to mark the end of the declaration Iterator = 1 << 22, // The expression to a `yield*` should be treated as an Iterator when down-leveling, not an Iterable. + ToStringFormatting = 1 << 23 } export interface EmitHelper { From 51c76ac35128adba8a760fc08092e0035a1b5cd5 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 8 May 2017 18:17:17 -0700 Subject: [PATCH 38/83] fix malformed nodes --- src/compiler/checker.ts | 6 +++--- src/compiler/factory.ts | 4 ++++ src/compiler/utilities.ts | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 658bad82f8..9ac1dc2d61 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2752,7 +2752,7 @@ namespace ts { function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, context: NodeBuilderContext): IndexSignatureDeclaration { const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword); - const name = getNameFromIndexInfo(indexInfo); + const name = getNameFromIndexInfo(indexInfo) || "x"; const indexingParameter = createParameter( /*decorators*/ undefined, @@ -2830,8 +2830,8 @@ namespace ts { initializer = parameterDeclaration.initializer; } const parameterNode = createParameter( - parameterDeclaration.decorators, - parameterDeclaration.modifiers, + /*decorators*/ undefined, + cloneNodeArray(parameterDeclaration.modifiers), (parameterDeclaration ? isRestParameter(parameterDeclaration) : isTransientSymbol(parameterSymbol) && parameterSymbol.isRestParameter) ? createToken(SyntaxKind.DotDotDotToken) : undefined, diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 172710f39a..45b09892bb 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -89,6 +89,10 @@ namespace ts { return nodeIsSynthesized(clone) ? clone : getSynthesizedClone(clone); } + export function cloneNodeArray(nodeArray: NodeArray) { + return nodeArray && nodeArray.map(getDeepSynthesizedClone); + } + // Literals export function createLiteral(value: string): StringLiteral; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index cd63ebfb69..baa83697fb 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -466,7 +466,7 @@ namespace ts { return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name); } - export function getNameFromIndexInfo(info: IndexInfo) { + export function getNameFromIndexInfo(info: IndexInfo): string | undefined { return info.declaration ? declarationNameToString(info.declaration.parameters[0].name) : undefined; } From ac68e8d6f12ec81eda832d1f67ee6ff438e58cd8 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 9 May 2017 11:09:20 -0700 Subject: [PATCH 39/83] initializer issues --- src/compiler/checker.ts | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9ac1dc2d61..9410402d37 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2810,7 +2810,10 @@ namespace ts { function symbolToParameterDeclaration(parameterSymbol: Symbol, context: NodeBuilderContext): ParameterDeclaration { const parameterDeclaration = getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter); - const parameterType = getTypeOfSymbol(parameterSymbol); + let parameterType = getTypeOfSymbol(parameterSymbol); + if (isRequiredInitializedParameter(parameterDeclaration)) { + parameterType = includeFalsyTypes(parameterType, TypeFlags.Undefined); + } const parameterTypeNode = typeToTypeNodeHelper(parameterType, context); let name: BindingName; if (parameterDeclaration.name.kind === SyntaxKind.Identifier) { @@ -2820,25 +2823,19 @@ namespace ts { Debug.assert(parameterDeclaration.name.kind === SyntaxKind.ArrayBindingPattern || parameterDeclaration.name.kind === SyntaxKind.ObjectBindingPattern); name = cloneBindingName(parameterDeclaration.name); } - let questionToken: Token | undefined; - let initializer: Expression | undefined; - if (isOptionalParameter(parameterDeclaration)) { - questionToken = createToken(SyntaxKind.QuestionToken); - } - else { - // TODO(aozgaa): In the future, check initializer accessibility. - initializer = parameterDeclaration.initializer; - } + const questionToken = isOptionalParameter(parameterDeclaration) ? createToken(SyntaxKind.QuestionToken) : undefined; + const dotDotDotToken = (parameterDeclaration ? isRestParameter(parameterDeclaration) : isTransientSymbol(parameterSymbol) && parameterSymbol.isRestParameter) ? + createToken(SyntaxKind.DotDotDotToken) : + undefined; + const parameterNode = createParameter( /*decorators*/ undefined, cloneNodeArray(parameterDeclaration.modifiers), - (parameterDeclaration ? isRestParameter(parameterDeclaration) : isTransientSymbol(parameterSymbol) && parameterSymbol.isRestParameter) ? - createToken(SyntaxKind.DotDotDotToken) : - undefined, + dotDotDotToken, name, questionToken, parameterTypeNode, - initializer); + /*initializer*/ undefined); return parameterNode; function cloneBindingName(node: BindingName): BindingName { From e0438db63eaadddf6cf1f8822fb588d4f26eaaff Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 9 May 2017 12:57:22 -0700 Subject: [PATCH 40/83] Parenthesize function types --- src/compiler/checker.ts | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9410402d37..439874cf98 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2359,6 +2359,8 @@ namespace ts { context.InElementType = false; const inTypeAlias = context.InTypeAlias; context.InTypeAlias = false; + const inFirstTypeArgument = context.InFirstTypeArgument; + context.InFirstTypeArgument = false; // TODO: should be assert? if (!type) { @@ -2367,8 +2369,6 @@ namespace ts { return undefined; } - - if (type.flags & TypeFlags.Any) { return createKeywordTypeNode(SyntaxKind.AnyKeyword); } @@ -2586,15 +2586,18 @@ namespace ts { if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { const signature = resolved.callSignatures[0]; - const functionTypeNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context); + const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context); return shouldAddParenthesisAroundFunctionType(signature, context) ? - createParenthesizedTypeNode(functionTypeNode) : - functionTypeNode; + createParenthesizedTypeNode(signatureNode) : + signatureNode; } if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { const signature = resolved.constructSignatures[0]; - return signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, context); + const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, context); + return shouldAddParenthesisAroundFunctionType(signature, context) ? + createParenthesizedTypeNode(signatureNode) : + signatureNode; } } @@ -2610,7 +2613,7 @@ namespace ts { if (InElementType) { return true; } - else if (context.InFirstTypeArgument) { + else if (inFirstTypeArgument) { // Add parenthesis around function type for the first type argument to avoid ambiguity const typeParameters = callSignature.target && (context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature) ? callSignature.target.typeParameters : callSignature.typeParameters; @@ -2690,7 +2693,14 @@ namespace ts { entityName = nameIdentifier; } const typeParameterCount = (type.target.typeParameters || emptyArray).length; - const typeArgumentNodes = some(typeArguments) ? mapToTypeNodeArray(typeArguments.slice(i, typeParameterCount - i), /*addInElementTypeFlag*/ false) : undefined; + + let typeArgumentNodes: TypeNode[] | undefined; + if (some(typeArguments)) { + const slice = typeArguments.slice(i, typeParameterCount - i); + context.InFirstTypeArgument = true; + typeArgumentNodes = mapToTypeNodeArray(slice, /*addInElementTypeFlag*/ false); + } + return createTypeReferenceNode(entityName, typeArgumentNodes); } } @@ -2851,7 +2861,6 @@ namespace ts { } } - // TODO: add meaning: SymbolFlags argument. // TODO: add SymbolFormatFlags?? Yes to add outer type parameters. Defer UseOnlyExternalAliasing until a separate symbolbuilder PR. function symbolToName(symbol: Symbol, expectsIdentifier: true, meaning: SymbolFlags, context: NodeBuilderContext): Identifier; function symbolToName(symbol: Symbol, expectsIdentifier: false, meaning: SymbolFlags, context: NodeBuilderContext): EntityName; From 89f8cca488361b8385861792f13b87606802fbb8 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 9 May 2017 13:14:39 -0700 Subject: [PATCH 41/83] mapped type indent --- src/compiler/checker.ts | 3 ++- src/compiler/emitter.ts | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 439874cf98..f06afe4425 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2516,7 +2516,8 @@ namespace ts { const readonlyToken = type.declaration && type.declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined; const questionToken = type.declaration && type.declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined; - return createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode); + const mappedTypeNode = createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode); + return setEmitFlags(mappedTypeNode, EmitFlags.SingleLine); } function createAnonymousTypeNode(type: ObjectType): TypeNode { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 70c9688b60..11cc83dc15 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1004,9 +1004,15 @@ namespace ts { } function emitMappedType(node: MappedTypeNode) { + const emitFlags = getEmitFlags(node); write("{"); - writeLine(); - increaseIndent(); + if (emitFlags & EmitFlags.SingleLine) { + write(" "); + } + else { + writeLine(); + increaseIndent(); + } writeIfPresent(node.readonlyToken, "readonly "); write("["); emit(node.typeParameter.name); @@ -1017,8 +1023,13 @@ namespace ts { write(": "); emit(node.type); write(";"); - writeLine(); - decreaseIndent(); + if (emitFlags & EmitFlags.SingleLine) { + write(" "); + } + else { + writeLine(); + decreaseIndent(); + } write("}"); } From ad58572edbcd761623a918851e9afa36a733a455 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 9 May 2017 13:50:14 -0700 Subject: [PATCH 42/83] trailing comma --- src/compiler/emitter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 11cc83dc15..582bc6ed7a 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2965,7 +2965,7 @@ namespace ts { TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented, UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine, IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine, - ObjectBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings, + ObjectBindingPatternElements = SingleLine | CommaDelimited | SpaceBetweenSiblings, ObjectBindingPatternElementsWithSpaceBetweenBraces = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings, ArrayBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings, ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces, From 41452a5b2199e17ceb440784a06fd18e60220d8d Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 9 May 2017 18:20:46 -0700 Subject: [PATCH 43/83] add typeArguments to identifier --- src/compiler/checker.ts | 59 ++++++++++++++++++++-------------------- src/compiler/emitter.ts | 1 + src/compiler/factory.ts | 9 +++++- src/compiler/types.ts | 1 + src/compiler/visitor.ts | 3 ++ src/services/services.ts | 1 + 6 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f06afe4425..82567bc170 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2449,13 +2449,13 @@ namespace ts { if (!inTypeAlias && type.aliasSymbol && isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context); - const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, /*addInElementTypeFlag*/ false); + const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true); return createTypeReferenceNode(name, typeArgumentNodes); } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { const types = type.flags & TypeFlags.Union ? formatUnionTypes((type).types) : (type).types; - const typeNodes = types && mapToTypeNodeArray(types, /*addInElementTypeFlag*/ true); + const typeNodes = types && mapToTypeNodeArray(types, context, /*addInElementTypeFlag*/ true, /*addInFirstTypeArgumentFlag*/ false); if (typeNodes && typeNodes.length > 0) { const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes); return InElementType ? createParenthesizedTypeNode(unionOrIntersectionTypeNode) : unionOrIntersectionTypeNode; @@ -2492,20 +2492,6 @@ namespace ts { Debug.fail("Should be unreachable."); - function mapToTypeNodeArray(types: Type[], addInElementTypeFlag: boolean): TypeNode[] { - const result = []; - Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper"); - for (const type of types) { - context.InElementType = addInElementTypeFlag; - const typeNode = typeToTypeNodeHelper(type, context); - if (typeNode) { - result.push(typeNode); - } - } - Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper"); - return result; - } - function createMappedTypeNodeFromType(type: MappedType) { Debug.assert(!!(type.flags & TypeFlags.Object)); const typeParameter = getTypeParameterFromMappedType(type); @@ -2642,7 +2628,7 @@ namespace ts { } else if (type.target.objectFlags & ObjectFlags.Tuple) { if (typeArguments.length > 0) { - const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)), /*addInElementTypeFlag*/ false); + const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)), context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ false); if (tupleConstituentNodes && tupleConstituentNodes.length > 0) { return createTupleTypeNode(tupleConstituentNodes); } @@ -2669,8 +2655,11 @@ namespace ts { // When type parameters are their own type arguments for the whole group (i.e. we have // the default outer type arguments), we don't show the group. if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { - // inFirstTypeArgument??? + const qualifiedNamePartTypeArguments = typeArguments.slice(start,i); + const qualifiedNamePartTypeArgumentNodes = qualifiedNamePartTypeArguments && createNodeArray(mapToTypeNodeArray(qualifiedNamePartTypeArguments, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true)); const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true, SymbolFlags.Type, context); + qualifiedNamePart.typeArguments = qualifiedNamePartTypeArgumentNodes; + if (!qualifiedName) { qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined); } @@ -2699,7 +2688,7 @@ namespace ts { if (some(typeArguments)) { const slice = typeArguments.slice(i, typeParameterCount - i); context.InFirstTypeArgument = true; - typeArgumentNodes = mapToTypeNodeArray(slice, /*addInElementTypeFlag*/ false); + typeArgumentNodes = mapToTypeNodeArray(slice, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true); } return createTypeReferenceNode(entityName, typeArgumentNodes); @@ -2761,6 +2750,24 @@ namespace ts { } } + function mapToTypeNodeArray(types: Type[], context: NodeBuilderContext, addInElementTypeFlag: boolean, addInFirstTypeArgumentFlag: boolean): TypeNode[] { + const result = []; + Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper"); + for (let i = 0; i < types.length; ++i) { + let type = types[i] + context.InElementType = addInElementTypeFlag; + if (i === 0) { + context.InFirstTypeArgument = addInFirstTypeArgumentFlag; + } + const typeNode = typeToTypeNodeHelper(type, context); + if (typeNode) { + result.push(typeNode); + } + } + Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper"); + return result; + } + function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, context: NodeBuilderContext): IndexSignatureDeclaration { const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword); const name = getNameFromIndexInfo(indexInfo) || "x"; @@ -2889,9 +2896,8 @@ namespace ts { Debug.assert(chain && 0 <= index && index < chain.length); // const parentIndex = index - 1; const symbol = chain[index]; - let typeParameterString = ""; + let typeParameterNodes: TypeNode[] | undefined; if (index > 0) { - const parentSymbol = chain[index - 1]; let typeParameters: TypeParameter[]; if (getCheckFlags(symbol) & CheckFlags.Instantiated) { @@ -2907,17 +2913,12 @@ namespace ts { if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowTypeParameterInQualifiedName)) { context.encounteredError = true; } - const writer = getSingleLineStringWriter(); - const displayBuilder = getSymbolDisplayBuilder(); - displayBuilder.buildDisplayForTypeParametersAndDelimiters(typeParameters, writer, context.enclosingDeclaration, 0); - typeParameterString = writer.string(); - releaseStringWriter(writer); - + typeParameterNodes = typeParameters && mapToTypeNodeArray(typeParameters, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true); } } + const symbolName = getNameOfSymbol(symbol, context); - const symbolNameWithTypeParameters = typeParameterString.length > 0 ? `${symbolName}<${typeParameterString}>` : symbolName; - const identifier = createIdentifier(symbolNameWithTypeParameters); + const identifier = createIdentifier(symbolName, typeParameterNodes); return index > 0 ? createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 582bc6ed7a..b96e87ec55 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -780,6 +780,7 @@ namespace ts { function emitIdentifier(node: Identifier) { write(getTextOfNode(node, /*includeTrivia*/ false)); + emitTypeArguments(node, node.typeArguments); } // diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 45b09892bb..510e4ec03d 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -136,15 +136,22 @@ namespace ts { // Identifiers - export function createIdentifier(text: string): Identifier { + export function createIdentifier(text: string, typeArguments?: TypeNode[]): Identifier { const node = createSynthesizedNode(SyntaxKind.Identifier); node.text = escapeIdentifier(text); node.originalKeywordKind = text ? stringToToken(text) : SyntaxKind.Unknown; node.autoGenerateKind = GeneratedIdentifierKind.None; node.autoGenerateId = 0; + node.typeArguments = asNodeArray(typeArguments); return node; } + export function updateIdentifier(node: Identifier, typeArguments: NodeArray | undefined): Identifier { + return node.typeArguments !== typeArguments + ? updateNode(createIdentifier(node.text, typeArguments), node) + : node; + } + let nextAutoGenerateId = 0; /** Create a unique temporary variable. */ diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 67b73cdbda..ad89069c28 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -575,6 +575,7 @@ namespace ts { /*@internal*/ autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier. /*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name. isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace + /*@internal*/ typeArguments: NodeArray; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics. } // Transient identifier node (marked by id === -1) diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 1e196a925f..fce43b622b 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -219,6 +219,9 @@ namespace ts { } switch (node.kind) { + case SyntaxKind.Identifier: + return updateIdentifier(node, nodesVisitor((node).typeArguments, visitor, isTypeNode)); + case SyntaxKind.SemicolonClassElement: case SyntaxKind.EmptyStatement: case SyntaxKind.OmittedExpression: diff --git a/src/services/services.ts b/src/services/services.ts index 8f2cbb2237..faf27f4f2b 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -357,6 +357,7 @@ namespace ts { _incrementExpressionBrand: any; _unaryExpressionBrand: any; _expressionBrand: any; + typeArguments: any; constructor(_kind: SyntaxKind.Identifier, pos: number, end: number) { super(pos, end); } From ac6018aa955147838aacbdce9c4d0604a9b634be Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Wed, 10 May 2017 17:01:05 -0700 Subject: [PATCH 44/83] type arguments in qualified names --- src/compiler/checker.ts | 74 ++++++++++++++++++++++++++++++----------- src/compiler/types.ts | 12 +++---- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 82567bc170..ed5c7ea669 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2448,9 +2448,10 @@ namespace ts { if (!inTypeAlias && type.aliasSymbol && isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { - const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context); - const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true); + const name = symbolToTypeReferenceName(type.aliasSymbol); + const typeArgumentNodes = toTypeArgumentNodes(type.aliasTypeArguments, context); return createTypeReferenceNode(name, typeArgumentNodes); + // return symbolToTypeReferenceIdentifier(type.aliasSymbol, type.aliasTypeArguments); } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { @@ -2614,6 +2615,13 @@ namespace ts { return createTypeQueryNode(entityName); } + function symbolToTypeReferenceName(symbol: Symbol) { + // Unnamed function expressions and arrow functions have reserved names that we don't want to display + const entityName = symbol.flags & SymbolFlags.Class || !isReservedMemberName(symbol.name) ? symbolToName(symbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context) : createIdentifier(""); + // TODO: assert no type args? + return entityName; + } + function typeReferenceToTypeNode(type: TypeReference) { const typeArguments: Type[] = type.typeArguments || emptyArray; if (type.target === globalArrayType) { @@ -2641,7 +2649,7 @@ namespace ts { else { const outerTypeParameters = type.target.outerTypeParameters; let i = 0; - let qualifiedName: QualifiedName | undefined = undefined; + let qualifiedName: QualifiedName | undefined; if (outerTypeParameters) { let inFirstTypeArgument = true; const length = outerTypeParameters.length; @@ -2655,46 +2663,68 @@ namespace ts { // When type parameters are their own type arguments for the whole group (i.e. we have // the default outer type arguments), we don't show the group. if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { - const qualifiedNamePartTypeArguments = typeArguments.slice(start,i); - const qualifiedNamePartTypeArgumentNodes = qualifiedNamePartTypeArguments && createNodeArray(mapToTypeNodeArray(qualifiedNamePartTypeArguments, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true)); - const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true, SymbolFlags.Type, context); - qualifiedNamePart.typeArguments = qualifiedNamePartTypeArgumentNodes; + const typeArgumentNodes = createNodeArray(toTypeArgumentNodes(typeArguments.slice(start, i), context)); + const namePart = symbolToTypeReferenceName(parent); + (namePart.kind === SyntaxKind.Identifier ? namePart : namePart.right).typeArguments = typeArgumentNodes; - if (!qualifiedName) { - qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined); + if (qualifiedName) { + Debug.assert(!qualifiedName.right); + qualifiedName = addToQualifiedNameMissingRightIdentifier(qualifiedName, namePart); + qualifiedName = createQualifiedName(qualifiedName, /*right*/ undefined); } else { - Debug.assert(!qualifiedName.right); - qualifiedName.right = qualifiedNamePart; - qualifiedName = createQualifiedName(qualifiedName, /*right*/ undefined); + qualifiedName = createQualifiedName(namePart, /*right*/ undefined); } } inFirstTypeArgument = false; } } + let entityName: EntityName = undefined; - const nameIdentifier = symbolToName(type.symbol, /*expectsIdentifier*/ true, SymbolFlags.Type, context); + const nameIdentifier = symbolToTypeReferenceName(type.symbol); if (qualifiedName) { Debug.assert(!qualifiedName.right); - qualifiedName.right = nameIdentifier; + qualifiedName = addToQualifiedNameMissingRightIdentifier(qualifiedName, nameIdentifier); entityName = qualifiedName; } else { entityName = nameIdentifier; } - const typeParameterCount = (type.target.typeParameters || emptyArray).length; let typeArgumentNodes: TypeNode[] | undefined; if (some(typeArguments)) { - const slice = typeArguments.slice(i, typeParameterCount - i); - context.InFirstTypeArgument = true; - typeArgumentNodes = mapToTypeNodeArray(slice, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true); + const typeParameterCount = (type.target.typeParameters || emptyArray).length; + const slice = typeArguments && typeArguments.slice(i, typeParameterCount); + typeArgumentNodes = toTypeArgumentNodes(slice, context); + } + + if (typeArgumentNodes) { + const lastIdentifier = entityName.kind === SyntaxKind.Identifier ? entityName : entityName.right; + lastIdentifier.typeArguments = undefined; } return createTypeReferenceNode(entityName, typeArgumentNodes); } } + function addToQualifiedNameMissingRightIdentifier(left: QualifiedName, right: Identifier | QualifiedName) { + Debug.assert(left.right === undefined); + + if (right.kind === SyntaxKind.Identifier) { + left.right = right; + return left; + } + + let rightPart = right; + while (rightPart.left.kind !== SyntaxKind.Identifier) { + rightPart = rightPart.left; + } + + left.right = rightPart.left; + rightPart.left = left; + return right; + } + function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] { const typeElements: TypeElement[] = []; for (const signature of resolvedType.callSignatures) { @@ -2754,7 +2784,7 @@ namespace ts { const result = []; Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper"); for (let i = 0; i < types.length; ++i) { - let type = types[i] + const type = types[i]; context.InElementType = addInElementTypeFlag; if (i === 0) { context.InFirstTypeArgument = addInFirstTypeArgumentFlag; @@ -2768,6 +2798,10 @@ namespace ts { return result; } + function toTypeArgumentNodes(typeArguments: Type[], context: NodeBuilderContext) { + return typeArguments && mapToTypeNodeArray(typeArguments, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true); + } + function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, context: NodeBuilderContext): IndexSignatureDeclaration { const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword); const name = getNameFromIndexInfo(indexInfo) || "x"; @@ -2913,7 +2947,7 @@ namespace ts { if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowTypeParameterInQualifiedName)) { context.encounteredError = true; } - typeParameterNodes = typeParameters && mapToTypeNodeArray(typeParameters, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true); + typeParameterNodes = toTypeArgumentNodes(typeParameters, context); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ad89069c28..73d6067cb1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -570,12 +570,12 @@ namespace ts { export interface Identifier extends PrimaryExpression { kind: SyntaxKind.Identifier; - text: string; // Text of identifier (with escapes converted to characters) - originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later - /*@internal*/ autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier. - /*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name. - isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace - /*@internal*/ typeArguments: NodeArray; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics. + text: string; // Text of identifier (with escapes converted to characters) + originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later + /*@internal*/ autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier. + /*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name. + isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace + /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics. } // Transient identifier node (marked by id === -1) From d5f34da9dd913c201ba00c44b50806b2ca1a0261 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 11 May 2017 14:07:33 -0700 Subject: [PATCH 45/83] Accept baselines and update test --- tests/baselines/reference/escapedIdentifiers.types | 2 +- .../reference/unicodeExtendedEscapesInStrings06_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings06_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings08_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings08_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings09_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings09_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings10_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings10_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings11_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings11_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings13_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings13_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings15_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings15_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings16_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings16_ES6.types | 2 +- .../fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/baselines/reference/escapedIdentifiers.types b/tests/baselines/reference/escapedIdentifiers.types index 6d48bb3392..ef6c0983d3 100644 --- a/tests/baselines/reference/escapedIdentifiers.types +++ b/tests/baselines/reference/escapedIdentifiers.types @@ -220,7 +220,7 @@ class testClass { >testClass : testClass public func(arg1: number, arg\u0032: string, arg\u0033: boolean, arg4: number) { ->func : (arg1: number, arg\u0032: string, arg\u0033: boolean, arg4: number) => void +>func : (arg1: number, arg2: string, arg3: boolean, arg4: number) => void >arg1 : number >arg\u0032 : string >arg\u0033 : boolean diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES5.types index 0c742aaf7b..e6942df5d1 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES5.types @@ -3,5 +3,5 @@ // 1. Assert: 0 ≤ cp ≤ 0x10FFFF. var x = "\u{10FFFF}"; >x : string ->"\u{10FFFF}" : "􏿿" +>"\u{10FFFF}" : "\uDBFF\uDFFF" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES6.types index 6b98c0c98a..82cc1fa622 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES6.types @@ -3,5 +3,5 @@ // 1. Assert: 0 ≤ cp ≤ 0x10FFFF. var x = "\u{10FFFF}"; >x : string ->"\u{10FFFF}" : "􏿿" +>"\u{10FFFF}" : "\uDBFF\uDFFF" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES5.types index 0007b75881..9c316cca31 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES5.types @@ -4,5 +4,5 @@ // (FFFF == 65535) var x = "\u{FFFF}"; >x : string ->"\u{FFFF}" : "￿" +>"\u{FFFF}" : "\uFFFF" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES6.types index aedd2f72ef..a5982a77c6 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES6.types @@ -4,5 +4,5 @@ // (FFFF == 65535) var x = "\u{FFFF}"; >x : string ->"\u{FFFF}" : "￿" +>"\u{FFFF}" : "\uFFFF" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES5.types index daf8a776e8..7508721f14 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES5.types @@ -4,5 +4,5 @@ // (10000 == 65536) var x = "\u{10000}"; >x : string ->"\u{10000}" : "𐀀" +>"\u{10000}" : "\uD800\uDC00" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES6.types index 0963f552c9..5f05276ed3 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES6.types @@ -4,5 +4,5 @@ // (10000 == 65536) var x = "\u{10000}"; >x : string ->"\u{10000}" : "𐀀" +>"\u{10000}" : "\uD800\uDC00" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES5.types index a4977300e6..a5422cc7a9 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES5.types @@ -5,5 +5,5 @@ // this is a useful edge-case test. var x = "\u{D800}"; >x : string ->"\u{D800}" : "�" +>"\u{D800}" : "\uD800" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES6.types index 6d6d0112f0..2fcdd0547e 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES6.types @@ -5,5 +5,5 @@ // this is a useful edge-case test. var x = "\u{D800}"; >x : string ->"\u{D800}" : "�" +>"\u{D800}" : "\uD800" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES5.types index 74e6817c85..b26387baae 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES5.types @@ -5,5 +5,5 @@ // this is a useful edge-case test. var x = "\u{DC00}"; >x : string ->"\u{DC00}" : "�" +>"\u{DC00}" : "\uDC00" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES6.types index c1b3f372da..cd01052999 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES6.types @@ -5,5 +5,5 @@ // this is a useful edge-case test. var x = "\u{DC00}"; >x : string ->"\u{DC00}" : "�" +>"\u{DC00}" : "\uDC00" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES5.types index 224e81adec..68eb2fe8de 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES5.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings13_ES5.ts === var x = "\u{DDDDD}"; >x : string ->"\u{DDDDD}" : "󝷝" +>"\u{DDDDD}" : "\uDB37\uDDDD" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES6.types index e69b2af435..4ad8d2e3f3 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES6.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings13_ES6.ts === var x = "\u{DDDDD}"; >x : string ->"\u{DDDDD}" : "󝷝" +>"\u{DDDDD}" : "\uDB37\uDDDD" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES5.types index 1973bb3790..8da5611518 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES5.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings15_ES5.ts === var x = "\u{abcd}\u{ef12}\u{3456}\u{7890}"; >x : string ->"\u{abcd}\u{ef12}\u{3456}\u{7890}" : "ꯍ㑖碐" +>"\u{abcd}\u{ef12}\u{3456}\u{7890}" : "\uABCD\uEF12\u3456\u7890" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES6.types index 16ae5177f5..613d91afae 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES6.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings15_ES6.ts === var x = "\u{abcd}\u{ef12}\u{3456}\u{7890}"; >x : string ->"\u{abcd}\u{ef12}\u{3456}\u{7890}" : "ꯍ㑖碐" +>"\u{abcd}\u{ef12}\u{3456}\u{7890}" : "\uABCD\uEF12\u3456\u7890" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES5.types index 1ae9d9ef3d..1b29651e2d 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES5.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings16_ES5.ts === var x = "\u{ABCD}\u{EF12}\u{3456}\u{7890}"; >x : string ->"\u{ABCD}\u{EF12}\u{3456}\u{7890}" : "ꯍ㑖碐" +>"\u{ABCD}\u{EF12}\u{3456}\u{7890}" : "\uABCD\uEF12\u3456\u7890" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES6.types index a4abc5bdea..addf7dedff 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES6.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings16_ES6.ts === var x = "\u{ABCD}\u{EF12}\u{3456}\u{7890}"; >x : string ->"\u{ABCD}\u{EF12}\u{3456}\u{7890}" : "ꯍ㑖碐" +>"\u{ABCD}\u{EF12}\u{3456}\u{7890}" : "\uABCD\uEF12\u3456\u7890" diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts index eab4c80c78..f7dfd5e178 100644 --- a/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts @@ -5,7 +5,7 @@ //// class C implements I {[| |]} verify.rangeAfterCodeFix(` - test(a: MyType): void { + test(a: [string, number]): void { throw new Error("Method not implemented."); } `); From a5e93c427ba9f1987b8b84f31a20deb1af5bf35e Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 11 May 2017 16:40:14 -0700 Subject: [PATCH 46/83] remove souceFile checks --- src/compiler/checker.ts | 4 ++-- src/compiler/emitter.ts | 17 +++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ed5c7ea669..2e45a17a20 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2289,9 +2289,9 @@ namespace ts { const newLine = NewLineKind.None; const options = { newLine, removeComments: true }; const writer = createTextWriter(""); - // writer.writeLine = noop; const printer = createPrinter(options, writer); - printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ undefined, writer); + const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); + printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer); const result = writer.getText(); const maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index b96e87ec55..073c49df55 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -153,7 +153,7 @@ namespace ts { for (let i = 0; i < numNodes; i++) { const currentNode = bundle ? bundle.sourceFiles[i] : node; const sourceFile = isSourceFile(currentNode) ? currentNode : currentSourceFile; - const shouldSkip = compilerOptions.noEmitHelpers || (sourceFile && getExternalHelpersModuleName(sourceFile) !== undefined); + const shouldSkip = compilerOptions.noEmitHelpers || getExternalHelpersModuleName(sourceFile) !== undefined; const shouldBundle = isSourceFile(currentNode) && !isOwnFileEmit; const helpers = getEmitHelpers(currentNode); if (helpers) { @@ -234,6 +234,11 @@ namespace ts { writeBundle }; + /** + * If `sourceFile` is `undefined`, `node` must be a synthesized `TypeNode`. + */ + function printNode(hint: EmitHint, node: TypeNode, sourceFile: undefined): string; + function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string; function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined): string { switch (hint) { case EmitHint.SourceFile: @@ -1112,7 +1117,7 @@ namespace ts { function emitPropertyAccessExpression(node: PropertyAccessExpression) { let indentBeforeDot = false; let indentAfterDot = false; - if (currentSourceFile && !(getEmitFlags(node) & EmitFlags.NoIndentation)) { + if (!(getEmitFlags(node) & EmitFlags.NoIndentation)) { const dotRangeStart = node.expression.end; const dotRangeEnd = skipTrivia(currentSourceFile.text, node.expression.end) + 1; const dotToken = { kind: SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd }; @@ -2520,7 +2525,7 @@ namespace ts { const firstChild = children[0]; if (firstChild === undefined) { - return !(currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile)); + return !(rangeIsOnSingleLine(parentNode, currentSourceFile)); } else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(firstChild)) { return synthesizedNodeStartsOnNewLine(firstChild, format); @@ -2546,7 +2551,7 @@ namespace ts { return synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format); } else { - return !(currentSourceFile && rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile)); + return !(rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile)); } } else { @@ -2565,13 +2570,13 @@ namespace ts { const lastChild = lastOrUndefined(children); if (lastChild === undefined) { - return !(currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile)); + return !(rangeIsOnSingleLine(parentNode, currentSourceFile)); } else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(lastChild)) { return synthesizedNodeStartsOnNewLine(lastChild, format); } else { - return !(currentSourceFile && rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile)); + return !(rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile)); } } else { From 82109d3d1c1f4d31bad310521e5375875e2db4e0 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 11 May 2017 17:39:27 -0700 Subject: [PATCH 47/83] cleanup --- src/compiler/checker.ts | 61 ++++++++++++----------------------------- 1 file changed, 17 insertions(+), 44 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2e45a17a20..f6930b01ac 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2229,19 +2229,7 @@ namespace ts { return result; } - function oldTypeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { - const writer = getSingleLineStringWriter(); - getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); - let result = writer.string(); - releaseStringWriter(writer); - - const maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100; - if (maxLength && result.length >= maxLength) { - result = result.substr(0, maxLength - "...".length) + "..."; - } - return result; - } - + function typeFormatFlagsToNodeBuilderFlags(flags: TypeFormatFlags): NodeBuilderFlags { let result = NodeBuilderFlags.None; if (flags & TypeFormatFlags.WriteArrayAsGenericType) { @@ -2282,8 +2270,6 @@ namespace ts { } function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { - const str = oldTypeToString(type, enclosingDeclaration, flags); str; - const str2 = oldTypeToString(type, enclosingDeclaration, flags); str2; const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, typeFormatFlagsToNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors, !!(flags & TypeFormatFlags.InTypeAlias)); Debug.assert(typeNode !== undefined, "should always get typenode?"); const newLine = NewLineKind.None; @@ -2331,11 +2317,8 @@ namespace ts { // State encounteredError: boolean; inObjectTypeLiteral: boolean; - // TODO: needed for part of parens handling InElementType: boolean; // Writing an array or union element type - // TODO: ??? - InFirstTypeArgument: boolean; // Writing first type argument of the instantiated type - // TODO: ??? + InFirstTypeArgument: boolean; // Writing first type argument of the instantiated type InTypeAlias: boolean; // Writing type in type alias declaration symbolStack: Symbol[] | undefined; } @@ -2354,18 +2337,15 @@ namespace ts { } function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { - const InElementType = context.InElementType; - // TODO: why doesn't tts unset the flag? + const inElementType = context.InElementType; context.InElementType = false; const inTypeAlias = context.InTypeAlias; context.InTypeAlias = false; const inFirstTypeArgument = context.InFirstTypeArgument; context.InFirstTypeArgument = false; - // TODO: should be assert? if (!type) { context.encounteredError = true; - // TODO(aozgaa): should we return implict any (undefined) or explicit any (keywordtypenode)? return undefined; } @@ -2382,7 +2362,7 @@ namespace ts { return createKeywordTypeNode(SyntaxKind.BooleanKeyword); } if (type.flags & TypeFlags.Enum) { - const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context); + const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false); return createTypeReferenceNode(name, /*typeArguments*/ undefined); } if (type.flags & (TypeFlags.StringLiteral)) { @@ -2396,7 +2376,7 @@ namespace ts { } if (type.flags & TypeFlags.EnumLiteral) { const parentSymbol = getParentOfSymbol(type.symbol); - const parentName = symbolToName(parentSymbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context); + const parentName = symbolToName(parentSymbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false); const name = getNameOfSymbol(type.symbol, context); const enumLiteralName = createQualifiedName(parentName, name); return createTypeReferenceNode(enumLiteralName, /*typeArguments*/ undefined); @@ -2436,12 +2416,11 @@ namespace ts { } if (objectFlags & ObjectFlags.ClassOrInterface) { Debug.assert(!!(type.flags & TypeFlags.Object)); - const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context); - // TODO(aozgaa): handle type arguments. + const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false); return createTypeReferenceNode(name, /*typeArguments*/ undefined); } if (type.flags & TypeFlags.TypeParameter) { - const name = symbolToName(type.symbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context); + const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false); // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. return createTypeReferenceNode(name, /*typeArguments*/ undefined); } @@ -2451,7 +2430,6 @@ namespace ts { const name = symbolToTypeReferenceName(type.aliasSymbol); const typeArgumentNodes = toTypeArgumentNodes(type.aliasTypeArguments, context); return createTypeReferenceNode(name, typeArgumentNodes); - // return symbolToTypeReferenceIdentifier(type.aliasSymbol, type.aliasTypeArguments); } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { @@ -2459,7 +2437,7 @@ namespace ts { const typeNodes = types && mapToTypeNodeArray(types, context, /*addInElementTypeFlag*/ true, /*addInFirstTypeArgumentFlag*/ false); if (typeNodes && typeNodes.length > 0) { const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes); - return InElementType ? createParenthesizedTypeNode(unionOrIntersectionTypeNode) : unionOrIntersectionTypeNode; + return inElementType ? createParenthesizedTypeNode(unionOrIntersectionTypeNode) : unionOrIntersectionTypeNode; } else { if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyUnionOrIntersection)) { @@ -2521,7 +2499,7 @@ namespace ts { const typeAlias = getTypeAliasForTypeLiteral(type); if (typeAlias) { // The specified symbol flags need to be reinterpreted as type flags - const entityName = symbolToName(typeAlias, /*expectsIdentifier*/ false, SymbolFlags.Type, context); + const entityName = symbolToName(typeAlias, context, SymbolFlags.Type, /*expectsIdentifier*/ false ); return createTypeReferenceNode(entityName, /*typeArguments*/ undefined); } else { @@ -2598,7 +2576,7 @@ namespace ts { } function shouldAddParenthesisAroundFunctionType(callSignature: Signature, context: NodeBuilderContext) { - if (InElementType) { + if (inElementType) { return true; } else if (inFirstTypeArgument) { @@ -2611,14 +2589,13 @@ namespace ts { } function createTypeQueryNodeFromSymbol(symbol: Symbol, symbolFlags: SymbolFlags) { - const entityName = symbolToName(symbol, /*expectsIdentifier*/ false, symbolFlags, context); + const entityName = symbolToName(symbol, context, symbolFlags, /*expectsIdentifier*/ false); return createTypeQueryNode(entityName); } function symbolToTypeReferenceName(symbol: Symbol) { // Unnamed function expressions and arrow functions have reserved names that we don't want to display - const entityName = symbol.flags & SymbolFlags.Class || !isReservedMemberName(symbol.name) ? symbolToName(symbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context) : createIdentifier(""); - // TODO: assert no type args? + const entityName = symbol.flags & SymbolFlags.Class || !isReservedMemberName(symbol.name) ? symbolToName(symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false) : createIdentifier(""); return entityName; } @@ -2651,7 +2628,6 @@ namespace ts { let i = 0; let qualifiedName: QualifiedName | undefined; if (outerTypeParameters) { - let inFirstTypeArgument = true; const length = outerTypeParameters.length; while (i < length) { // Find group of type arguments for type parameters with the same declaring container. @@ -2676,7 +2652,6 @@ namespace ts { qualifiedName = createQualifiedName(namePart, /*right*/ undefined); } } - inFirstTypeArgument = false; } } @@ -2745,12 +2720,11 @@ namespace ts { return typeElements; } - // TODO: make logic mirror that of writeObjectLiteralType for (const propertySymbol of properties) { const propertyType = getTypeOfSymbol(propertySymbol); const saveEnclosingDeclaration = context.enclosingDeclaration; context.enclosingDeclaration = undefined; - const propertyName = symbolToName(propertySymbol, /*expectsIdentifier*/ true, SymbolFlags.Value, context); + const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true); context.enclosingDeclaration = saveEnclosingDeclaration; const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined; if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) { @@ -2856,7 +2830,7 @@ namespace ts { const constraintNode = constraint && typeToTypeNodeHelper(constraint, context); const defaultParameter = getDefaultFromTypeParameter(type); const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, context); - const name = symbolToName(type.symbol, /*expectsIdentifier*/ true, SymbolFlags.Type, context); + const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ true); return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode); } @@ -2903,10 +2877,9 @@ namespace ts { } } - // TODO: add SymbolFormatFlags?? Yes to add outer type parameters. Defer UseOnlyExternalAliasing until a separate symbolbuilder PR. - function symbolToName(symbol: Symbol, expectsIdentifier: true, meaning: SymbolFlags, context: NodeBuilderContext): Identifier; - function symbolToName(symbol: Symbol, expectsIdentifier: false, meaning: SymbolFlags, context: NodeBuilderContext): EntityName; - function symbolToName(symbol: Symbol, expectsIdentifier: boolean, meaning: SymbolFlags, context: NodeBuilderContext): EntityName { + function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: true): Identifier; + function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: false): EntityName; + function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: boolean): EntityName { // Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration. let chain: Symbol[]; From c099938f61291e777fb796af20dff13eb3de1e10 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 11 May 2017 18:18:35 -0700 Subject: [PATCH 48/83] move state to flags --- src/compiler/checker.ts | 61 ++++++++++++++++++----------------------- src/compiler/types.ts | 8 ++++++ 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f6930b01ac..b5000a7af9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2229,7 +2229,7 @@ namespace ts { return result; } - + function typeFormatFlagsToNodeBuilderFlags(flags: TypeFormatFlags): NodeBuilderFlags { let result = NodeBuilderFlags.None; if (flags & TypeFormatFlags.WriteArrayAsGenericType) { @@ -2270,7 +2270,7 @@ namespace ts { } function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { - const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, typeFormatFlagsToNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors, !!(flags & TypeFormatFlags.InTypeAlias)); + const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, typeFormatFlagsToNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors); Debug.assert(typeNode !== undefined, "should always get typenode?"); const newLine = NewLineKind.None; const options = { newLine, removeComments: true }; @@ -2289,9 +2289,8 @@ namespace ts { function createNodeBuilder() { return { - typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, inTypeAlias?: boolean) => { + typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { const context = createNodeBuilderContext(enclosingDeclaration, flags); - context.InTypeAlias = inTypeAlias; const resultingNode = typeToTypeNodeHelper(type, context); const result = context.encounteredError ? undefined : resultingNode; return result; @@ -2312,14 +2311,10 @@ namespace ts { interface NodeBuilderContext { enclosingDeclaration: Node | undefined; - readonly flags: NodeBuilderFlags | undefined; + flags: NodeBuilderFlags | undefined; // State encounteredError: boolean; - inObjectTypeLiteral: boolean; - InElementType: boolean; // Writing an array or union element type - InFirstTypeArgument: boolean; // Writing first type argument of the instantiated type - InTypeAlias: boolean; // Writing type in type alias declaration symbolStack: Symbol[] | undefined; } @@ -2328,21 +2323,15 @@ namespace ts { enclosingDeclaration, flags, encounteredError: false, - inObjectTypeLiteral: false, - InElementType: false, - InFirstTypeArgument: false, - InTypeAlias: false, symbolStack: undefined }; } function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { - const inElementType = context.InElementType; - context.InElementType = false; - const inTypeAlias = context.InTypeAlias; - context.InTypeAlias = false; - const inFirstTypeArgument = context.InFirstTypeArgument; - context.InFirstTypeArgument = false; + const inElementType = context.flags & NodeBuilderFlags.InElementType; + const inFirstTypeArgument = context.flags & NodeBuilderFlags.InFirstTypeArgument; + const inTypeAlias = context.flags & NodeBuilderFlags.InTypeAlias; + context.flags &= ~(NodeBuilderFlags.StateClearingFlags); if (!type) { context.encounteredError = true; @@ -2400,7 +2389,7 @@ namespace ts { return createKeywordTypeNode(SyntaxKind.ObjectKeyword); } if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { - if (context.inObjectTypeLiteral) { + if (context.flags & NodeBuilderFlags.inObjectTypeLiteral) { if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowThisInObjectLiteral)) { context.encounteredError = true; } @@ -2455,16 +2444,16 @@ namespace ts { if (type.flags & TypeFlags.Index) { const indexedType = (type).type; - context.InElementType = true; + context.flags |= NodeBuilderFlags.InElementType; const indexTypeNode = typeToTypeNodeHelper(indexedType, context); - Debug.assert(context.InElementType === false); + Debug.assert(!(context.flags & NodeBuilderFlags.InElementType)); return createTypeOperatorNode(indexTypeNode); } if (type.flags & TypeFlags.IndexedAccess) { - context.InElementType = true; + context.flags |= NodeBuilderFlags.InElementType; const objectTypeNode = typeToTypeNodeHelper((type).objectType, context); - Debug.assert(context.InElementType === false); + Debug.assert(!(context.flags & NodeBuilderFlags.InElementType)); const indexTypeNode = typeToTypeNodeHelper((type).indexType, context); return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); } @@ -2567,10 +2556,10 @@ namespace ts { } } - const saveInObjectTypeLiteral = context.inObjectTypeLiteral; - context.inObjectTypeLiteral = true; + const savedFlags = context.flags; + context.flags |= NodeBuilderFlags.inObjectTypeLiteral; const members = createTypeNodesFromResolvedType(resolved); - context.inObjectTypeLiteral = saveInObjectTypeLiteral; + context.flags = savedFlags; const typeLiteralNode = createTypeLiteralNode(members); return setEmitFlags(typeLiteralNode, EmitFlags.ToStringFormatting); } @@ -2606,9 +2595,11 @@ namespace ts { const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context); return createTypeReferenceNode("Array", [typeArgumentNode]); } - context.InElementType = true; + + context.flags |= NodeBuilderFlags.InElementType; const elementType = typeToTypeNodeHelper(typeArguments[0], context); - context.InElementType = false; + Debug.assert(!(context.flags & NodeBuilderFlags.InElementType)); + return createArrayTypeNode(elementType); } else if (type.target.objectFlags & ObjectFlags.Tuple) { @@ -2756,19 +2747,21 @@ namespace ts { function mapToTypeNodeArray(types: Type[], context: NodeBuilderContext, addInElementTypeFlag: boolean, addInFirstTypeArgumentFlag: boolean): TypeNode[] { const result = []; - Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper"); + Debug.assert(!(context.flags & NodeBuilderFlags.InElementType), "should be unset at the beginning of the helper"); for (let i = 0; i < types.length; ++i) { const type = types[i]; - context.InElementType = addInElementTypeFlag; - if (i === 0) { - context.InFirstTypeArgument = addInFirstTypeArgumentFlag; + if (addInElementTypeFlag) { + context.flags |= NodeBuilderFlags.InElementType; + } + if (i === 0 && addInFirstTypeArgumentFlag) { + context.flags |= NodeBuilderFlags.InFirstTypeArgument; } const typeNode = typeToTypeNodeHelper(type, context); if (typeNode) { result.push(typeNode); } } - Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper"); + Debug.assert(!(context.flags & NodeBuilderFlags.InElementType), "should be unset at the end of the helper"); return result; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 73d6067cb1..e23bba7b23 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2589,6 +2589,14 @@ namespace ts { ignoreErrors = allowThisInObjectLiteral | allowQualifedNameInPlaceOfIdentifier | allowTypeParameterInQualifiedName | allowAnonymousIdentifier | allowEmptyUnionOrIntersection | allowEmptyTuple, + // State + inObjectTypeLiteral = 1 << 20, + InElementType = 1 << 21, // Writing an array or union element type + InFirstTypeArgument = 1 << 22, // Writing first type argument of the instantiated type + InTypeAlias = 1 << 23, // Writing type in type alias declaration + + /** Flags that should not be passed on to sub-nodes of the current node being built. */ + StateClearingFlags = InElementType | InFirstTypeArgument | InTypeAlias } export interface SymbolDisplayBuilder { From 0432257949b617e043bbc45f7bab2a1ba24eadd9 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 11 May 2017 18:39:40 -0700 Subject: [PATCH 49/83] use EmitFlags.SingleLine --- src/compiler/checker.ts | 4 ++-- src/compiler/emitter.ts | 4 ++-- src/compiler/types.ts | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b5000a7af9..a5e1787cfd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2561,7 +2561,7 @@ namespace ts { const members = createTypeNodesFromResolvedType(resolved); context.flags = savedFlags; const typeLiteralNode = createTypeLiteralNode(members); - return setEmitFlags(typeLiteralNode, EmitFlags.ToStringFormatting); + return setEmitFlags(typeLiteralNode, EmitFlags.SingleLine); } function shouldAddParenthesisAroundFunctionType(callSignature: Signature, context: NodeBuilderContext) { @@ -2865,7 +2865,7 @@ namespace ts { if (clone.kind === SyntaxKind.BindingElement) { (clone).initializer = undefined; } - return setEmitFlags(clone, EmitFlags.ToStringFormatting); + return setEmitFlags(clone, EmitFlags.SingleLine); } } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 073c49df55..59e3c9df96 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -962,7 +962,7 @@ namespace ts { function emitTypeLiteral(node: TypeLiteralNode) { write("{"); if (node.members.length > 0) { - emitList(node, node.members, getEmitFlags(node) & EmitFlags.ToStringFormatting ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers); + emitList(node, node.members, getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers); } write("}"); } @@ -1054,7 +1054,7 @@ namespace ts { } else { write("{"); - emitList(node, elements, getEmitFlags(node) & EmitFlags.ToStringFormatting ? ListFormat.ObjectBindingPatternElements : ListFormat.ObjectBindingPatternElementsWithSpaceBetweenBraces); + emitList(node, elements, getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.ObjectBindingPatternElements : ListFormat.ObjectBindingPatternElementsWithSpaceBetweenBraces); write("}"); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e23bba7b23..9191ad844f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3979,7 +3979,6 @@ namespace ts { NoHoisting = 1 << 20, // Do not hoist this declaration in --module system HasEndOfDeclarationMarker = 1 << 21, // Declaration has an associated NotEmittedStatement to mark the end of the declaration Iterator = 1 << 22, // The expression to a `yield*` should be treated as an Iterator when down-leveling, not an Iterable. - ToStringFormatting = 1 << 23 } export interface EmitHelper { From 7d48deec340e5b9d0096fad3b5e8751d7e5b68c3 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 11 May 2017 18:44:26 -0700 Subject: [PATCH 50/83] handle todo --- src/compiler/checker.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a5e1787cfd..fa81541d51 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2728,7 +2728,6 @@ namespace ts { } } else { - // TODO(aozgaa): should we create a node with explicit or implict any? const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword); const modifiers = isReadonlySymbol(propertySymbol) ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined; From 3640abd0a72f4a3018a9014d97df88c7f900d342 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 11 May 2017 18:53:57 -0700 Subject: [PATCH 51/83] Remove unused flags --- src/compiler/checker.ts | 28 ++++++---------------------- src/compiler/types.ts | 14 +------------- src/compiler/visitor.ts | 1 - 3 files changed, 7 insertions(+), 36 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fa81541d51..729fbdcaa5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2232,20 +2232,17 @@ namespace ts { function typeFormatFlagsToNodeBuilderFlags(flags: TypeFormatFlags): NodeBuilderFlags { let result = NodeBuilderFlags.None; - if (flags & TypeFormatFlags.WriteArrayAsGenericType) { - result |= NodeBuilderFlags.WriteArrayAsGenericType; - } - if (flags & TypeFormatFlags.UseTypeOfFunction) { - result |= NodeBuilderFlags.UseTypeOfFunction; + if (flags === TypeFormatFlags.None) { + return result; } if (flags & TypeFormatFlags.NoTruncation) { result |= NodeBuilderFlags.NoTruncation; } - if (flags & TypeFormatFlags.WriteArrowStyleSignature) { - result |= NodeBuilderFlags.WriteArrowStyleSignature; + if (flags & TypeFormatFlags.UseFullyQualifiedType) { + result |= NodeBuilderFlags.UseFullyQualifiedType; } - if (flags & TypeFormatFlags.WriteOwnNameForAnyLike) { - result |= NodeBuilderFlags.WriteOwnNameForAnyLike; + if (flags & TypeFormatFlags.SuppressAnyReturnType) { + result |= NodeBuilderFlags.SuppressAnyReturnType; } if (flags & TypeFormatFlags.WriteArrayAsGenericType) { result |= NodeBuilderFlags.WriteArrayAsGenericType; @@ -2253,18 +2250,6 @@ namespace ts { if (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature) { result |= NodeBuilderFlags.WriteTypeArgumentsOfSignature; } - if (flags & TypeFormatFlags.UseFullyQualifiedType) { - result |= NodeBuilderFlags.UseFullyQualifiedType; - } - if (flags & TypeFormatFlags.UseTypeAliasValue) { - result |= NodeBuilderFlags.UseTypeAliasValue; - } - if (flags & TypeFormatFlags.SuppressAnyReturnType) { - result |= NodeBuilderFlags.SuppressAnyReturnType; - } - if (flags & TypeFormatFlags.AddUndefined) { - result |= NodeBuilderFlags.AddUndefined; - } return result; } @@ -2893,7 +2878,6 @@ namespace ts { function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName { Debug.assert(chain && 0 <= index && index < chain.length); - // const parentIndex = index - 1; const symbol = chain[index]; let typeParameterNodes: TypeNode[] | undefined; if (index > 0) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9191ad844f..49f1e9a338 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2497,7 +2497,7 @@ namespace ts { /** Note that the resulting nodes cannot be checked. */ - typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, inTypeAlias?: boolean): TypeNode; + typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode; /** Note that the resulting nodes cannot be checked. */ signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration; /** Note that the resulting nodes cannot be checked. */ @@ -2562,22 +2562,10 @@ namespace ts { None = 0, // Options NoTruncation = 1 << 0, // Don't truncate result - // TODO: part of emit. WriteArrayAsGenericType = 1 << 1, // Write Array instead T[] - // TODO: part of emit. - UseTypeOfFunction = 1 << 2, // Write typeof instead of function type literal - // TODO: part of emit. - WriteArrowStyleSignature = 1 << 3, // Write arrow style signature - // TODO: turn it into a failing type reference? - WriteOwnNameForAnyLike = 1 << 4, // Write symbol's own name instead of 'any' for any like types (eg. unknown, __resolving__ etc) - // TODO WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type) - // TODO - UseTypeAliasValue = 1 << 7, // Serialize the type instead of using type-alias. This is needed when we emit declaration file. SuppressAnyReturnType = 1 << 8, // If the return type is any-like, don't offer a return type. - // TODO - AddUndefined = 1 << 9, // Add undefined to types of initialized, non-optional parameters // Error handling allowThisInObjectLiteral = 1 << 10, diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index fce43b622b..ce7908b885 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -359,7 +359,6 @@ namespace ts { case SyntaxKind.PropertySignature: return updatePropertySignature((node), - // TODO: tokenVisitor or visitor for a nodearray of tokens? nodesVisitor((node).modifiers, visitor, isToken), visitNode((node).name, visitor, isPropertyName), visitNode((node).questionToken, tokenVisitor, isToken), From 0588f8b3800097513c3029c8b8f20ffba443c5c1 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 12 May 2017 13:25:15 -0700 Subject: [PATCH 52/83] cleanup --- src/compiler/checker.ts | 46 +++++++++++++---------------------------- src/compiler/factory.ts | 9 -------- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3ce73b3283..3d040bd284 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2436,24 +2436,17 @@ namespace ts { Debug.assert(!!(type.flags & TypeFlags.Object)); return typeReferenceToTypeNode(type); } - if (objectFlags & ObjectFlags.ClassOrInterface) { - Debug.assert(!!(type.flags & TypeFlags.Object)); - const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false); - return createTypeReferenceNode(name, /*typeArguments*/ undefined); - } - if (type.flags & TypeFlags.TypeParameter) { + if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) { const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false); // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. return createTypeReferenceNode(name, /*typeArguments*/ undefined); } - if (!inTypeAlias && type.aliasSymbol && isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { const name = symbolToTypeReferenceName(type.aliasSymbol); const typeArgumentNodes = toTypeArgumentNodes(type.aliasTypeArguments, context); return createTypeReferenceNode(name, typeArgumentNodes); } - if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { const types = type.flags & TypeFlags.Union ? formatUnionTypes((type).types) : (type).types; const typeNodes = types && mapToTypeNodeArray(types, context, /*addInElementTypeFlag*/ true, /*addInFirstTypeArgumentFlag*/ false); @@ -2468,13 +2461,11 @@ namespace ts { return undefined; } } - if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) { Debug.assert(!!(type.flags & TypeFlags.Object)); // The type is an object literal type. return createAnonymousTypeNode(type); } - if (type.flags & TypeFlags.Index) { const indexedType = (type).type; context.flags |= NodeBuilderFlags.InElementType; @@ -2482,7 +2473,6 @@ namespace ts { Debug.assert(!(context.flags & NodeBuilderFlags.InElementType)); return createTypeOperatorNode(indexTypeNode); } - if (type.flags & TypeFlags.IndexedAccess) { context.flags |= NodeBuilderFlags.InElementType; const objectTypeNode = typeToTypeNodeHelper((type).objectType, context); @@ -2495,13 +2485,10 @@ namespace ts { function createMappedTypeNodeFromType(type: MappedType) { Debug.assert(!!(type.flags & TypeFlags.Object)); - const typeParameter = getTypeParameterFromMappedType(type); - const typeParameterNode = typeParameterToDeclaration(typeParameter, context); - - const templateType = getTemplateTypeFromMappedType(type); - const templateTypeNode = typeToTypeNodeHelper(templateType, context); const readonlyToken = type.declaration && type.declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined; const questionToken = type.declaration && type.declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined; + const typeParameterNode = typeParameterToDeclaration(getTypeParameterFromMappedType(type), context); + const templateTypeNode = typeToTypeNodeHelper(getTemplateTypeFromMappedType(type), context); const mappedTypeNode = createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode); return setEmitFlags(mappedTypeNode, EmitFlags.SingleLine); @@ -2521,7 +2508,7 @@ namespace ts { const typeAlias = getTypeAliasForTypeLiteral(type); if (typeAlias) { // The specified symbol flags need to be reinterpreted as type flags - const entityName = symbolToName(typeAlias, context, SymbolFlags.Type, /*expectsIdentifier*/ false ); + const entityName = symbolToName(typeAlias, context, SymbolFlags.Type, /*expectsIdentifier*/ false); return createTypeReferenceNode(entityName, /*typeArguments*/ undefined); } else { @@ -2802,8 +2789,8 @@ namespace ts { } function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, context: NodeBuilderContext): IndexSignatureDeclaration { - const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword); const name = getNameFromIndexInfo(indexInfo) || "x"; + const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword); const indexingParameter = createParameter( /*decorators*/ undefined, @@ -2851,37 +2838,32 @@ namespace ts { } function typeParameterToDeclaration(type: TypeParameter, context: NodeBuilderContext): TypeParameterDeclaration { + const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ true); const constraint = getConstraintFromTypeParameter(type); const constraintNode = constraint && typeToTypeNodeHelper(constraint, context); const defaultParameter = getDefaultFromTypeParameter(type); const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, context); - const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ true); return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode); } function symbolToParameterDeclaration(parameterSymbol: Symbol, context: NodeBuilderContext): ParameterDeclaration { const parameterDeclaration = getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter); + const modifiers = parameterDeclaration.modifiers && parameterDeclaration.modifiers.map(getSynthesizedClone); + const dotDotDotToken = isRestParameter(parameterDeclaration) ? createToken(SyntaxKind.DotDotDotToken) : undefined; + const name = parameterDeclaration.name.kind === SyntaxKind.Identifier ? + getSynthesizedClone(parameterDeclaration.name) : + cloneBindingName(parameterDeclaration.name); + const questionToken = isOptionalParameter(parameterDeclaration) ? createToken(SyntaxKind.QuestionToken) : undefined; + let parameterType = getTypeOfSymbol(parameterSymbol); if (isRequiredInitializedParameter(parameterDeclaration)) { parameterType = includeFalsyTypes(parameterType, TypeFlags.Undefined); } const parameterTypeNode = typeToTypeNodeHelper(parameterType, context); - let name: BindingName; - if (parameterDeclaration.name.kind === SyntaxKind.Identifier) { - name = getSynthesizedClone(parameterDeclaration.name); - } - else { - Debug.assert(parameterDeclaration.name.kind === SyntaxKind.ArrayBindingPattern || parameterDeclaration.name.kind === SyntaxKind.ObjectBindingPattern); - name = cloneBindingName(parameterDeclaration.name); - } - const questionToken = isOptionalParameter(parameterDeclaration) ? createToken(SyntaxKind.QuestionToken) : undefined; - const dotDotDotToken = (parameterDeclaration ? isRestParameter(parameterDeclaration) : isTransientSymbol(parameterSymbol) && parameterSymbol.isRestParameter) ? - createToken(SyntaxKind.DotDotDotToken) : - undefined; const parameterNode = createParameter( /*decorators*/ undefined, - cloneNodeArray(parameterDeclaration.modifiers), + modifiers, dotDotDotToken, name, questionToken, diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 230eb678ee..97ee45aedc 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -84,15 +84,6 @@ namespace ts { return clone; } - export function getDeepSynthesizedClone(node: T | undefined): T { - const clone = visitEachChild(node, getDeepSynthesizedClone, nullTransformationContext, /*nodeVisitor*/ undefined, getSynthesizedClone); - return nodeIsSynthesized(clone) ? clone : getSynthesizedClone(clone); - } - - export function cloneNodeArray(nodeArray: NodeArray) { - return nodeArray && nodeArray.map(getDeepSynthesizedClone); - } - // Literals export function createLiteral(value: string): StringLiteral; From a32bc985bfeca89c32f0d7c10e83563dc115ef6e Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 12 May 2017 16:27:35 -0700 Subject: [PATCH 53/83] respond to comments --- src/compiler/checker.ts | 65 +++++++++++++++++++-------------------- src/compiler/emitter.ts | 21 +++++++------ src/compiler/factory.ts | 60 +++++++++++++++++++----------------- src/compiler/types.ts | 28 ++++++++--------- src/compiler/utilities.ts | 2 -- src/compiler/visitor.ts | 12 ++++++++ src/services/services.ts | 2 +- 7 files changed, 101 insertions(+), 89 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3d040bd284..a4c5f40132 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2278,35 +2278,10 @@ namespace ts { return result; } - function typeFormatFlagsToNodeBuilderFlags(flags: TypeFormatFlags): NodeBuilderFlags { - let result = NodeBuilderFlags.None; - if (flags === TypeFormatFlags.None) { - return result; - } - if (flags & TypeFormatFlags.NoTruncation) { - result |= NodeBuilderFlags.NoTruncation; - } - if (flags & TypeFormatFlags.UseFullyQualifiedType) { - result |= NodeBuilderFlags.UseFullyQualifiedType; - } - if (flags & TypeFormatFlags.SuppressAnyReturnType) { - result |= NodeBuilderFlags.SuppressAnyReturnType; - } - if (flags & TypeFormatFlags.WriteArrayAsGenericType) { - result |= NodeBuilderFlags.WriteArrayAsGenericType; - } - if (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature) { - result |= NodeBuilderFlags.WriteTypeArgumentsOfSignature; - } - - return result; - } - function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { - const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, typeFormatFlagsToNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors); + const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors); Debug.assert(typeNode !== undefined, "should always get typenode?"); - const newLine = NewLineKind.None; - const options = { newLine, removeComments: true }; + const options = { removeComments: true }; const writer = createTextWriter(""); const printer = createPrinter(options, writer); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); @@ -2318,6 +2293,30 @@ namespace ts { return result.substr(0, maxLength - "...".length) + "..."; } return result; + + function toNodeBuilderFlags(flags?: TypeFormatFlags): NodeBuilderFlags { + let result = NodeBuilderFlags.None; + if (!flags) { + return result; + } + if (flags & TypeFormatFlags.NoTruncation) { + result |= NodeBuilderFlags.NoTruncation; + } + if (flags & TypeFormatFlags.UseFullyQualifiedType) { + result |= NodeBuilderFlags.UseFullyQualifiedType; + } + if (flags & TypeFormatFlags.SuppressAnyReturnType) { + result |= NodeBuilderFlags.SuppressAnyReturnType; + } + if (flags & TypeFormatFlags.WriteArrayAsGenericType) { + result |= NodeBuilderFlags.WriteArrayAsGenericType; + } + if (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature) { + result |= NodeBuilderFlags.WriteTypeArgumentsOfSignature; + } + + return result; + } } function createNodeBuilder() { @@ -2423,7 +2422,7 @@ namespace ts { } if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { if (context.flags & NodeBuilderFlags.inObjectTypeLiteral) { - if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowThisInObjectLiteral)) { + if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowThisInObjectLiteral)) { context.encounteredError = true; } } @@ -2455,7 +2454,7 @@ namespace ts { return inElementType ? createParenthesizedType(unionOrIntersectionTypeNode) : unionOrIntersectionTypeNode; } else { - if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyUnionOrIntersection)) { + if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) { context.encounteredError = true; } return undefined; @@ -2629,7 +2628,7 @@ namespace ts { return createTupleTypeNode(tupleConstituentNodes); } } - if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyTuple)) { + if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowEmptyTuple)) { context.encounteredError = true; } return undefined; @@ -2901,7 +2900,7 @@ namespace ts { if (expectsIdentifier && chain.length !== 1 && !context.encounteredError - && !(context.flags & NodeBuilderFlags.allowQualifedNameInPlaceOfIdentifier)) { + && !(context.flags & NodeBuilderFlags.AllowQualifedNameInPlaceOfIdentifier)) { context.encounteredError = true; } return createEntityNameFromSymbolChain(chain, chain.length - 1); @@ -2923,7 +2922,7 @@ namespace ts { } } if (typeParameters && typeParameters.length > 0) { - if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowTypeParameterInQualifiedName)) { + if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowTypeParameterInQualifiedName)) { context.encounteredError = true; } typeParameterNodes = toTypeArgumentNodes(typeParameters, context); @@ -2981,7 +2980,7 @@ namespace ts { if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) { return declarationNameToString((declaration.parent).name); } - if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowAnonymousIdentifier)) { + if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) { context.encounteredError = true; } switch (declaration.kind) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index d943e91b49..30e5ba1a09 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -234,12 +234,7 @@ namespace ts { writeBundle }; - /** - * If `sourceFile` is `undefined`, `node` must be a synthesized `TypeNode`. - */ - function printNode(hint: EmitHint, node: TypeNode, sourceFile: undefined): string; - function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string; - function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined): string { + function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string { switch (hint) { case EmitHint.SourceFile: Debug.assert(isSourceFile(node), "Expected a SourceFile node."); @@ -269,6 +264,11 @@ namespace ts { return endPrint(); } + /** + * If `sourceFile` is `undefined`, `node` must be a synthesized `TypeNode`. + */ + function writeNode(hint: EmitHint, node: TypeNode, sourceFile: undefined, output: EmitTextWriter): void; + function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile, output: EmitTextWriter): void; function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, output: EmitTextWriter) { const previousWriter = writer; setWriter(output); @@ -961,6 +961,7 @@ namespace ts { function emitTypeLiteral(node: TypeLiteralNode) { write("{"); + // TODO: fix added indentation so we can remove this check. if (node.members.length > 0) { emitList(node, node.members, getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers); } @@ -2525,7 +2526,7 @@ namespace ts { const firstChild = children[0]; if (firstChild === undefined) { - return !(rangeIsOnSingleLine(parentNode, currentSourceFile)); + return !rangeIsOnSingleLine(parentNode, currentSourceFile); } else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(firstChild)) { return synthesizedNodeStartsOnNewLine(firstChild, format); @@ -2551,7 +2552,7 @@ namespace ts { return synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format); } else { - return !(rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile)); + return !rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile); } } else { @@ -2570,13 +2571,13 @@ namespace ts { const lastChild = lastOrUndefined(children); if (lastChild === undefined) { - return !(rangeIsOnSingleLine(parentNode, currentSourceFile)); + return !rangeIsOnSingleLine(parentNode, currentSourceFile); } else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(lastChild)) { return synthesizedNodeStartsOnNewLine(lastChild, format); } else { - return !(rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile)); + return !rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile); } } else { diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 97ee45aedc..45aa14bdd2 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2,26 +2,6 @@ /// namespace ts { - export const nullTransformationContext: TransformationContext = { - enableEmitNotification: noop, - enableSubstitution: noop, - endLexicalEnvironment: () => undefined, - getCompilerOptions: notImplemented, - getEmitHost: notImplemented, - getEmitResolver: notImplemented, - hoistFunctionDeclaration: noop, - hoistVariableDeclaration: noop, - isEmitNotificationEnabled: notImplemented, - isSubstitutionEnabled: notImplemented, - onEmitNode: noop, - onSubstituteNode: notImplemented, - readEmitHelpers: notImplemented, - requestEmitHelper: noop, - resumeLexicalEnvironment: noop, - startLexicalEnvironment: noop, - suspendLexicalEnvironment: noop - }; - function createSynthesizedNode(kind: SyntaxKind): Node { const node = createNode(kind, -1, -1); node.flags |= NodeFlags.Synthesized; @@ -127,13 +107,18 @@ namespace ts { // Identifiers + export function createIdentifier(text: string): Identifier; + /* @internal */ + export function createIdentifier(text: string, typeArguments: TypeNode[]): Identifier; export function createIdentifier(text: string, typeArguments?: TypeNode[]): Identifier { const node = createSynthesizedNode(SyntaxKind.Identifier); node.text = escapeIdentifier(text); node.originalKeywordKind = text ? stringToToken(text) : SyntaxKind.Unknown; node.autoGenerateKind = GeneratedIdentifierKind.None; node.autoGenerateId = 0; - node.typeArguments = asNodeArray(typeArguments); + if (typeArguments) { + node.typeArguments = createNodeArray(typeArguments); + } return node; } @@ -299,13 +284,13 @@ namespace ts { // Type Elements export function createPropertySignature(modifiers: Modifier[] | undefined, name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertySignature { - const propertySignature = createSynthesizedNode(SyntaxKind.PropertySignature) as PropertySignature; - propertySignature.modifiers = asNodeArray(modifiers); - propertySignature.name = asName(name); - propertySignature.questionToken = questionToken; - propertySignature.type = type; - propertySignature.initializer = initializer; - return propertySignature; + const node = createSynthesizedNode(SyntaxKind.PropertySignature) as PropertySignature; + node.modifiers = asNodeArray(modifiers); + node.name = asName(name); + node.questionToken = questionToken; + node.type = type; + node.initializer = initializer; + return node; } export function updatePropertySignature(node: PropertySignature, modifiers: Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { @@ -2494,6 +2479,25 @@ namespace ts { /* @internal */ namespace ts { + export const nullTransformationContext: TransformationContext = { + enableEmitNotification: noop, + enableSubstitution: noop, + endLexicalEnvironment: () => undefined, + getCompilerOptions: notImplemented, + getEmitHost: notImplemented, + getEmitResolver: notImplemented, + hoistFunctionDeclaration: noop, + hoistVariableDeclaration: noop, + isEmitNotificationEnabled: notImplemented, + isSubstitutionEnabled: notImplemented, + onEmitNode: noop, + onSubstituteNode: notImplemented, + readEmitHelpers: notImplemented, + requestEmitHelper: noop, + resumeLexicalEnvironment: noop, + startLexicalEnvironment: noop, + suspendLexicalEnvironment: noop + }; // Compound nodes diff --git a/src/compiler/types.ts b/src/compiler/types.ts index df89120e44..e7e6f9ad1a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -576,11 +576,11 @@ namespace ts { * If the identifier begins with two underscores, this will begin with three. */ text: string; - originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later + originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later /*@internal*/ autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier. - /*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name. - isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace - /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics. + /*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name. + isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace + /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics. } // Transient identifier node (marked by id === -1) @@ -2592,14 +2592,14 @@ namespace ts { SuppressAnyReturnType = 1 << 8, // If the return type is any-like, don't offer a return type. // Error handling - allowThisInObjectLiteral = 1 << 10, - allowQualifedNameInPlaceOfIdentifier = 1 << 11, - allowTypeParameterInQualifiedName = 1 << 12, - allowAnonymousIdentifier = 1 << 13, - allowEmptyUnionOrIntersection = 1 << 14, - allowEmptyTuple = 1 << 15, + AllowThisInObjectLiteral = 1 << 10, + AllowQualifedNameInPlaceOfIdentifier = 1 << 11, + AllowTypeParameterInQualifiedName = 1 << 12, + AllowAnonymousIdentifier = 1 << 13, + AllowEmptyUnionOrIntersection = 1 << 14, + AllowEmptyTuple = 1 << 15, - ignoreErrors = allowThisInObjectLiteral | allowQualifedNameInPlaceOfIdentifier | allowTypeParameterInQualifiedName | allowAnonymousIdentifier | allowEmptyUnionOrIntersection | allowEmptyTuple, + ignoreErrors = AllowThisInObjectLiteral | AllowQualifedNameInPlaceOfIdentifier | AllowTypeParameterInQualifiedName | AllowAnonymousIdentifier | AllowEmptyUnionOrIntersection | AllowEmptyTuple, // State inObjectTypeLiteral = 1 << 20, @@ -3538,8 +3538,7 @@ namespace ts { export const enum NewLineKind { CarriageReturnLineFeed = 0, - LineFeed = 1, - None = 2 + LineFeed = 1 } export interface LineAndCharacter { @@ -3964,7 +3963,6 @@ namespace ts { } export const enum EmitFlags { - None = 0, SingleLine = 1 << 0, // The contents of this node should be emitted on a single line. AdviseOnEmitNode = 1 << 1, // The printer should invoke the onEmitNode callback when printing this node. NoSubstitution = 1 << 2, // Disables further substitution of an expression. @@ -4195,7 +4193,7 @@ namespace ts { * the identifiers of the source file are used when generating unique names to avoid * collisions. */ - printNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined): string; + printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string; /** * Prints a source file as-is, without any emit transformations. */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index be6b8ccee1..825465085c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3253,8 +3253,6 @@ namespace ts { const lineFeed = "\n"; export function getNewLineCharacter(options: CompilerOptions | PrinterOptions): string { switch (options.newLine) { - case NewLineKind.None: - return ""; case NewLineKind.CarriageReturnLineFeed: return carriageReturnLineFeed; case NewLineKind.LineFeed: diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index c9c3a3c48f..c62af0da79 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -254,6 +254,7 @@ namespace ts { case SyntaxKind.Decorator: return updateDecorator(node, visitNode((node).expression, visitor, isExpression)); + // Type elements case SyntaxKind.PropertySignature: @@ -970,6 +971,15 @@ namespace ts { break; // Type member + + case SyntaxKind.PropertySignature: + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).questionToken, cbNode, result); + result = reduceNode((node).type, cbNode, result); + result = reduceNode((node).initializer, cbNode, result); + break; + case SyntaxKind.PropertyDeclaration: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result); @@ -978,6 +988,8 @@ namespace ts { result = reduceNode((node).initializer, cbNode, result); break; + case SyntaxKind.PropertySignature: + case SyntaxKind.MethodDeclaration: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result); diff --git a/src/services/services.ts b/src/services/services.ts index 43d875cbf7..ccc9f66e51 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -360,7 +360,7 @@ namespace ts { _incrementExpressionBrand: any; _unaryExpressionBrand: any; _expressionBrand: any; - typeArguments: any; + /*@internal*/typeArguments: NodeArray; constructor(_kind: SyntaxKind.Identifier, pos: number, end: number) { super(pos, end); } From 9e9054bd2b112acfaa310fa7ac7cfb0209ff7c16 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 12 May 2017 17:42:10 -0700 Subject: [PATCH 54/83] handle todo --- src/compiler/checker.ts | 2 +- src/compiler/emitter.ts | 2 +- src/compiler/factory.ts | 12 ++---------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a4c5f40132..a5295df7b8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2555,7 +2555,7 @@ namespace ts { const resolved = resolveStructuredTypeMembers(type); if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) { if (!resolved.callSignatures.length && !resolved.constructSignatures.length) { - return createTypeLiteralNode(/*members*/ undefined); + return setEmitFlags(createTypeLiteralNode(/*members*/ undefined), EmitFlags.SingleLine); } if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 30e5ba1a09..8ec03e90c7 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -961,7 +961,7 @@ namespace ts { function emitTypeLiteral(node: TypeLiteralNode) { write("{"); - // TODO: fix added indentation so we can remove this check. + // If the literal is empty, do not add spaces between braces. if (node.members.length > 0) { emitList(node, node.members, getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers); } diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 45aa14bdd2..d236ef9959 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3294,16 +3294,6 @@ namespace ts { return statements; } - export function parenthesizeConditionalHead(condition: Expression) { - const conditionalPrecedence = getOperatorPrecedence(SyntaxKind.ConditionalExpression, SyntaxKind.QuestionToken); - const emittedCondition = skipPartiallyEmittedExpressions(condition); - const conditionPrecedence = getExpressionPrecedence(emittedCondition); - if (compareValues(conditionPrecedence, conditionalPrecedence) === Comparison.LessThan) { - return createParen(condition); - } - return condition; - } - /** * Wraps the operand to a BinaryExpression in parentheses if they are needed to preserve the intended * order of operations. @@ -3605,6 +3595,8 @@ namespace ts { return expression; } + function parenthesizeElementTypeMembers() {} + /** * Clones a series of not-emitted expressions with a new inner expression. * From 6fd86b47f9f374aeb8022f8a58cad877e503affb Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 12 May 2017 17:51:14 -0700 Subject: [PATCH 55/83] temp --- src/compiler/factory.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index d236ef9959..094ad8cb8c 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3595,7 +3595,18 @@ namespace ts { return expression; } - function parenthesizeElementTypeMembers() {} + function parenthesizeElementTypeMember(member: TypeNode) { + switch (member.kind) { + case SyntaxKind.UnionType: + case SyntaxKind.IntersectionType: + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + return createParenthesizedType(member); + } + } + function parenthesizeElementTypeMembers(members: NodeArray) { + return createNodeArray(members.map(parenthesizeElementTypeMember)); + } /** * Clones a series of not-emitted expressions with a new inner expression. From 5eb2bd08acb4bf42e0aeb75f30dd90d83a4182fb Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 15 May 2017 08:24:29 -0700 Subject: [PATCH 56/83] findAllReferences: In `export default foo`, symbol name is `foo` --- src/compiler/utilities.ts | 4 ++++ src/services/importTracker.ts | 9 +++++---- .../fourslash/findAllRefsForDefaultExport04.ts | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tests/cases/fourslash/findAllRefsForDefaultExport04.ts diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 58a1822a24..5046b44d09 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4032,6 +4032,10 @@ namespace ts { return node.kind === SyntaxKind.ExportSpecifier; } + export function isExportAssignment(node: Node): node is ExportAssignment { + return node.kind === SyntaxKind.ExportAssignment; + } + export function isModuleOrEnumDeclaration(node: Node): node is ModuleDeclaration | EnumDeclaration { return node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.EnumDeclaration; } diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index df50f3ec31..c540c44620 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -526,17 +526,18 @@ namespace ts.FindAllReferences { return isExternalModuleSymbol(exportingModuleSymbol) ? { exportingModuleSymbol, exportKind } : undefined; } - function symbolName(symbol: Symbol): string { + function symbolName(symbol: Symbol): string | undefined { if (symbol.name !== "default") { return symbol.name; } - const name = forEach(symbol.declarations, decl => { + return forEach(symbol.declarations, decl => { + if (isExportAssignment(decl)) { + return isIdentifier(decl.expression) ? decl.expression.text : undefined; + } const name = getNameOfDeclaration(decl); return name && name.kind === SyntaxKind.Identifier && name.text; }); - Debug.assert(!!name); - return name; } /** If at an export specifier, go to the symbol it refers to. */ diff --git a/tests/cases/fourslash/findAllRefsForDefaultExport04.ts b/tests/cases/fourslash/findAllRefsForDefaultExport04.ts new file mode 100644 index 0000000000..c8fdb0a614 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsForDefaultExport04.ts @@ -0,0 +1,16 @@ +/// + +// @Filename: /a.ts +////const [|{| "isWriteAccess": true, "isDefinition": true |}a|] = 0; +////export default [|a|]; + +// @Filename: /b.ts +////import [|{| "isWriteAccess": true, "isDefinition": true |}a|] from "./a"; +////[|a|]; + +const [r0, r1, r2, r3] = test.ranges(); +verify.referenceGroups([r0, r1], [ + { definition: "const a: 0", ranges: [r0, r1] }, + { definition: "import a", ranges: [r2, r3] } +]); +verify.singleReferenceGroup("import a", [r2, r3]); From 26416c32f324395207659517a24a96de6a5a828c Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 15 May 2017 10:17:36 -0700 Subject: [PATCH 57/83] Allow spreading arrays after required parameters This allows: 1. Spreading arrays into all-optional parameters whose types match. 2. Spreading arrays into parameter lists that are too short and whose body presumably uses `arguments`. --- src/compiler/checker.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dde60c19f4..6c68df7c0c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9598,6 +9598,10 @@ namespace ts { return signature.hasRestParameter && parameterIndex >= signature.parameters.length - 1; } + function areAllParametersOptionalAfter(signature: Signature, parameterIndex: number) { + return parameterIndex >= signature.minArgumentCount; + } + function isSupertypeOfEach(candidate: Type, types: Type[]): boolean { for (const t of types) { if (candidate !== t && !isTypeSubtypeOf(t, candidate)) return false; @@ -14649,7 +14653,7 @@ namespace ts { // If spread arguments are present, check that they correspond to a rest parameter. If so, no // further checking is necessary. if (spreadArgIndex >= 0) { - return isRestParameterIndex(signature, spreadArgIndex); + return isRestParameterIndex(signature, spreadArgIndex) || areAllParametersOptionalAfter(signature, spreadArgIndex); } // Too many arguments implies incorrect arity. From 20a4e32becf40823d86cdd76e32b5291e41315df Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 15 May 2017 10:18:34 -0700 Subject: [PATCH 58/83] parenthesization in factory --- src/compiler/checker.ts | 72 ++++++++++----------------------------- src/compiler/factory.ts | 29 ++++++++++++---- src/compiler/types.ts | 9 ++--- src/compiler/utilities.ts | 10 ++++++ 4 files changed, 52 insertions(+), 68 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a5295df7b8..a7ca676908 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2279,7 +2279,7 @@ namespace ts { } function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { - const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors); + const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName); Debug.assert(typeNode !== undefined, "should always get typenode?"); const options = { removeComments: true }; const writer = createTextWriter(""); @@ -2360,10 +2360,8 @@ namespace ts { } function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { - const inElementType = context.flags & NodeBuilderFlags.InElementType; - const inFirstTypeArgument = context.flags & NodeBuilderFlags.InFirstTypeArgument; const inTypeAlias = context.flags & NodeBuilderFlags.InTypeAlias; - context.flags &= ~(NodeBuilderFlags.StateClearingFlags); + context.flags &= ~(NodeBuilderFlags.InTypeAlias); if (!type) { context.encounteredError = true; @@ -2443,15 +2441,15 @@ namespace ts { if (!inTypeAlias && type.aliasSymbol && isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { const name = symbolToTypeReferenceName(type.aliasSymbol); - const typeArgumentNodes = toTypeArgumentNodes(type.aliasTypeArguments, context); + const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, context); return createTypeReferenceNode(name, typeArgumentNodes); } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { const types = type.flags & TypeFlags.Union ? formatUnionTypes((type).types) : (type).types; - const typeNodes = types && mapToTypeNodeArray(types, context, /*addInElementTypeFlag*/ true, /*addInFirstTypeArgumentFlag*/ false); + const typeNodes = types && mapToTypeNodeArray(types, context); if (typeNodes && typeNodes.length > 0) { const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes); - return inElementType ? createParenthesizedType(unionOrIntersectionTypeNode) : unionOrIntersectionTypeNode; + return unionOrIntersectionTypeNode; } else { if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) { @@ -2467,15 +2465,11 @@ namespace ts { } if (type.flags & TypeFlags.Index) { const indexedType = (type).type; - context.flags |= NodeBuilderFlags.InElementType; const indexTypeNode = typeToTypeNodeHelper(indexedType, context); - Debug.assert(!(context.flags & NodeBuilderFlags.InElementType)); return createTypeOperatorNode(indexTypeNode); } if (type.flags & TypeFlags.IndexedAccess) { - context.flags |= NodeBuilderFlags.InElementType; const objectTypeNode = typeToTypeNodeHelper((type).objectType, context); - Debug.assert(!(context.flags & NodeBuilderFlags.InElementType)); const indexTypeNode = typeToTypeNodeHelper((type).indexType, context); return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); } @@ -2561,17 +2555,14 @@ namespace ts { if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { const signature = resolved.callSignatures[0]; const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context); - return shouldAddParenthesisAroundFunctionType(signature, context) ? - createParenthesizedType(signatureNode) : - signatureNode; + return signatureNode; } + if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { const signature = resolved.constructSignatures[0]; const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, context); - return shouldAddParenthesisAroundFunctionType(signature, context) ? - createParenthesizedType(signatureNode) : - signatureNode; + return signatureNode; } } @@ -2583,19 +2574,6 @@ namespace ts { return setEmitFlags(typeLiteralNode, EmitFlags.SingleLine); } - function shouldAddParenthesisAroundFunctionType(callSignature: Signature, context: NodeBuilderContext) { - if (inElementType) { - return true; - } - else if (inFirstTypeArgument) { - // Add parenthesis around function type for the first type argument to avoid ambiguity - const typeParameters = callSignature.target && (context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature) ? - callSignature.target.typeParameters : callSignature.typeParameters; - return typeParameters && typeParameters.length !== 0; - } - return false; - } - function createTypeQueryNodeFromSymbol(symbol: Symbol, symbolFlags: SymbolFlags) { const entityName = symbolToName(symbol, context, symbolFlags, /*expectsIdentifier*/ false); return createTypeQueryNode(entityName); @@ -2615,15 +2593,13 @@ namespace ts { return createTypeReferenceNode("Array", [typeArgumentNode]); } - context.flags |= NodeBuilderFlags.InElementType; const elementType = typeToTypeNodeHelper(typeArguments[0], context); - Debug.assert(!(context.flags & NodeBuilderFlags.InElementType)); - return createArrayTypeNode(elementType); } else if (type.target.objectFlags & ObjectFlags.Tuple) { if (typeArguments.length > 0) { - const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)), context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ false); + const slice = typeArguments.slice(0, getTypeReferenceArity(type)); + const tupleConstituentNodes = slice && mapToTypeNodeArray(slice, context); if (tupleConstituentNodes && tupleConstituentNodes.length > 0) { return createTupleTypeNode(tupleConstituentNodes); } @@ -2649,7 +2625,8 @@ namespace ts { // When type parameters are their own type arguments for the whole group (i.e. we have // the default outer type arguments), we don't show the group. if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { - const typeArgumentNodes = createNodeArray(toTypeArgumentNodes(typeArguments.slice(start, i), context)); + const slice = typeArguments.slice(start, i); + const typeArgumentNodes = slice && createNodeArray(mapToTypeNodeArray(slice, context)); const namePart = symbolToTypeReferenceName(parent); (namePart.kind === SyntaxKind.Identifier ? namePart : namePart.right).typeArguments = typeArgumentNodes; @@ -2680,7 +2657,7 @@ namespace ts { if (some(typeArguments)) { const typeParameterCount = (type.target.typeParameters || emptyArray).length; const slice = typeArguments && typeArguments.slice(i, typeParameterCount); - typeArgumentNodes = toTypeArgumentNodes(slice, context); + typeArgumentNodes = slice && mapToTypeNodeArray(slice, context); } if (typeArgumentNodes) { @@ -2763,28 +2740,17 @@ namespace ts { } } - function mapToTypeNodeArray(types: Type[], context: NodeBuilderContext, addInElementTypeFlag: boolean, addInFirstTypeArgumentFlag: boolean): TypeNode[] { + function mapToTypeNodeArray(types: Type[], context: NodeBuilderContext): TypeNode[] { const result = []; - Debug.assert(!(context.flags & NodeBuilderFlags.InElementType), "should be unset at the beginning of the helper"); for (let i = 0; i < types.length; ++i) { const type = types[i]; - if (addInElementTypeFlag) { - context.flags |= NodeBuilderFlags.InElementType; - } - if (i === 0 && addInFirstTypeArgumentFlag) { - context.flags |= NodeBuilderFlags.InFirstTypeArgument; - } const typeNode = typeToTypeNodeHelper(type, context); if (typeNode) { result.push(typeNode); } } - Debug.assert(!(context.flags & NodeBuilderFlags.InElementType), "should be unset at the end of the helper"); - return result; - } - function toTypeArgumentNodes(typeArguments: Type[], context: NodeBuilderContext) { - return typeArguments && mapToTypeNodeArray(typeArguments, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true); + return result; } function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, context: NodeBuilderContext): IndexSignatureDeclaration { @@ -2909,7 +2875,7 @@ namespace ts { Debug.assert(chain && 0 <= index && index < chain.length); const symbol = chain[index]; let typeParameterNodes: TypeNode[] | undefined; - if (index > 0) { + if (context.flags & NodeBuilderFlags.WriteTypeParametersInQualifiedName && index > 0) { const parentSymbol = chain[index - 1]; let typeParameters: TypeParameter[]; if (getCheckFlags(symbol) & CheckFlags.Instantiated) { @@ -2921,11 +2887,9 @@ namespace ts { typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); } } + if (typeParameters && typeParameters.length > 0) { - if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowTypeParameterInQualifiedName)) { - context.encounteredError = true; - } - typeParameterNodes = toTypeArgumentNodes(typeParameters, context); + typeParameterNodes = mapToTypeNodeArray(typeParameters, context); } } diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 094ad8cb8c..18e71f94ee 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -506,7 +506,7 @@ namespace ts { export function createTypeReferenceNode(typeName: string | EntityName, typeArguments: TypeNode[] | undefined) { const node = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode; node.typeName = asName(typeName); - node.typeArguments = asNodeArray(typeArguments); + node.typeArguments = typeArguments && parenthesizeTypeParameters(typeArguments); return node; } @@ -559,7 +559,7 @@ namespace ts { export function createArrayTypeNode(elementType: TypeNode) { const node = createSynthesizedNode(SyntaxKind.ArrayType) as ArrayTypeNode; - node.elementType = elementType; + node.elementType = parenthesizeElementTypeMember(elementType); return node; } @@ -599,7 +599,7 @@ namespace ts { export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: TypeNode[]) { const node = createSynthesizedNode(kind) as UnionTypeNode | IntersectionTypeNode; - node.types = createNodeArray(types); + node.types = parenthesizeElementTypeMembers(types); return node; } @@ -628,7 +628,7 @@ namespace ts { export function createTypeOperatorNode(type: TypeNode) { const node = createSynthesizedNode(SyntaxKind.TypeOperator) as TypeOperatorNode; node.operator = SyntaxKind.KeyOfKeyword; - node.type = type; + node.type = parenthesizeElementTypeMember(type); return node; } @@ -638,7 +638,7 @@ namespace ts { export function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) { const node = createSynthesizedNode(SyntaxKind.IndexedAccessType) as IndexedAccessTypeNode; - node.objectType = objectType; + node.objectType = parenthesizeElementTypeMember(objectType); node.indexType = indexType; return node; } @@ -3595,7 +3595,7 @@ namespace ts { return expression; } - function parenthesizeElementTypeMember(member: TypeNode) { + export function parenthesizeElementTypeMember(member: TypeNode) { switch (member.kind) { case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: @@ -3603,11 +3603,26 @@ namespace ts { case SyntaxKind.ConstructorType: return createParenthesizedType(member); } + return member; } - function parenthesizeElementTypeMembers(members: NodeArray) { + + export function parenthesizeElementTypeMembers(members: TypeNode[]) { + // TODO: does this lose `originalNode` ptr? return createNodeArray(members.map(parenthesizeElementTypeMember)); } + export function parenthesizeTypeParameters(typeParameters: TypeNode[]) { + if (typeParameters && typeParameters.length > 0) { + const nodeArray = createNodeArray(typeParameters); + const firstEntry = nodeArray[0]; + if (isFunctionOrConstructor(firstEntry) && firstEntry.typeParameters) { + nodeArray[0] = createParenthesizedType(firstEntry); + } + + return nodeArray; + } + } + /** * Clones a series of not-emitted expressions with a new inner expression. * diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e7e6f9ad1a..cf204d158a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2590,25 +2590,20 @@ namespace ts { WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type) SuppressAnyReturnType = 1 << 8, // If the return type is any-like, don't offer a return type. + WriteTypeParametersInQualifiedName = 1 << 9, // Error handling AllowThisInObjectLiteral = 1 << 10, AllowQualifedNameInPlaceOfIdentifier = 1 << 11, - AllowTypeParameterInQualifiedName = 1 << 12, AllowAnonymousIdentifier = 1 << 13, AllowEmptyUnionOrIntersection = 1 << 14, AllowEmptyTuple = 1 << 15, - ignoreErrors = AllowThisInObjectLiteral | AllowQualifedNameInPlaceOfIdentifier | AllowTypeParameterInQualifiedName | AllowAnonymousIdentifier | AllowEmptyUnionOrIntersection | AllowEmptyTuple, + ignoreErrors = AllowThisInObjectLiteral | AllowQualifedNameInPlaceOfIdentifier | AllowAnonymousIdentifier | AllowEmptyUnionOrIntersection | AllowEmptyTuple, // State inObjectTypeLiteral = 1 << 20, - InElementType = 1 << 21, // Writing an array or union element type - InFirstTypeArgument = 1 << 22, // Writing first type argument of the instantiated type InTypeAlias = 1 << 23, // Writing type in type alias declaration - - /** Flags that should not be passed on to sub-nodes of the current node being built. */ - StateClearingFlags = InElementType | InFirstTypeArgument | InTypeAlias } export interface SymbolDisplayBuilder { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 825465085c..80daf38363 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -881,6 +881,16 @@ namespace ts { return false; } + export function isFunctionOrConstructor(node: Node): node is FunctionTypeNode | ConstructorTypeNode { + switch (node.kind) { + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + return true; + } + + return false; + } + export function introducesArgumentsExoticObject(node: Node) { switch (node.kind) { case SyntaxKind.MethodDeclaration: From 9ba0668afafdbfd6d2a0212f4a2861bdb7a2124a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 15 May 2017 10:20:28 -0700 Subject: [PATCH 59/83] Test:spread array after required params --- .../reference/callWithSpread2.errors.txt | 94 +++++++++++++++++++ tests/baselines/reference/callWithSpread2.js | 80 ++++++++++++++++ .../functionCalls/callWithSpread2.ts | 48 ++++++++++ 3 files changed, 222 insertions(+) create mode 100644 tests/baselines/reference/callWithSpread2.errors.txt create mode 100644 tests/baselines/reference/callWithSpread2.js create mode 100644 tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts diff --git a/tests/baselines/reference/callWithSpread2.errors.txt b/tests/baselines/reference/callWithSpread2.errors.txt new file mode 100644 index 0000000000..f12846ab1c --- /dev/null +++ b/tests/baselines/reference/callWithSpread2.errors.txt @@ -0,0 +1,94 @@ +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(40,5): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(41,5): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(42,13): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(43,13): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(44,11): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(45,11): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(46,1): error TS2346: Supplied parameters do not match any signature of call target. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(46,11): error TS2461: Type '(a?: number, b?: number) => void' is not an array type. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(47,1): error TS2346: Supplied parameters do not match any signature of call target. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(48,1): error TS2346: Supplied parameters do not match any signature of call target. + + +==== tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts (10 errors) ==== + // Desired semantics: take type of array that is spread, + // allow it to be applied to a + // *trailing* set of optional parameters whose types match. + // Length is *not* checked, the parameters it's applied to just have to be optional. + + // that means that tuples are non-starters because their array element type + // is a union like string | number. + + // with exceptions for JS functions that use arguments, or maybe all JS functions + + declare function all(a?: number, b?: number): void; + declare function weird(a?: number | string, b?: number | string): void; + declare function prefix(s: string, a?: number, b?: number): void; + declare function rest(s: string, a?: number, b?: number, ...rest: number[]): void; + declare function normal(s: string): void; + declare function thunk(): string; + + declare var ns: number[]; + declare var mixed: (number | string)[]; + declare var tuple: [number, string]; + + // good + all(...ns) + weird(...ns) + weird(...mixed) + weird(...tuple) + prefix("a", ...ns) + rest("d", ...ns) + + + // this covers the arguments case + normal("g", ...ns) + normal("h", ...mixed) + normal("i", ...tuple) + thunk(...ns) + thunk(...mixed) + thunk(...tuple) + + // bad + all(...mixed) + ~~~~~~~~ +!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +!!! error TS2345: Type 'string' is not assignable to type 'number'. + all(...tuple) + ~~~~~~~~ +!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +!!! error TS2345: Type 'string' is not assignable to type 'number'. + prefix("b", ...mixed) + ~~~~~~~~ +!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +!!! error TS2345: Type 'string' is not assignable to type 'number'. + prefix("c", ...tuple) + ~~~~~~~~ +!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +!!! error TS2345: Type 'string' is not assignable to type 'number'. + rest("e", ...mixed) + ~~~~~~~~ +!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +!!! error TS2345: Type 'string' is not assignable to type 'number'. + rest("f", ...tuple) + ~~~~~~~~ +!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +!!! error TS2345: Type 'string' is not assignable to type 'number'. + prefix(...all) // required parameters are required + ~~~~~~~~~~~~~~ +!!! error TS2346: Supplied parameters do not match any signature of call target. + ~~~ +!!! error TS2461: Type '(a?: number, b?: number) => void' is not an array type. + prefix(...mixed) + ~~~~~~~~~~~~~~~~ +!!! error TS2346: Supplied parameters do not match any signature of call target. + prefix(...tuple) + ~~~~~~~~~~~~~~~~ +!!! error TS2346: Supplied parameters do not match any signature of call target. + \ No newline at end of file diff --git a/tests/baselines/reference/callWithSpread2.js b/tests/baselines/reference/callWithSpread2.js new file mode 100644 index 0000000000..25ccc58209 --- /dev/null +++ b/tests/baselines/reference/callWithSpread2.js @@ -0,0 +1,80 @@ +//// [callWithSpread2.ts] +// Desired semantics: take type of array that is spread, +// allow it to be applied to a +// *trailing* set of optional parameters whose types match. +// Length is *not* checked, the parameters it's applied to just have to be optional. + +// that means that tuples are non-starters because their array element type +// is a union like string | number. + +// with exceptions for JS functions that use arguments, or maybe all JS functions + +declare function all(a?: number, b?: number): void; +declare function weird(a?: number | string, b?: number | string): void; +declare function prefix(s: string, a?: number, b?: number): void; +declare function rest(s: string, a?: number, b?: number, ...rest: number[]): void; +declare function normal(s: string): void; +declare function thunk(): string; + +declare var ns: number[]; +declare var mixed: (number | string)[]; +declare var tuple: [number, string]; + +// good +all(...ns) +weird(...ns) +weird(...mixed) +weird(...tuple) +prefix("a", ...ns) +rest("d", ...ns) + + +// this covers the arguments case +normal("g", ...ns) +normal("h", ...mixed) +normal("i", ...tuple) +thunk(...ns) +thunk(...mixed) +thunk(...tuple) + +// bad +all(...mixed) +all(...tuple) +prefix("b", ...mixed) +prefix("c", ...tuple) +rest("e", ...mixed) +rest("f", ...tuple) +prefix(...all) // required parameters are required +prefix(...mixed) +prefix(...tuple) + + +//// [callWithSpread2.js] +// Desired semantics: take type of array that is spread, +// allow it to be applied to a +// *trailing* set of optional parameters whose types match. +// Length is *not* checked, the parameters it's applied to just have to be optional. +// good +all.apply(void 0, ns); +weird.apply(void 0, ns); +weird.apply(void 0, mixed); +weird.apply(void 0, tuple); +prefix.apply(void 0, ["a"].concat(ns)); +rest.apply(void 0, ["d"].concat(ns)); +// this covers the arguments case +normal.apply(void 0, ["g"].concat(ns)); +normal.apply(void 0, ["h"].concat(mixed)); +normal.apply(void 0, ["i"].concat(tuple)); +thunk.apply(void 0, ns); +thunk.apply(void 0, mixed); +thunk.apply(void 0, tuple); +// bad +all.apply(void 0, mixed); +all.apply(void 0, tuple); +prefix.apply(void 0, ["b"].concat(mixed)); +prefix.apply(void 0, ["c"].concat(tuple)); +rest.apply(void 0, ["e"].concat(mixed)); +rest.apply(void 0, ["f"].concat(tuple)); +prefix.apply(void 0, all); // required parameters are required +prefix.apply(void 0, mixed); +prefix.apply(void 0, tuple); diff --git a/tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts b/tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts new file mode 100644 index 0000000000..72ff97f7c9 --- /dev/null +++ b/tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts @@ -0,0 +1,48 @@ +// Desired semantics: take type of array that is spread, +// allow it to be applied to a +// *trailing* set of optional parameters whose types match. +// Length is *not* checked, the parameters it's applied to just have to be optional. + +// that means that tuples are non-starters because their array element type +// is a union like string | number. + +// with exceptions for JS functions that use arguments, or maybe all JS functions + +declare function all(a?: number, b?: number): void; +declare function weird(a?: number | string, b?: number | string): void; +declare function prefix(s: string, a?: number, b?: number): void; +declare function rest(s: string, a?: number, b?: number, ...rest: number[]): void; +declare function normal(s: string): void; +declare function thunk(): string; + +declare var ns: number[]; +declare var mixed: (number | string)[]; +declare var tuple: [number, string]; + +// good +all(...ns) +weird(...ns) +weird(...mixed) +weird(...tuple) +prefix("a", ...ns) +rest("d", ...ns) + + +// this covers the arguments case +normal("g", ...ns) +normal("h", ...mixed) +normal("i", ...tuple) +thunk(...ns) +thunk(...mixed) +thunk(...tuple) + +// bad +all(...mixed) +all(...tuple) +prefix("b", ...mixed) +prefix("c", ...tuple) +rest("e", ...mixed) +rest("f", ...tuple) +prefix(...all) // required parameters are required +prefix(...mixed) +prefix(...tuple) From b61eaf70a1587ad0d171ec3141ad90fe1a34d764 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 15 May 2017 10:31:47 -0700 Subject: [PATCH 60/83] Inline function that is called once --- src/compiler/checker.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6c68df7c0c..9e6a5f946b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9598,10 +9598,6 @@ namespace ts { return signature.hasRestParameter && parameterIndex >= signature.parameters.length - 1; } - function areAllParametersOptionalAfter(signature: Signature, parameterIndex: number) { - return parameterIndex >= signature.minArgumentCount; - } - function isSupertypeOfEach(candidate: Type, types: Type[]): boolean { for (const t of types) { if (candidate !== t && !isTypeSubtypeOf(t, candidate)) return false; @@ -14653,7 +14649,7 @@ namespace ts { // If spread arguments are present, check that they correspond to a rest parameter. If so, no // further checking is necessary. if (spreadArgIndex >= 0) { - return isRestParameterIndex(signature, spreadArgIndex) || areAllParametersOptionalAfter(signature, spreadArgIndex); + return isRestParameterIndex(signature, spreadArgIndex) || spreadArgIndex >= signature.minArgumentCount; } // Too many arguments implies incorrect arity. From 4c80aa17b3e1f04283f821638b90f6daf679b237 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 15 May 2017 10:38:51 -0700 Subject: [PATCH 61/83] Clean up comments in tests --- .../reference/callWithSpread2.errors.txt | 30 +++++++------------ tests/baselines/reference/callWithSpread2.js | 14 --------- .../functionCalls/callWithSpread2.ts | 10 ------- 3 files changed, 10 insertions(+), 44 deletions(-) diff --git a/tests/baselines/reference/callWithSpread2.errors.txt b/tests/baselines/reference/callWithSpread2.errors.txt index f12846ab1c..770e33c9ae 100644 --- a/tests/baselines/reference/callWithSpread2.errors.txt +++ b/tests/baselines/reference/callWithSpread2.errors.txt @@ -1,32 +1,22 @@ -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(40,5): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(30,5): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(41,5): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(31,5): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(42,13): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(32,13): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(43,13): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(33,13): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(44,11): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(34,11): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(45,11): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(35,11): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(46,1): error TS2346: Supplied parameters do not match any signature of call target. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(46,11): error TS2461: Type '(a?: number, b?: number) => void' is not an array type. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(47,1): error TS2346: Supplied parameters do not match any signature of call target. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(48,1): error TS2346: Supplied parameters do not match any signature of call target. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(36,1): error TS2346: Supplied parameters do not match any signature of call target. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(36,11): error TS2461: Type '(a?: number, b?: number) => void' is not an array type. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(37,1): error TS2346: Supplied parameters do not match any signature of call target. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(38,1): error TS2346: Supplied parameters do not match any signature of call target. ==== tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts (10 errors) ==== - // Desired semantics: take type of array that is spread, - // allow it to be applied to a - // *trailing* set of optional parameters whose types match. - // Length is *not* checked, the parameters it's applied to just have to be optional. - - // that means that tuples are non-starters because their array element type - // is a union like string | number. - - // with exceptions for JS functions that use arguments, or maybe all JS functions - declare function all(a?: number, b?: number): void; declare function weird(a?: number | string, b?: number | string): void; declare function prefix(s: string, a?: number, b?: number): void; diff --git a/tests/baselines/reference/callWithSpread2.js b/tests/baselines/reference/callWithSpread2.js index 25ccc58209..0380c69f80 100644 --- a/tests/baselines/reference/callWithSpread2.js +++ b/tests/baselines/reference/callWithSpread2.js @@ -1,14 +1,4 @@ //// [callWithSpread2.ts] -// Desired semantics: take type of array that is spread, -// allow it to be applied to a -// *trailing* set of optional parameters whose types match. -// Length is *not* checked, the parameters it's applied to just have to be optional. - -// that means that tuples are non-starters because their array element type -// is a union like string | number. - -// with exceptions for JS functions that use arguments, or maybe all JS functions - declare function all(a?: number, b?: number): void; declare function weird(a?: number | string, b?: number | string): void; declare function prefix(s: string, a?: number, b?: number): void; @@ -50,10 +40,6 @@ prefix(...tuple) //// [callWithSpread2.js] -// Desired semantics: take type of array that is spread, -// allow it to be applied to a -// *trailing* set of optional parameters whose types match. -// Length is *not* checked, the parameters it's applied to just have to be optional. // good all.apply(void 0, ns); weird.apply(void 0, ns); diff --git a/tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts b/tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts index 72ff97f7c9..07441dc74b 100644 --- a/tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts +++ b/tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts @@ -1,13 +1,3 @@ -// Desired semantics: take type of array that is spread, -// allow it to be applied to a -// *trailing* set of optional parameters whose types match. -// Length is *not* checked, the parameters it's applied to just have to be optional. - -// that means that tuples are non-starters because their array element type -// is a union like string | number. - -// with exceptions for JS functions that use arguments, or maybe all JS functions - declare function all(a?: number, b?: number): void; declare function weird(a?: number | string, b?: number | string): void; declare function prefix(s: string, a?: number, b?: number): void; From cefcc668a881a52b71db6e601ba70c00f1c36332 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 15 May 2017 10:55:58 -0700 Subject: [PATCH 62/83] Correct test argument in callwithSpread2 --- tests/baselines/reference/callWithSpread2.errors.txt | 9 +++------ tests/baselines/reference/callWithSpread2.js | 4 ++-- .../expressions/functionCalls/callWithSpread2.ts | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/baselines/reference/callWithSpread2.errors.txt b/tests/baselines/reference/callWithSpread2.errors.txt index 770e33c9ae..cfea427a2a 100644 --- a/tests/baselines/reference/callWithSpread2.errors.txt +++ b/tests/baselines/reference/callWithSpread2.errors.txt @@ -11,12 +11,11 @@ tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(34,11): err tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(35,11): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(36,1): error TS2346: Supplied parameters do not match any signature of call target. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(36,11): error TS2461: Type '(a?: number, b?: number) => void' is not an array type. tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(37,1): error TS2346: Supplied parameters do not match any signature of call target. tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(38,1): error TS2346: Supplied parameters do not match any signature of call target. -==== tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts (10 errors) ==== +==== tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts (9 errors) ==== declare function all(a?: number, b?: number): void; declare function weird(a?: number | string, b?: number | string): void; declare function prefix(s: string, a?: number, b?: number): void; @@ -70,11 +69,9 @@ tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(38,1): erro ~~~~~~~~ !!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. !!! error TS2345: Type 'string' is not assignable to type 'number'. - prefix(...all) // required parameters are required - ~~~~~~~~~~~~~~ + prefix(...ns) // required parameters are required + ~~~~~~~~~~~~~ !!! error TS2346: Supplied parameters do not match any signature of call target. - ~~~ -!!! error TS2461: Type '(a?: number, b?: number) => void' is not an array type. prefix(...mixed) ~~~~~~~~~~~~~~~~ !!! error TS2346: Supplied parameters do not match any signature of call target. diff --git a/tests/baselines/reference/callWithSpread2.js b/tests/baselines/reference/callWithSpread2.js index 0380c69f80..55296d924f 100644 --- a/tests/baselines/reference/callWithSpread2.js +++ b/tests/baselines/reference/callWithSpread2.js @@ -34,7 +34,7 @@ prefix("b", ...mixed) prefix("c", ...tuple) rest("e", ...mixed) rest("f", ...tuple) -prefix(...all) // required parameters are required +prefix(...ns) // required parameters are required prefix(...mixed) prefix(...tuple) @@ -61,6 +61,6 @@ prefix.apply(void 0, ["b"].concat(mixed)); prefix.apply(void 0, ["c"].concat(tuple)); rest.apply(void 0, ["e"].concat(mixed)); rest.apply(void 0, ["f"].concat(tuple)); -prefix.apply(void 0, all); // required parameters are required +prefix.apply(void 0, ns); // required parameters are required prefix.apply(void 0, mixed); prefix.apply(void 0, tuple); diff --git a/tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts b/tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts index 07441dc74b..9151f52f00 100644 --- a/tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts +++ b/tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts @@ -33,6 +33,6 @@ prefix("b", ...mixed) prefix("c", ...tuple) rest("e", ...mixed) rest("f", ...tuple) -prefix(...all) // required parameters are required +prefix(...ns) // required parameters are required prefix(...mixed) prefix(...tuple) From d8f29a5fe8b918c2a48e7b745117de3c66b5a827 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 15 May 2017 12:42:28 -0700 Subject: [PATCH 63/83] update tests --- ...assImplementInterfaceMemberNestedTypeAlias.ts | 16 ++++++++++++++++ ...eFixClassImplementInterfaceMemberTypeAlias.ts | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 tests/cases/fourslash/codeFixClassImplementInterfaceMemberNestedTypeAlias.ts diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceMemberNestedTypeAlias.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceMemberNestedTypeAlias.ts new file mode 100644 index 0000000000..5aa5f1a4e5 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceMemberNestedTypeAlias.ts @@ -0,0 +1,16 @@ +/// + +//// type Either = { val: T } | Error; +//// interface I { +//// x: Either>; +//// foo(x: Either>): void; +//// } +//// class C implements I {[| |]} + +verify.rangeAfterCodeFix(` + x: Either>; + foo(x: Either>): void { + throw new Error("Method not implemented."); + } +`); + diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts index f7dfd5e178..44981302a1 100644 --- a/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceMemberTypeAlias.ts @@ -1,12 +1,12 @@ /// //// type MyType = [string, number]; -//// interface I { test(a: MyType): void; } +//// interface I { x: MyType; test(a: MyType): void; } //// class C implements I {[| |]} verify.rangeAfterCodeFix(` + x: [string, number]; test(a: [string, number]): void { throw new Error("Method not implemented."); } `); - From 4d028a81eeb8909f2be3a89fa14e8291199b656c Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 15 May 2017 15:10:52 -0700 Subject: [PATCH 64/83] getTokenAtPositionWorker: Remove duplicate loop --- src/services/utilities.ts | 48 ++++++++++++--------------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 4ae9204f7e..e452d18de4 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -651,44 +651,26 @@ namespace ts { return current; } - if (includeJsDocComment) { - const jsDocChildren = ts.filter(current.getChildren(), isJSDocNode); - for (const jsDocChild of jsDocChildren) { - const start = allowPositionInLeadingTrivia ? jsDocChild.getFullStart() : jsDocChild.getStart(sourceFile, includeJsDocComment); - if (start <= position) { - const end = jsDocChild.getEnd(); - if (position < end || (position === end && jsDocChild.kind === SyntaxKind.EndOfFileToken)) { - current = jsDocChild; - continue outer; - } - else if (includeItemAtEndPosition && end === position) { - const previousToken = findPrecedingToken(position, sourceFile, jsDocChild); - if (previousToken && includeItemAtEndPosition(previousToken)) { - return previousToken; - } - } - } - } - } - // find the child that contains 'position' for (const child of current.getChildren()) { - // all jsDocComment nodes were already visited - if (isJSDocNode(child)) { + if (isJSDocNode(child) && !includeJsDocComment) { continue; } + const start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile, includeJsDocComment); - if (start <= position) { - const end = child.getEnd(); - if (position < end || (position === end && child.kind === SyntaxKind.EndOfFileToken)) { - current = child; - continue outer; - } - else if (includeItemAtEndPosition && end === position) { - const previousToken = findPrecedingToken(position, sourceFile, child); - if (previousToken && includeItemAtEndPosition(previousToken)) { - return previousToken; - } + if (start > position) { + break; + } + + const end = child.getEnd(); + if (position < end || (position === end && child.kind === SyntaxKind.EndOfFileToken)) { + current = child; + continue outer; + } + else if (includeItemAtEndPosition && end === position) { + const previousToken = findPrecedingToken(position, sourceFile, child); + if (previousToken && includeItemAtEndPosition(previousToken)) { + return previousToken; } } } From 05d2f2d5d9c88a28f86d48a6d8ee49f5cdf28a3b Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 15 May 2017 15:28:55 -0700 Subject: [PATCH 65/83] Fix issue with throw in async delegator. --- src/compiler/transformers/esnext.ts | 4 ++-- .../emitter.asyncGenerators.classMethods.es2015.js | 8 ++++---- .../reference/emitter.asyncGenerators.classMethods.es5.js | 8 ++++---- ...emitter.asyncGenerators.functionDeclarations.es2015.js | 8 ++++---- .../emitter.asyncGenerators.functionDeclarations.es5.js | 8 ++++---- .../emitter.asyncGenerators.functionExpressions.es2015.js | 8 ++++---- .../emitter.asyncGenerators.functionExpressions.es5.js | 8 ++++---- ...emitter.asyncGenerators.objectLiteralMethods.es2015.js | 8 ++++---- .../emitter.asyncGenerators.objectLiteralMethods.es5.js | 8 ++++---- 9 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index fef1b009ba..81ebd0b8f5 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -929,8 +929,8 @@ namespace ts { text: ` var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; ` }; diff --git a/tests/baselines/reference/emitter.asyncGenerators.classMethods.es2015.js b/tests/baselines/reference/emitter.asyncGenerators.classMethods.es2015.js index 5f1b97b208..d91571f93a 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.classMethods.es2015.js +++ b/tests/baselines/reference/emitter.asyncGenerators.classMethods.es2015.js @@ -128,8 +128,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); @@ -169,8 +169,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { }; var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; class C5 { f() { diff --git a/tests/baselines/reference/emitter.asyncGenerators.classMethods.es5.js b/tests/baselines/reference/emitter.asyncGenerators.classMethods.es5.js index 1fa1b19e36..cfd7c9725e 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.classMethods.es5.js +++ b/tests/baselines/reference/emitter.asyncGenerators.classMethods.es5.js @@ -264,8 +264,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); @@ -354,8 +354,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { }; var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __values = (this && this.__values) || function (o) { var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; diff --git a/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es2015.js b/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es2015.js index 98e8291ac6..4ca8322da9 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es2015.js +++ b/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es2015.js @@ -91,8 +91,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); @@ -130,8 +130,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { }; var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; function f5() { return __asyncGenerator(this, arguments, function* f5_1() { diff --git a/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es5.js b/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es5.js index f842a2c813..410a25d2e1 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es5.js +++ b/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es5.js @@ -218,8 +218,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); @@ -303,8 +303,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { }; var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __values = (this && this.__values) || function (o) { var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; diff --git a/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es2015.js b/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es2015.js index d491c0465f..602fd47d38 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es2015.js +++ b/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es2015.js @@ -91,8 +91,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); @@ -130,8 +130,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { }; var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; const f5 = function () { return __asyncGenerator(this, arguments, function* () { diff --git a/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es5.js b/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es5.js index 779d9c5340..45d17737ce 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es5.js +++ b/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es5.js @@ -218,8 +218,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); @@ -303,8 +303,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { }; var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __values = (this && this.__values) || function (o) { var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; diff --git a/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es2015.js b/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es2015.js index 22ffff01ee..760931a434 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es2015.js +++ b/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es2015.js @@ -111,8 +111,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); @@ -152,8 +152,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { }; var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; const o5 = { f() { diff --git a/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es5.js b/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es5.js index 46f3a1efac..b5069bcea2 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es5.js +++ b/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es5.js @@ -238,8 +238,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); @@ -325,8 +325,8 @@ var __asyncValues = (this && this.__asyncIterator) || function (o) { }; var __asyncDelegator = (this && this.__asyncDelegator) || function (o) { var i, p; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; } + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; } }; var __values = (this && this.__values) || function (o) { var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; From e9ccb1664263c88702cf8223ce3dd73f7dfd4751 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 15 May 2017 15:32:14 -0700 Subject: [PATCH 66/83] Eliminate redundant exploration in type inference --- src/compiler/checker.ts | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d6f56a69b9..26cdab1e59 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10096,21 +10096,29 @@ namespace ts { inferTypes(context.signature.typeParameters, context.inferences, originalSource, originalTarget); } + function getSymbolForInference(type: Type) { + // Exclude the static side of classes since it shares its symbol with the instance side which leads + // to false positives. + return type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class) ? type.symbol : undefined; + } + function inferTypes(typeVariables: TypeVariable[], typeInferences: TypeInferences[], originalSource: Type, originalTarget: Type) { - let sourceStack: Type[]; - let targetStack: Type[]; + let stack: Type[]; let depth = 0; let inferiority = 0; const visited = createMap(); inferFromTypes(originalSource, originalTarget); - function isInProcess(source: Type, target: Type) { - for (let i = 0; i < depth; i++) { - if (source === sourceStack[i] && target === targetStack[i]) { - return true; + function isInstantiationInProcess(type: Type) { + const symbol = getSymbolForInference(type); + if (symbol) { + for (let i = 0; i < depth; i++) { + const t = stack[i]; + if (getSymbolForInference(t) === symbol) { + return true; + } } } - return false; } function inferFromTypes(source: Type, target: Type) { @@ -10240,10 +10248,10 @@ namespace ts { else { source = getApparentType(source); if (source.flags & TypeFlags.Object) { - if (isInProcess(source, target)) { - return; - } - if (isDeeplyNestedType(source, sourceStack, depth) && isDeeplyNestedType(target, targetStack, depth)) { + // If we are already processing another target type with the same associated symbol (such as + // an instantiation of the same generic type), we do not explore this target as it would yield + // no further inferences. + if (isInstantiationInProcess(target)) { return; } const key = source.id + "," + target.id; @@ -10251,12 +10259,7 @@ namespace ts { return; } visited.set(key, true); - if (depth === 0) { - sourceStack = []; - targetStack = []; - } - sourceStack[depth] = source; - targetStack[depth] = target; + (stack || (stack = []))[depth] = target; depth++; inferFromObjectTypes(source, target); depth--; From d51e467238db9229ca0620607067c083aee07cc3 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Mon, 15 May 2017 15:46:50 -0700 Subject: [PATCH 67/83] Fix #15463: use intersection types to emulate spread in generic react components (#15851) * Fix #15463: use intersection types to emulate spread in generic react components * Fix lint errors * reverse condition --- src/compiler/checker.ts | 18 ++++++-- .../tsxAttributeResolution5.errors.txt | 24 ++++++----- .../reference/tsxGenericAttributesType9.js | 40 ++++++++++++++++++ .../tsxGenericAttributesType9.symbols | 37 +++++++++++++++++ .../reference/tsxGenericAttributesType9.types | 41 +++++++++++++++++++ ...ionComponentsWithTypeArguments2.errors.txt | 18 ++++---- ...ionComponentsWithTypeArguments4.errors.txt | 18 +++++--- ...ionComponentsWithTypeArguments5.errors.txt | 12 +++++- .../jsx/tsxGenericAttributesType9.tsx | 16 ++++++++ tests/cases/fourslash/tsxQuickInfo6.ts | 2 +- tests/cases/fourslash/tsxQuickInfo7.ts | 4 +- 11 files changed, 197 insertions(+), 33 deletions(-) create mode 100644 tests/baselines/reference/tsxGenericAttributesType9.js create mode 100644 tests/baselines/reference/tsxGenericAttributesType9.symbols create mode 100644 tests/baselines/reference/tsxGenericAttributesType9.types create mode 100644 tests/cases/conformance/jsx/tsxGenericAttributesType9.tsx diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d6f56a69b9..a2a31e3a19 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13314,6 +13314,7 @@ namespace ts { let spread: Type = emptyObjectType; let attributesArray: Symbol[] = []; let hasSpreadAnyType = false; + let typeToIntersect: Type; let explicitlySpecifyChildrenAttribute = false; const jsxChildrenPropertyName = getJsxElementChildrenPropertyname(); @@ -13345,11 +13346,16 @@ namespace ts { attributesArray = []; attributesTable = createMap(); } - const exprType = getApparentType(checkExpression(attributeDecl.expression)); + const exprType = checkExpression(attributeDecl.expression); if (isTypeAny(exprType)) { hasSpreadAnyType = true; } - spread = getSpreadType(spread, exprType); + if (isValidSpreadType(exprType)) { + spread = getSpreadType(spread, exprType); + } + else { + typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType; + } } } @@ -13404,7 +13410,13 @@ namespace ts { } } - return hasSpreadAnyType ? anyType : createJsxAttributesType(attributes.symbol, attributesTable); + if (hasSpreadAnyType) { + return anyType; + } + + const attributeType = createJsxAttributesType(attributes.symbol, attributesTable); + return typeToIntersect && attributesTable.size ? getIntersectionType([typeToIntersect, attributeType]) : + typeToIntersect ? typeToIntersect : attributeType; /** * Create anonymous type from given attributes symbol table. diff --git a/tests/baselines/reference/tsxAttributeResolution5.errors.txt b/tests/baselines/reference/tsxAttributeResolution5.errors.txt index 0c6be5f35d..f5af99d6f0 100644 --- a/tests/baselines/reference/tsxAttributeResolution5.errors.txt +++ b/tests/baselines/reference/tsxAttributeResolution5.errors.txt @@ -1,8 +1,10 @@ -tests/cases/conformance/jsx/file.tsx(21,16): error TS2322: Type '{ x: number; }' is not assignable to type 'Attribs1'. - Types of property 'x' are incompatible. - Type 'number' is not assignable to type 'string'. -tests/cases/conformance/jsx/file.tsx(25,16): error TS2322: Type '{ y: string; }' is not assignable to type 'Attribs1'. - Property 'x' is missing in type '{ y: string; }'. +tests/cases/conformance/jsx/file.tsx(21,16): error TS2322: Type 'T' is not assignable to type 'Attribs1'. + Type '{ x: number; }' is not assignable to type 'Attribs1'. + Types of property 'x' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/jsx/file.tsx(25,16): error TS2322: Type 'T' is not assignable to type 'Attribs1'. + Type '{ y: string; }' is not assignable to type 'Attribs1'. + Property 'x' is missing in type '{ y: string; }'. tests/cases/conformance/jsx/file.tsx(29,8): error TS2322: Type '{}' is not assignable to type 'Attribs1'. Property 'x' is missing in type '{}'. @@ -30,16 +32,18 @@ tests/cases/conformance/jsx/file.tsx(29,8): error TS2322: Type '{}' is not assig function make2 (obj: T) { return ; // Error (x is number, not string) ~~~~~~~~ -!!! error TS2322: Type '{ x: number; }' is not assignable to type 'Attribs1'. -!!! error TS2322: Types of property 'x' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! error TS2322: Type 'T' is not assignable to type 'Attribs1'. +!!! error TS2322: Type '{ x: number; }' is not assignable to type 'Attribs1'. +!!! error TS2322: Types of property 'x' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. } function make3 (obj: T) { return ; // Error, missing x ~~~~~~~~ -!!! error TS2322: Type '{ y: string; }' is not assignable to type 'Attribs1'. -!!! error TS2322: Property 'x' is missing in type '{ y: string; }'. +!!! error TS2322: Type 'T' is not assignable to type 'Attribs1'. +!!! error TS2322: Type '{ y: string; }' is not assignable to type 'Attribs1'. +!!! error TS2322: Property 'x' is missing in type '{ y: string; }'. } diff --git a/tests/baselines/reference/tsxGenericAttributesType9.js b/tests/baselines/reference/tsxGenericAttributesType9.js new file mode 100644 index 0000000000..b7b90736ad --- /dev/null +++ b/tests/baselines/reference/tsxGenericAttributesType9.js @@ -0,0 +1,40 @@ +//// [file.tsx] +import React = require('react'); + +export function makeP

(Ctor: React.ComponentClass

): React.ComponentClass

{ + return class extends React.PureComponent { + public render(): JSX.Element { + return ( + + ); + } + }; +} + +//// [file.jsx] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +var React = require("react"); +function makeP(Ctor) { + return (function (_super) { + __extends(class_1, _super); + function class_1() { + return _super !== null && _super.apply(this, arguments) || this; + } + class_1.prototype.render = function () { + return (); + }; + return class_1; + }(React.PureComponent)); +} +exports.makeP = makeP; diff --git a/tests/baselines/reference/tsxGenericAttributesType9.symbols b/tests/baselines/reference/tsxGenericAttributesType9.symbols new file mode 100644 index 0000000000..f4df2e7940 --- /dev/null +++ b/tests/baselines/reference/tsxGenericAttributesType9.symbols @@ -0,0 +1,37 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react'); +>React : Symbol(React, Decl(file.tsx, 0, 0)) + +export function makeP

(Ctor: React.ComponentClass

): React.ComponentClass

{ +>makeP : Symbol(makeP, Decl(file.tsx, 0, 32)) +>P : Symbol(P, Decl(file.tsx, 2, 22)) +>Ctor : Symbol(Ctor, Decl(file.tsx, 2, 25)) +>React : Symbol(React, Decl(file.tsx, 0, 0)) +>ComponentClass : Symbol(React.ComponentClass, Decl(react.d.ts, 204, 5)) +>P : Symbol(P, Decl(file.tsx, 2, 22)) +>React : Symbol(React, Decl(file.tsx, 0, 0)) +>ComponentClass : Symbol(React.ComponentClass, Decl(react.d.ts, 204, 5)) +>P : Symbol(P, Decl(file.tsx, 2, 22)) + + return class extends React.PureComponent { +>React.PureComponent : Symbol(React.PureComponent, Decl(react.d.ts, 179, 5)) +>React : Symbol(React, Decl(file.tsx, 0, 0)) +>PureComponent : Symbol(React.PureComponent, Decl(react.d.ts, 179, 5)) +>P : Symbol(P, Decl(file.tsx, 2, 22)) + + public render(): JSX.Element { +>render : Symbol((Anonymous class).render, Decl(file.tsx, 3, 52)) +>JSX : Symbol(JSX, Decl(react.d.ts, 2352, 1)) +>Element : Symbol(JSX.Element, Decl(react.d.ts, 2355, 27)) + + return ( + +>Ctor : Symbol(Ctor, Decl(file.tsx, 2, 25)) +>this.props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37)) +>this : Symbol((Anonymous class), Decl(file.tsx, 3, 7)) +>props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37)) + + ); + } + }; +} diff --git a/tests/baselines/reference/tsxGenericAttributesType9.types b/tests/baselines/reference/tsxGenericAttributesType9.types new file mode 100644 index 0000000000..a1d7efc49b --- /dev/null +++ b/tests/baselines/reference/tsxGenericAttributesType9.types @@ -0,0 +1,41 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react'); +>React : typeof React + +export function makeP

(Ctor: React.ComponentClass

): React.ComponentClass

{ +>makeP :

(Ctor: React.ComponentClass

) => React.ComponentClass

+>P : P +>Ctor : React.ComponentClass

+>React : any +>ComponentClass : React.ComponentClass

+>P : P +>React : any +>ComponentClass : React.ComponentClass

+>P : P + + return class extends React.PureComponent { +>class extends React.PureComponent { public render(): JSX.Element { return ( ); } } : typeof (Anonymous class) +>React.PureComponent : React.PureComponent +>React : typeof React +>PureComponent : typeof React.PureComponent +>P : P + + public render(): JSX.Element { +>render : () => JSX.Element +>JSX : any +>Element : JSX.Element + + return ( +>( ) : JSX.Element + + +> : JSX.Element +>Ctor : React.ComponentClass

+>this.props : P & { children?: React.ReactNode; } +>this : this +>props : P & { children?: React.ReactNode; } + + ); + } + }; +} diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments2.errors.txt b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments2.errors.txt index c8ff457711..7e94011688 100644 --- a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments2.errors.txt +++ b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments2.errors.txt @@ -1,10 +1,9 @@ -tests/cases/conformance/jsx/file.tsx(8,34): error TS2322: Type '{ ignore-prop: 10; prop: number; }' is not assignable to type 'IntrinsicAttributes & { prop: number; "ignore-prop": string; }'. - Type '{ ignore-prop: 10; prop: number; }' is not assignable to type '{ prop: number; "ignore-prop": string; }'. +tests/cases/conformance/jsx/file.tsx(8,34): error TS2322: Type 'T & { ignore-prop: 10; }' is not assignable to type 'IntrinsicAttributes & { prop: number; "ignore-prop": string; }'. + Type 'T & { ignore-prop: 10; }' is not assignable to type '{ prop: number; "ignore-prop": string; }'. Types of property '"ignore-prop"' are incompatible. Type '10' is not assignable to type 'string'. -tests/cases/conformance/jsx/file.tsx(13,34): error TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & { prop: {}; "ignore-prop": string; }'. - Type '{}' is not assignable to type '{ prop: {}; "ignore-prop": string; }'. - Property 'prop' is missing in type '{}'. +tests/cases/conformance/jsx/file.tsx(13,34): error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { prop: {}; "ignore-prop": string; }'. + Type 'T' is not assignable to type '{ prop: {}; "ignore-prop": string; }'. tests/cases/conformance/jsx/file.tsx(20,19): error TS2322: Type '{ func: (a: number, b: string) => void; }' is not assignable to type 'IntrinsicAttributes & { func: (arg: number) => void; }'. Type '{ func: (a: number, b: string) => void; }' is not assignable to type '{ func: (arg: number) => void; }'. Types of property 'func' are incompatible. @@ -25,8 +24,8 @@ tests/cases/conformance/jsx/file.tsx(31,10): error TS2453: The type argument for function Bar(arg: T) { let a1 = ; ~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ ignore-prop: 10; prop: number; }' is not assignable to type 'IntrinsicAttributes & { prop: number; "ignore-prop": string; }'. -!!! error TS2322: Type '{ ignore-prop: 10; prop: number; }' is not assignable to type '{ prop: number; "ignore-prop": string; }'. +!!! error TS2322: Type 'T & { ignore-prop: 10; }' is not assignable to type 'IntrinsicAttributes & { prop: number; "ignore-prop": string; }'. +!!! error TS2322: Type 'T & { ignore-prop: 10; }' is not assignable to type '{ prop: number; "ignore-prop": string; }'. !!! error TS2322: Types of property '"ignore-prop"' are incompatible. !!! error TS2322: Type '10' is not assignable to type 'string'. } @@ -35,9 +34,8 @@ tests/cases/conformance/jsx/file.tsx(31,10): error TS2453: The type argument for function Baz(arg: T) { let a0 = ~~~~~~~~ -!!! error TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & { prop: {}; "ignore-prop": string; }'. -!!! error TS2322: Type '{}' is not assignable to type '{ prop: {}; "ignore-prop": string; }'. -!!! error TS2322: Property 'prop' is missing in type '{}'. +!!! error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { prop: {}; "ignore-prop": string; }'. +!!! error TS2322: Type 'T' is not assignable to type '{ prop: {}; "ignore-prop": string; }'. } declare function Link(l: {func: (arg: U)=>void}): JSX.Element; diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments4.errors.txt b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments4.errors.txt index d9b50ef31c..311cfaed86 100644 --- a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments4.errors.txt +++ b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments4.errors.txt @@ -1,9 +1,12 @@ tests/cases/conformance/jsx/file.tsx(9,33): error TS2322: Type '{ a: number; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: number; }'. Type '{ a: number; }' is not assignable to type '{ b: {}; a: number; }'. Property 'b' is missing in type '{ a: number; }'. -tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'. - Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'. - Property 'a' is missing in type '{ b: number; }'. +tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'. + Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'. + Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'. + Type 'T' is not assignable to type '{ b: number; a: {}; }'. + Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'. + Property 'a' is missing in type '{ b: number; }'. ==== tests/cases/conformance/jsx/file.tsx (2 errors) ==== @@ -22,7 +25,10 @@ tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type '{ b: number; }' !!! error TS2322: Property 'b' is missing in type '{ a: number; }'. let a2 = // missing a ~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'. -!!! error TS2322: Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'. -!!! error TS2322: Property 'a' is missing in type '{ b: number; }'. +!!! error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'. +!!! error TS2322: Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'. +!!! error TS2322: Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'. +!!! error TS2322: Type 'T' is not assignable to type '{ b: number; a: {}; }'. +!!! error TS2322: Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'. +!!! error TS2322: Property 'a' is missing in type '{ b: number; }'. } \ No newline at end of file diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments5.errors.txt b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments5.errors.txt index b92375797e..57a2ae556f 100644 --- a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments5.errors.txt +++ b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments5.errors.txt @@ -1,7 +1,11 @@ +tests/cases/conformance/jsx/file.tsx(15,14): error TS2605: JSX element type 'Element' is not a constructor function for JSX elements. + Property 'render' is missing in type 'Element'. +tests/cases/conformance/jsx/file.tsx(15,15): error TS2453: The type argument for type parameter 'U' cannot be inferred from the usage. Consider specifying the type arguments explicitly. + Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate '"hello"'. tests/cases/conformance/jsx/file.tsx(16,42): error TS2339: Property 'prop1' does not exist on type 'IntrinsicAttributes & { prop: number; }'. -==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== +==== tests/cases/conformance/jsx/file.tsx (3 errors) ==== import React = require('react') declare function Component(l: U): JSX.Element; @@ -17,6 +21,12 @@ tests/cases/conformance/jsx/file.tsx(16,42): error TS2339: Property 'prop1' does let a1 = ; // U is number let a2 = ; // U is number let a3 = ; // U is "hello" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2605: JSX element type 'Element' is not a constructor function for JSX elements. +!!! error TS2605: Property 'render' is missing in type 'Element'. + ~~~~~~~~~~~~~~~~~ +!!! error TS2453: The type argument for type parameter 'U' cannot be inferred from the usage. Consider specifying the type arguments explicitly. +!!! error TS2453: Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate '"hello"'. let a4 = ; // U is "hello" ~~~~~~~~~~~~~ !!! error TS2339: Property 'prop1' does not exist on type 'IntrinsicAttributes & { prop: number; }'. diff --git a/tests/cases/conformance/jsx/tsxGenericAttributesType9.tsx b/tests/cases/conformance/jsx/tsxGenericAttributesType9.tsx new file mode 100644 index 0000000000..a9466a4398 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxGenericAttributesType9.tsx @@ -0,0 +1,16 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +export function makeP

(Ctor: React.ComponentClass

): React.ComponentClass

{ + return class extends React.PureComponent { + public render(): JSX.Element { + return ( + + ); + } + }; +} \ No newline at end of file diff --git a/tests/cases/fourslash/tsxQuickInfo6.ts b/tests/cases/fourslash/tsxQuickInfo6.ts index 88d9435e80..2b65dc7667 100644 --- a/tests/cases/fourslash/tsxQuickInfo6.ts +++ b/tests/cases/fourslash/tsxQuickInfo6.ts @@ -15,5 +15,5 @@ verify.quickInfos({ 1: "function ComponentSpecific(l: {\n prop: number;\n}): any", - 2: "function ComponentSpecific<\"hello\">(l: {\n prop: \"hello\";\n}): any" + 2: "function ComponentSpecific(l: {\n prop: U;\n}): any" }); diff --git a/tests/cases/fourslash/tsxQuickInfo7.ts b/tests/cases/fourslash/tsxQuickInfo7.ts index 3e66fb655f..cf08aa53e9 100644 --- a/tests/cases/fourslash/tsxQuickInfo7.ts +++ b/tests/cases/fourslash/tsxQuickInfo7.ts @@ -24,6 +24,6 @@ verify.quickInfos({ 3: "function OverloadComponent(attr: {\n b: string;\n a: boolean;\n}): any (+2 overloads)", 4: "function OverloadComponent(attr: {\n b: number;\n a?: string;\n \"ignore-prop\": boolean;\n}): any (+2 overloads)", 5: "function OverloadComponent(): any (+2 overloads)", - 6: "function OverloadComponent(attr: {\n b: number;\n a: boolean;\n}): any (+2 overloads)", - 7: "function OverloadComponent(attr: {\n b: string;\n a: boolean;\n}): any (+2 overloads)" + 6: "function OverloadComponent(): any (+2 overloads)", + 7: "function OverloadComponent(): any (+2 overloads)", }); From bba41a8a0c9740ff57eed37ea281c4a6b046c21b Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 15 May 2017 18:42:49 -0700 Subject: [PATCH 68/83] avoid ascii escaping literal text --- src/compiler/checker.ts | 8 +++++--- src/compiler/emitter.ts | 4 +++- src/compiler/types.ts | 1 + src/compiler/utilities.ts | 19 +++++++++---------- tests/cases/compiler/unicodeStringLiteral.ts | 1 + ...ImplementInterfaceIndexSignaturesString.ts | 4 ++-- ...mplementInterfaceInheritsAbstractMethod.ts | 4 ++-- ...ssImplementInterfaceMultipleImplements2.ts | 4 ++-- 8 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 tests/cases/compiler/unicodeStringLiteral.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a7ca676908..d9b3c52b73 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2385,7 +2385,7 @@ namespace ts { return createTypeReferenceNode(name, /*typeArguments*/ undefined); } if (type.flags & (TypeFlags.StringLiteral)) { - return createLiteralTypeNode((createLiteral((type).text))); + return createLiteralTypeNode(setEmitFlags(createLiteral((type).text), EmitFlags.NoAsciiEscaping)); } if (type.flags & (TypeFlags.NumberLiteral)) { return createLiteralTypeNode((createNumericLiteral((type).text))); @@ -2783,7 +2783,9 @@ namespace ts { let returnTypeNode: TypeNode; if (signature.typePredicate) { const typePredicate = signature.typePredicate; - const parameterName = typePredicate.kind === TypePredicateKind.Identifier ? createIdentifier((typePredicate).parameterName) : createThisTypeNode(); + const parameterName = typePredicate.kind === TypePredicateKind.Identifier ? + setEmitFlags(createIdentifier((typePredicate).parameterName), EmitFlags.NoAsciiEscaping) : + createThisTypeNode(); const typeNode = typeToTypeNodeHelper(typePredicate.type, context); returnTypeNode = createTypePredicateNode(parameterName, typeNode); } @@ -2894,7 +2896,7 @@ namespace ts { } const symbolName = getNameOfSymbol(symbol, context); - const identifier = createIdentifier(symbolName, typeParameterNodes); + const identifier = setEmitFlags(createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); return index > 0 ? createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 8ec03e90c7..826b636e71 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2653,7 +2653,9 @@ namespace ts { if (node.kind === SyntaxKind.StringLiteral && (node).textSourceNode) { const textSourceNode = (node).textSourceNode; if (isIdentifier(textSourceNode)) { - return "\"" + escapeNonAsciiCharacters(escapeString(getTextOfNode(textSourceNode))) + "\""; + return getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? + `"${escapeString(getTextOfNode(textSourceNode))}"` : + `"${escapeNonAsciiCharacters(escapeString(getTextOfNode(textSourceNode)))}"`; } else { return getLiteralTextOfNode(textSourceNode); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index cf204d158a..4bc97c56c0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3985,6 +3985,7 @@ namespace ts { NoHoisting = 1 << 21, // Do not hoist this declaration in --module system HasEndOfDeclarationMarker = 1 << 22, // Declaration has an associated NotEmittedStatement to mark the end of the declaration Iterator = 1 << 23, // The expression to a `yield*` should be treated as an Iterator when down-leveling, not an Iterable. + NoAsciiEscaping = 1 << 24, // When synthesizing nodes that lack an original node or textSourceNode, we want to write the text on the node with ASCII escaping substitutions. } export interface EmitHelper { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 80daf38363..9dac18eec8 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -328,19 +328,22 @@ namespace ts { return getSourceTextOfNodeFromSourceFile(sourceFile, node); } + const escapeText = getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? + (text: string) => escapeString(text) : + (text: string) => escapeNonAsciiCharacters(escapeString(text)); // If we can't reach the original source text, use the canonical form if it's a number, - // or an escaped quoted form of the original text if it's string-like. + // or a (possibly escaped) quoted form of the original text if it's string-like. switch (node.kind) { case SyntaxKind.StringLiteral: - return getQuotedEscapedLiteralText('"', node.text, '"'); + return '"' + escapeText(node.text) + '"'; case SyntaxKind.NoSubstitutionTemplateLiteral: - return getQuotedEscapedLiteralText("`", node.text, "`"); + return "`" + escapeText(node.text) + "`"; case SyntaxKind.TemplateHead: - return getQuotedEscapedLiteralText("`", node.text, "${"); + return "`" + escapeText(node.text) + "${"; case SyntaxKind.TemplateMiddle: - return getQuotedEscapedLiteralText("}", node.text, "${"); + return "}" + escapeText(node.text) + "${"; case SyntaxKind.TemplateTail: - return getQuotedEscapedLiteralText("}", node.text, "`"); + return "}" + escapeText(node.text) + "`"; case SyntaxKind.NumericLiteral: return node.text; } @@ -348,10 +351,6 @@ namespace ts { Debug.fail(`Literal kind '${node.kind}' not accounted for.`); } - function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) { - return leftQuote + escapeNonAsciiCharacters(escapeString(text)) + rightQuote; - } - // Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__' export function escapeIdentifier(identifier: string): string { return identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier; diff --git a/tests/cases/compiler/unicodeStringLiteral.ts b/tests/cases/compiler/unicodeStringLiteral.ts new file mode 100644 index 0000000000..fa2e128330 --- /dev/null +++ b/tests/cases/compiler/unicodeStringLiteral.ts @@ -0,0 +1 @@ +var ੳ = "Ü­ਲĭ"; \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceIndexSignaturesString.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceIndexSignaturesString.ts index 4b595c6eda..9d42faada3 100644 --- a/tests/cases/fourslash/codeFixClassImplementInterfaceIndexSignaturesString.ts +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceIndexSignaturesString.ts @@ -1,11 +1,11 @@ /// //// interface I { -//// [x: string]: X; +//// [Ƚ: string]: X; //// } //// //// class C implements I {[| |]} verify.rangeAfterCodeFix(` - [x: string]: number; + [Ƚ: string]: number; `); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceInheritsAbstractMethod.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceInheritsAbstractMethod.ts index c141592823..7bb230a2df 100644 --- a/tests/cases/fourslash/codeFixClassImplementInterfaceInheritsAbstractMethod.ts +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceInheritsAbstractMethod.ts @@ -2,12 +2,12 @@ //// abstract class C1 { } //// abstract class C2 { -//// abstract f1(); +//// abstract fA(); //// } //// interface I1 extends C1, C2 { } //// class C3 implements I1 {[| |]} -verify.rangeAfterCodeFix(`f1(){ +verify.rangeAfterCodeFix(`fA(){ throw new Error("Method not implemented."); } `); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceMultipleImplements2.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceMultipleImplements2.ts index e5100b88f6..946b6495c5 100644 --- a/tests/cases/fourslash/codeFixClassImplementInterfaceMultipleImplements2.ts +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceMultipleImplements2.ts @@ -4,7 +4,7 @@ //// x: number; //// } //// interface I2 { -//// y: number; +//// y: "𣋝ઢȴ¬⏊"; //// } //// //// class C implements I1,I2 {[| @@ -12,7 +12,7 @@ //// } verify.rangeAfterCodeFix(` -y: number; +y: "𣋝ઢȴ¬⏊"; `); verify.not.codeFixAvailable(); From a9ab30c068e3096a6586980d5c3dd89ab63f1851 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 15 May 2017 18:43:06 -0700 Subject: [PATCH 69/83] revert baselines --- .../reference/unicodeExtendedEscapesInStrings06_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings06_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings08_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings08_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings09_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings09_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings10_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings10_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings11_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings11_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings13_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings13_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings15_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings15_ES6.types | 2 +- .../reference/unicodeExtendedEscapesInStrings16_ES5.types | 2 +- .../reference/unicodeExtendedEscapesInStrings16_ES6.types | 2 +- tests/baselines/reference/unicodeStringLiteral.js | 5 +++++ tests/baselines/reference/unicodeStringLiteral.symbols | 4 ++++ tests/baselines/reference/unicodeStringLiteral.types | 5 +++++ 19 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 tests/baselines/reference/unicodeStringLiteral.js create mode 100644 tests/baselines/reference/unicodeStringLiteral.symbols create mode 100644 tests/baselines/reference/unicodeStringLiteral.types diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES5.types index e6942df5d1..0c742aaf7b 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES5.types @@ -3,5 +3,5 @@ // 1. Assert: 0 ≤ cp ≤ 0x10FFFF. var x = "\u{10FFFF}"; >x : string ->"\u{10FFFF}" : "\uDBFF\uDFFF" +>"\u{10FFFF}" : "􏿿" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES6.types index 82cc1fa622..6b98c0c98a 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings06_ES6.types @@ -3,5 +3,5 @@ // 1. Assert: 0 ≤ cp ≤ 0x10FFFF. var x = "\u{10FFFF}"; >x : string ->"\u{10FFFF}" : "\uDBFF\uDFFF" +>"\u{10FFFF}" : "􏿿" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES5.types index 9c316cca31..0007b75881 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES5.types @@ -4,5 +4,5 @@ // (FFFF == 65535) var x = "\u{FFFF}"; >x : string ->"\u{FFFF}" : "\uFFFF" +>"\u{FFFF}" : "￿" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES6.types index a5982a77c6..aedd2f72ef 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings08_ES6.types @@ -4,5 +4,5 @@ // (FFFF == 65535) var x = "\u{FFFF}"; >x : string ->"\u{FFFF}" : "\uFFFF" +>"\u{FFFF}" : "￿" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES5.types index 7508721f14..daf8a776e8 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES5.types @@ -4,5 +4,5 @@ // (10000 == 65536) var x = "\u{10000}"; >x : string ->"\u{10000}" : "\uD800\uDC00" +>"\u{10000}" : "𐀀" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES6.types index 5f05276ed3..0963f552c9 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings09_ES6.types @@ -4,5 +4,5 @@ // (10000 == 65536) var x = "\u{10000}"; >x : string ->"\u{10000}" : "\uD800\uDC00" +>"\u{10000}" : "𐀀" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES5.types index a5422cc7a9..a4977300e6 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES5.types @@ -5,5 +5,5 @@ // this is a useful edge-case test. var x = "\u{D800}"; >x : string ->"\u{D800}" : "\uD800" +>"\u{D800}" : "�" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES6.types index 2fcdd0547e..6d6d0112f0 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings10_ES6.types @@ -5,5 +5,5 @@ // this is a useful edge-case test. var x = "\u{D800}"; >x : string ->"\u{D800}" : "\uD800" +>"\u{D800}" : "�" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES5.types index b26387baae..74e6817c85 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES5.types @@ -5,5 +5,5 @@ // this is a useful edge-case test. var x = "\u{DC00}"; >x : string ->"\u{DC00}" : "\uDC00" +>"\u{DC00}" : "�" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES6.types index cd01052999..c1b3f372da 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings11_ES6.types @@ -5,5 +5,5 @@ // this is a useful edge-case test. var x = "\u{DC00}"; >x : string ->"\u{DC00}" : "\uDC00" +>"\u{DC00}" : "�" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES5.types index 68eb2fe8de..224e81adec 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES5.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings13_ES5.ts === var x = "\u{DDDDD}"; >x : string ->"\u{DDDDD}" : "\uDB37\uDDDD" +>"\u{DDDDD}" : "󝷝" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES6.types index 4ad8d2e3f3..e69b2af435 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings13_ES6.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings13_ES6.ts === var x = "\u{DDDDD}"; >x : string ->"\u{DDDDD}" : "\uDB37\uDDDD" +>"\u{DDDDD}" : "󝷝" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES5.types index 8da5611518..1973bb3790 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES5.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings15_ES5.ts === var x = "\u{abcd}\u{ef12}\u{3456}\u{7890}"; >x : string ->"\u{abcd}\u{ef12}\u{3456}\u{7890}" : "\uABCD\uEF12\u3456\u7890" +>"\u{abcd}\u{ef12}\u{3456}\u{7890}" : "ꯍ㑖碐" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES6.types index 613d91afae..16ae5177f5 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings15_ES6.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings15_ES6.ts === var x = "\u{abcd}\u{ef12}\u{3456}\u{7890}"; >x : string ->"\u{abcd}\u{ef12}\u{3456}\u{7890}" : "\uABCD\uEF12\u3456\u7890" +>"\u{abcd}\u{ef12}\u{3456}\u{7890}" : "ꯍ㑖碐" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES5.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES5.types index 1b29651e2d..1ae9d9ef3d 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES5.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES5.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings16_ES5.ts === var x = "\u{ABCD}\u{EF12}\u{3456}\u{7890}"; >x : string ->"\u{ABCD}\u{EF12}\u{3456}\u{7890}" : "\uABCD\uEF12\u3456\u7890" +>"\u{ABCD}\u{EF12}\u{3456}\u{7890}" : "ꯍ㑖碐" diff --git a/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES6.types b/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES6.types index addf7dedff..a4abc5bdea 100644 --- a/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES6.types +++ b/tests/baselines/reference/unicodeExtendedEscapesInStrings16_ES6.types @@ -1,5 +1,5 @@ === tests/cases/conformance/es6/unicodeExtendedEscapes/unicodeExtendedEscapesInStrings16_ES6.ts === var x = "\u{ABCD}\u{EF12}\u{3456}\u{7890}"; >x : string ->"\u{ABCD}\u{EF12}\u{3456}\u{7890}" : "\uABCD\uEF12\u3456\u7890" +>"\u{ABCD}\u{EF12}\u{3456}\u{7890}" : "ꯍ㑖碐" diff --git a/tests/baselines/reference/unicodeStringLiteral.js b/tests/baselines/reference/unicodeStringLiteral.js new file mode 100644 index 0000000000..c69f7aa7e9 --- /dev/null +++ b/tests/baselines/reference/unicodeStringLiteral.js @@ -0,0 +1,5 @@ +//// [unicodeStringLiteral.ts] +var ੳ = "Ü­ਲĭ"; + +//// [unicodeStringLiteral.js] +var ੳ = "Ü­ਲĭ"; diff --git a/tests/baselines/reference/unicodeStringLiteral.symbols b/tests/baselines/reference/unicodeStringLiteral.symbols new file mode 100644 index 0000000000..f48111c060 --- /dev/null +++ b/tests/baselines/reference/unicodeStringLiteral.symbols @@ -0,0 +1,4 @@ +=== tests/cases/compiler/unicodeStringLiteral.ts === +var ੳ = "Ü­ਲĭ"; +>ੳ : Symbol(ੳ, Decl(unicodeStringLiteral.ts, 0, 3)) + diff --git a/tests/baselines/reference/unicodeStringLiteral.types b/tests/baselines/reference/unicodeStringLiteral.types new file mode 100644 index 0000000000..e98f5987ed --- /dev/null +++ b/tests/baselines/reference/unicodeStringLiteral.types @@ -0,0 +1,5 @@ +=== tests/cases/compiler/unicodeStringLiteral.ts === +var ੳ = "Ü­ਲĭ"; +>ੳ : string +>"Ü­ਲĭ" : "Ü­ਲ\u000Eĭ" + From b2176c1872ca67fe7a97491639a34942e5c35a65 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 15 May 2017 19:11:36 -0700 Subject: [PATCH 70/83] no ascii escaping in param names --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d9b3c52b73..0f2e5e9e0f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2818,7 +2818,7 @@ namespace ts { const modifiers = parameterDeclaration.modifiers && parameterDeclaration.modifiers.map(getSynthesizedClone); const dotDotDotToken = isRestParameter(parameterDeclaration) ? createToken(SyntaxKind.DotDotDotToken) : undefined; const name = parameterDeclaration.name.kind === SyntaxKind.Identifier ? - getSynthesizedClone(parameterDeclaration.name) : + setEmitFlags(getSynthesizedClone(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) : cloneBindingName(parameterDeclaration.name); const questionToken = isOptionalParameter(parameterDeclaration) ? createToken(SyntaxKind.QuestionToken) : undefined; @@ -2846,7 +2846,7 @@ namespace ts { if (clone.kind === SyntaxKind.BindingElement) { (clone).initializer = undefined; } - return setEmitFlags(clone, EmitFlags.SingleLine); + return setEmitFlags(clone, EmitFlags.SingleLine | EmitFlags.NoAsciiEscaping); } } } From 2d3c7bae24926ba1ef63722bab813c39bc81b2bf Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 16 May 2017 07:10:38 -0700 Subject: [PATCH 71/83] break -> continue --- src/services/utilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/utilities.ts b/src/services/utilities.ts index e452d18de4..ed28daf019 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -659,7 +659,7 @@ namespace ts { const start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile, includeJsDocComment); if (start > position) { - break; + continue; } const end = child.getEnd(); From ed1a6c10e2281d8c51b53d60e6957a03289d4a73 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 16 May 2017 09:12:32 -0700 Subject: [PATCH 72/83] Address CR feedback + defer creation of visited map --- src/compiler/checker.ts | 53 ++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 26cdab1e59..602125091a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10096,31 +10096,12 @@ namespace ts { inferTypes(context.signature.typeParameters, context.inferences, originalSource, originalTarget); } - function getSymbolForInference(type: Type) { - // Exclude the static side of classes since it shares its symbol with the instance side which leads - // to false positives. - return type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class) ? type.symbol : undefined; - } - function inferTypes(typeVariables: TypeVariable[], typeInferences: TypeInferences[], originalSource: Type, originalTarget: Type) { - let stack: Type[]; - let depth = 0; + let symbolStack: Symbol[]; + let visited: Map; let inferiority = 0; - const visited = createMap(); inferFromTypes(originalSource, originalTarget); - function isInstantiationInProcess(type: Type) { - const symbol = getSymbolForInference(type); - if (symbol) { - for (let i = 0; i < depth; i++) { - const t = stack[i]; - if (getSymbolForInference(t) === symbol) { - return true; - } - } - } - } - function inferFromTypes(source: Type, target: Type) { if (!couldContainTypeVariables(target)) { return; @@ -10248,21 +10229,29 @@ namespace ts { else { source = getApparentType(source); if (source.flags & TypeFlags.Object) { + const key = source.id + "," + target.id; + if (visited && visited.get(key)) { + return; + } + (visited || (visited = createMap())).set(key, true); // If we are already processing another target type with the same associated symbol (such as // an instantiation of the same generic type), we do not explore this target as it would yield - // no further inferences. - if (isInstantiationInProcess(target)) { - return; + // no further inferences. We exclude the static side of classes from this check since it shares + // its symbol with the instance side which would lead to false positives. + const isNonConstructorObject = target.flags & TypeFlags.Object && + !(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class); + const symbol = isNonConstructorObject ? target.symbol : undefined; + if (symbol) { + if (contains(symbolStack, symbol)) { + return; + } + (symbolStack || (symbolStack = [])).push(symbol); + inferFromObjectTypes(source, target); + symbolStack.pop(); } - const key = source.id + "," + target.id; - if (visited.get(key)) { - return; + else { + inferFromObjectTypes(source, target); } - visited.set(key, true); - (stack || (stack = []))[depth] = target; - depth++; - inferFromObjectTypes(source, target); - depth--; } } } From ffa21fe271d09eb964dad6715c272965294be981 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 16 May 2017 09:38:26 -0700 Subject: [PATCH 73/83] getDeclarationOfKind: Improve type safety --- src/compiler/checker.ts | 28 ++++++++++++++-------------- src/compiler/utilities.ts | 4 ++-- src/services/findAllReferences.ts | 4 ++-- src/services/symbolDisplay.ts | 4 ++-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a2a31e3a19..5c37ff2c6c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2731,7 +2731,7 @@ namespace ts { } function symbolToParameterDeclaration(parameterSymbol: Symbol): ParameterDeclaration { - const parameterDeclaration = getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter); + const parameterDeclaration = getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter); const parameterType = getTypeOfSymbol(parameterSymbol); const parameterTypeNode = typeToTypeNodeHelper(parameterType); // TODO(aozgaa): In the future, check initializer accessibility. @@ -4100,7 +4100,7 @@ namespace ts { const func = declaration.parent; // For a parameter of a set accessor, use the type of the get accessor if one is present if (func.kind === SyntaxKind.SetAccessor && !hasDynamicName(func)) { - const getter = getDeclarationOfKind(declaration.parent.symbol, SyntaxKind.GetAccessor); + const getter = getDeclarationOfKind(declaration.parent.symbol, SyntaxKind.GetAccessor); if (getter) { const getterSignature = getSignatureFromDeclaration(getter); const thisParameter = getAccessorThisParameter(func as AccessorDeclaration); @@ -4389,8 +4389,8 @@ namespace ts { function getTypeOfAccessors(symbol: Symbol): Type { const links = getSymbolLinks(symbol); if (!links.type) { - const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); - const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor); + const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); + const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor); if (getter && getter.flags & NodeFlags.JavaScriptFile) { const jsDocType = getTypeForDeclarationFromJSDocComment(getter); @@ -4439,7 +4439,7 @@ namespace ts { if (!popTypeResolution()) { type = anyType; if (noImplicitAny) { - const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); + const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol)); } } @@ -4916,7 +4916,7 @@ namespace ts { return unknownType; } - let declaration: JSDocTypedefTag | TypeAliasDeclaration = getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag); + let declaration: JSDocTypedefTag | TypeAliasDeclaration = getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag); let type: Type; if (declaration) { if (declaration.jsDocTypeLiteral) { @@ -4927,7 +4927,7 @@ namespace ts { } } else { - declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); + declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); type = getTypeFromTypeNode(declaration.type); } @@ -6220,7 +6220,7 @@ namespace ts { !hasDynamicName(declaration) && (!hasThisParameter || !thisParameter)) { const otherKind = declaration.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; - const other = getDeclarationOfKind(declaration.symbol, otherKind); + const other = getDeclarationOfKind(declaration.symbol, otherKind); if (other) { thisParameter = getAnnotatedAccessorThisParameter(other); } @@ -6263,7 +6263,7 @@ namespace ts { // TypeScript 1.0 spec (April 2014): // If only one accessor includes a type annotation, the other behaves as if it had the same type annotation. if (declaration.kind === SyntaxKind.GetAccessor && !hasDynamicName(declaration)) { - const setter = getDeclarationOfKind(declaration.symbol, SyntaxKind.SetAccessor); + const setter = getDeclarationOfKind(declaration.symbol, SyntaxKind.SetAccessor); return getAnnotatedAccessorType(setter); } @@ -6476,7 +6476,7 @@ namespace ts { } function getConstraintDeclaration(type: TypeParameter) { - return (getDeclarationOfKind(type.symbol, SyntaxKind.TypeParameter)).constraint; + return getDeclarationOfKind(type.symbol, SyntaxKind.TypeParameter).constraint; } function getConstraintFromTypeParameter(typeParameter: TypeParameter): Type { @@ -12567,7 +12567,7 @@ namespace ts { // corresponding set accessor has a type annotation, return statements in the function are contextually typed if (functionDecl.type || functionDecl.kind === SyntaxKind.Constructor || - functionDecl.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(functionDecl.symbol, SyntaxKind.SetAccessor))) { + functionDecl.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(functionDecl.symbol, SyntaxKind.SetAccessor))) { return getReturnTypeOfSignature(getSignatureFromDeclaration(functionDecl)); } @@ -18110,7 +18110,7 @@ namespace ts { // TypeScript 1.0 spec (April 2014): 8.4.3 // Accessors for the same member name must specify the same accessibility. const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; - const otherAccessor = getDeclarationOfKind(node.symbol, otherKind); + const otherAccessor = getDeclarationOfKind(node.symbol, otherKind); if (otherAccessor) { if ((getModifierFlags(node) & ModifierFlags.AccessibilityModifier) !== (getModifierFlags(otherAccessor) & ModifierFlags.AccessibilityModifier)) { error(node.name, Diagnostics.Getter_and_setter_accessors_do_not_agree_in_visibility); @@ -20242,7 +20242,7 @@ namespace ts { } function isGetAccessorWithAnnotatedSetAccessor(node: FunctionLikeDeclaration) { - return !!(node.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(node.symbol, SyntaxKind.SetAccessor))); + return !!(node.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(node.symbol, SyntaxKind.SetAccessor))); } function isUnwrappedReturnTypeVoidOrAny(func: FunctionLikeDeclaration, returnType: Type): boolean { @@ -20930,7 +20930,7 @@ namespace ts { checkTypeParameterListsIdentical(symbol); // Only check this symbol once - const firstInterfaceDecl = getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); + const firstInterfaceDecl = getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); if (node === firstInterfaceDecl) { const type = getDeclaredTypeOfSymbol(symbol); const typeWithThis = getTypeWithThisArgument(type); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5046b44d09..98b22605ad 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -11,12 +11,12 @@ namespace ts { isTypeReferenceDirective?: boolean; } - export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration { + export function getDeclarationOfKind(symbol: Symbol, kind: T["kind"]): T { const declarations = symbol.declarations; if (declarations) { for (const declaration of declarations) { if (declaration.kind === kind) { - return declaration; + return declaration as T; } } } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 395c282f6d..d9deaef9e5 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -550,7 +550,7 @@ namespace ts.FindAllReferences.Core { } function isObjectBindingPatternElementWithoutPropertyName(symbol: Symbol): boolean { - const bindingElement = getDeclarationOfKind(symbol, SyntaxKind.BindingElement); + const bindingElement = getDeclarationOfKind(symbol, SyntaxKind.BindingElement); return bindingElement && bindingElement.parent.kind === SyntaxKind.ObjectBindingPattern && !bindingElement.propertyName; @@ -558,7 +558,7 @@ namespace ts.FindAllReferences.Core { function getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol: Symbol, checker: TypeChecker): Symbol | undefined { if (isObjectBindingPatternElementWithoutPropertyName(symbol)) { - const bindingElement = getDeclarationOfKind(symbol, SyntaxKind.BindingElement); + const bindingElement = getDeclarationOfKind(symbol, SyntaxKind.BindingElement); const typeOfPattern = checker.getTypeAtLocation(bindingElement.parent); return typeOfPattern && checker.getPropertyOfType(typeOfPattern, (bindingElement.name).text); } diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 4268a52c41..5e9d115b33 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -275,7 +275,7 @@ namespace ts.SymbolDisplay { } if (symbolFlags & SymbolFlags.Module) { addNewLineIfDisplayPartsExist(); - const declaration = getDeclarationOfKind(symbol, SyntaxKind.ModuleDeclaration); + const declaration = getDeclarationOfKind(symbol, SyntaxKind.ModuleDeclaration); const isNamespace = declaration && declaration.name && declaration.name.kind === SyntaxKind.Identifier; displayParts.push(keywordPart(isNamespace ? SyntaxKind.NamespaceKeyword : SyntaxKind.ModuleKeyword)); displayParts.push(spacePart()); @@ -296,7 +296,7 @@ namespace ts.SymbolDisplay { } else { // Method/function type parameter - let declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeParameter); + let declaration: Node = getDeclarationOfKind(symbol, SyntaxKind.TypeParameter); Debug.assert(declaration !== undefined); declaration = declaration.parent; From badfcbfb43f594710020481662fa2ae680ddfecd Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 16 May 2017 09:45:01 -0700 Subject: [PATCH 74/83] findAncestor: Add generic overload for use with type predicates --- src/compiler/checker.ts | 4 ++-- src/compiler/core.ts | 2 ++ src/compiler/utilities.ts | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7a22c84145..5b81665618 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1300,7 +1300,7 @@ namespace ts { return node; } - return findAncestor(node, n => n.kind === SyntaxKind.ImportDeclaration) as ImportDeclaration; + return findAncestor(node, isImportDeclaration); } } @@ -22638,7 +22638,7 @@ namespace ts { const symbolIsUmdExport = symbolFile !== referenceFile; return symbolIsUmdExport ? undefined : symbolFile; } - return findAncestor(node.parent, n => isModuleOrEnumDeclaration(n) && getSymbolOfNode(n) === parentSymbol) as ModuleDeclaration | EnumDeclaration; + return findAncestor(node.parent, (n): n is ModuleDeclaration | EnumDeclaration => isModuleOrEnumDeclaration(n) && getSymbolOfNode(n) === parentSymbol); } } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 5e4afce98c..60553fdab0 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -230,6 +230,8 @@ namespace ts { * If no such value is found, it applies the callback until the parent pointer is undefined or the callback returns "quit" * At that point findAncestor returns undefined. */ + export function findAncestor(node: Node, callback: (element: Node) => element is T): T | undefined; + export function findAncestor(node: Node, callback: (element: Node) => boolean | "quit"): Node | undefined; export function findAncestor(node: Node, callback: (element: Node) => boolean | "quit"): Node { while (node) { const result = callback(node); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5046b44d09..43a144f904 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4010,6 +4010,10 @@ namespace ts { return node.kind === SyntaxKind.ImportEqualsDeclaration; } + export function isImportDeclaration(node: Node): node is ImportDeclaration { + return node.kind === SyntaxKind.ImportDeclaration; + } + export function isImportClause(node: Node): node is ImportClause { return node.kind === SyntaxKind.ImportClause; } From ea42644c8f5d50633237438cc37637c8b4e4e4e1 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 16 May 2017 10:25:46 -0700 Subject: [PATCH 75/83] Replace unnecessary `let` with two `const`s --- src/services/symbolDisplay.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 5e9d115b33..71dc7b7813 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -296,9 +296,9 @@ namespace ts.SymbolDisplay { } else { // Method/function type parameter - let declaration: Node = getDeclarationOfKind(symbol, SyntaxKind.TypeParameter); - Debug.assert(declaration !== undefined); - declaration = declaration.parent; + const decl = getDeclarationOfKind(symbol, SyntaxKind.TypeParameter); + Debug.assert(decl !== undefined); + const declaration = decl.parent; if (declaration) { if (isFunctionLikeKind(declaration.kind)) { From 56d04429b31e2f440589c026de64e7722b471e1c Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 16 May 2017 11:30:30 -0700 Subject: [PATCH 76/83] Add target and lib references for tsc-instrumented I think they were previously provided implicitly. --- Gulpfile.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Gulpfile.ts b/Gulpfile.ts index 32fbf2c43e..03046789fe 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -935,7 +935,7 @@ gulp.task(loggedIOJsPath, /*help*/ false, [], (done) => { const temp = path.join(builtLocalDirectory, "temp"); mkdirP(temp, (err) => { if (err) { console.error(err); done(err); process.exit(1); } - exec(host, [LKGCompiler, "--types --outdir", temp, loggedIOpath], () => { + exec(host, [LKGCompiler, "--types", "--target es5", "--lib es5", "--outdir", temp, loggedIOpath], () => { fs.renameSync(path.join(temp, "/harness/loggedIO.js"), loggedIOJsPath); del(temp).then(() => done(), done); }, done); @@ -946,7 +946,13 @@ const instrumenterPath = path.join(harnessDirectory, "instrumenter.ts"); const instrumenterJsPath = path.join(builtLocalDirectory, "instrumenter.js"); gulp.task(instrumenterJsPath, /*help*/ false, [servicesFile], () => { const settings: tsc.Settings = getCompilerSettings({ - outFile: instrumenterJsPath + outFile: instrumenterJsPath, + target: "es5", + lib: [ + "es6", + "dom", + "scripthost" + ] }, /*useBuiltCompiler*/ true); return gulp.src(instrumenterPath) .pipe(newer(instrumenterJsPath)) From 5fb77a09011facdac31bd9cf5fb84f734026adac Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Tue, 16 May 2017 23:13:58 +0200 Subject: [PATCH 77/83] Update return types of APIs (#15887) * Update types.ts * Update types in parser.ts and scanner.ts --- src/compiler/parser.ts | 8 ++++---- src/compiler/scanner.ts | 13 +++++++------ src/compiler/types.ts | 30 +++++++++++++++--------------- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index dd189784a1..2d9806bcbf 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -23,19 +23,19 @@ namespace ts { } } - function visitNode(cbNode: (node: Node) => T, node: Node): T { + function visitNode(cbNode: (node: Node) => T, node: Node): T | undefined { if (node) { return cbNode(node); } } - function visitNodeArray(cbNodes: (nodes: Node[]) => T, nodes: Node[]) { + function visitNodeArray(cbNodes: (nodes: Node[]) => T, nodes: Node[]): T | undefined { if (nodes) { return cbNodes(nodes); } } - function visitEachNode(cbNode: (node: Node) => T, nodes: Node[]) { + function visitEachNode(cbNode: (node: Node) => T, nodes: Node[]): T | undefined { if (nodes) { for (const node of nodes) { const result = cbNode(node); @@ -50,7 +50,7 @@ namespace ts { // stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, // embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns // a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. - export function forEachChild(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T { + export function forEachChild(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T | undefined { if (!node) { return; } diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 659c2f416a..d27bbf879f 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -712,11 +712,11 @@ namespace ts { return accumulator; } - export function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T) { + export function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T): U | undefined { return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ false, cb, state); } - export function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T) { + export function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T): U | undefined { return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ true, cb, state); } @@ -746,10 +746,11 @@ namespace ts { } /** Optionally, get the shebang */ - export function getShebang(text: string): string { - return shebangTriviaRegex.test(text) - ? shebangTriviaRegex.exec(text)[0] - : undefined; + export function getShebang(text: string): string | undefined { + const match = shebangTriviaRegex.exec(text); + if (match) { + return match[0]; + } } export function isIdentifierStart(ch: number, languageVersion: ScriptTarget): boolean { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 67d80a92ce..955bb0622d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2527,11 +2527,11 @@ namespace ts { indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; - getSymbolAtLocation(node: Node): Symbol; + getSymbolAtLocation(node: Node): Symbol | undefined; getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[]; - getShorthandAssignmentValueSymbol(location: Node): Symbol; - getExportSpecifierLocalTargetSymbol(location: ExportSpecifier): Symbol; - getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol; + getShorthandAssignmentValueSymbol(location: Node): Symbol | undefined; + getExportSpecifierLocalTargetSymbol(location: ExportSpecifier): Symbol | undefined; + getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol | undefined; getTypeAtLocation(node: Node): Type; getTypeFromTypeNode(node: TypeNode): Type; signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string; @@ -2542,15 +2542,15 @@ namespace ts { getAugmentedPropertiesOfType(type: Type): Symbol[]; getRootSymbols(symbol: Symbol): Symbol[]; getContextualType(node: Expression): Type | undefined; - getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature; - getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature; - isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; + getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature | undefined; + getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature | undefined; + isImplementationOfOverload(node: FunctionLikeDeclaration): boolean | undefined; isUndefinedSymbol(symbol: Symbol): boolean; isArgumentsSymbol(symbol: Symbol): boolean; isUnknownSymbol(symbol: Symbol): boolean; /* @internal */ getMergedSymbol(symbol: Symbol): Symbol; - getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; + getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number | undefined; isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean; /** Follow all aliases to get the original symbol. */ getAliasedSymbol(symbol: Symbol): Symbol; @@ -2560,7 +2560,7 @@ namespace ts { /** Unlike `getExportsOfModule`, this includes properties of an `export =` value. */ /* @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[]; - getAllAttributesTypeFromJsxOpeningLikeElement(elementNode: JsxOpeningLikeElement): Type; + getAllAttributesTypeFromJsxOpeningLikeElement(elementNode: JsxOpeningLikeElement): Type | undefined; getJsxIntrinsicTagNames(): Symbol[]; isOptionalParameter(node: ParameterDeclaration): boolean; getAmbientModules(): Symbol[]; @@ -2568,10 +2568,10 @@ namespace ts { tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined; getApparentType(type: Type): Type; getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined; - getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string; - /* @internal */ getBaseConstraintOfType(type: Type): Type; + getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; + /* @internal */ getBaseConstraintOfType(type: Type): Type | undefined; - /* @internal */ tryFindAmbientModuleWithoutAugmentations(moduleName: string): Symbol; + /* @internal */ tryFindAmbientModuleWithoutAugmentations(moduleName: string): Symbol | undefined; // Should not be called directly. Should only be accessed through the Program instance. /* @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[]; @@ -2753,7 +2753,7 @@ namespace ts { getNodeCheckFlags(node: Node): NodeCheckFlags; isDeclarationVisible(node: Declaration): boolean; collectLinkedAliases(node: Identifier): Node[]; - isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; + isImplementationOfOverload(node: FunctionLikeDeclaration): boolean | undefined; isRequiredInitializedParameter(node: ParameterDeclaration): boolean; writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; @@ -3135,7 +3135,7 @@ namespace ts { */ export interface TypeReference extends ObjectType { target: GenericType; // Type reference target - typeArguments: Type[]; // Type reference type arguments (undefined if none) + typeArguments?: Type[]; // Type reference type arguments (undefined if none) } // Generic class and interface types @@ -3265,7 +3265,7 @@ namespace ts { export interface Signature { declaration: SignatureDeclaration; // Originating declaration - typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic) + typeParameters?: TypeParameter[]; // Type parameters (undefined if non-generic) parameters: Symbol[]; // Parameters /* @internal */ thisParameter?: Symbol; // symbol of this-type parameter From 0defde71850fe75b4ee3ef7e5386fd1d4d374fc6 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 16 May 2017 15:04:33 -0700 Subject: [PATCH 78/83] Services utilities: Combine `isInsideComment` with `isInComment` --- src/services/completions.ts | 2 +- src/services/services.ts | 4 +- src/services/utilities.ts | 84 ++++++++++++------------------------- 3 files changed, 30 insertions(+), 60 deletions(-) diff --git a/src/services/completions.ts b/src/services/completions.ts index 5bc2a26861..d80eaa9a7e 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -359,7 +359,7 @@ namespace ts.Completions { start = timestamp(); // Completion not allowed inside comments, bail out if this is the case - const insideComment = isInsideComment(sourceFile, currentToken, position); + const insideComment = isInComment(sourceFile, position, currentToken); log("getCompletionData: Is inside comment: " + (timestamp() - start)); if (insideComment) { diff --git a/src/services/services.ts b/src/services/services.ts index 1b4678b5db..d35f1e7b8a 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1853,8 +1853,8 @@ namespace ts { // OK, we have found a match in the file. This is only an acceptable match if // it is contained within a comment. - const token = getTokenAtPosition(sourceFile, matchPosition); - if (!isInsideComment(sourceFile, token, matchPosition)) { + + if (!isInComment(sourceFile, matchPosition)) { continue; } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 4ae9204f7e..8a9976e00b 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -256,37 +256,6 @@ namespace ts { getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node; } - /** Returns true if the position is within a comment */ - export function isInsideComment(sourceFile: SourceFile, token: Node, position: number): boolean { - // The position has to be: 1. in the leading trivia (before token.getStart()), and 2. within a comment - return position <= token.getStart(sourceFile) && - (isInsideCommentRange(getTrailingCommentRanges(sourceFile.text, token.getFullStart())) || - isInsideCommentRange(getLeadingCommentRanges(sourceFile.text, token.getFullStart()))); - - function isInsideCommentRange(comments: CommentRange[]): boolean { - return forEach(comments, comment => { - // either we are 1. completely inside the comment, or 2. at the end of the comment - if (comment.pos < position && position < comment.end) { - return true; - } - else if (position === comment.end) { - const text = sourceFile.text; - const width = comment.end - comment.pos; - // is single line comment or just /* - if (width <= 2 || text.charCodeAt(comment.pos + 1) === CharacterCodes.slash) { - return true; - } - else { - // is unterminated multi-line comment - return !(text.charCodeAt(comment.end - 1) === CharacterCodes.slash && - text.charCodeAt(comment.end - 2) === CharacterCodes.asterisk); - } - } - return false; - }); - } - } - export function getContainerNode(node: Node): Declaration { while (true) { node = node.parent; @@ -834,10 +803,6 @@ namespace ts { return false; } - export function isInComment(sourceFile: SourceFile, position: number) { - return isInCommentHelper(sourceFile, position, /*predicate*/ undefined); - } - /** * returns true if the position is in between the open and close elements of an JSX expression. */ @@ -883,15 +848,26 @@ namespace ts { } /** - * Returns true if the cursor at position in sourceFile is within a comment that additionally - * satisfies predicate, and false otherwise. + * Returns true if the cursor at position in sourceFile is within a comment. + * + * @param tokenAtPosition Must equal `getTokenAtPosition(sourceFile, position) + * @param predicate Additional predicate to test on the comment range. */ - export function isInCommentHelper(sourceFile: SourceFile, position: number, predicate?: (c: CommentRange) => boolean): boolean { - const token = getTokenAtPosition(sourceFile, position); + export function isInComment(sourceFile: SourceFile, position: number, tokenAtPosition = getTokenAtPosition(sourceFile, position), predicate?: (c: CommentRange) => boolean): boolean { + return position <= tokenAtPosition.getStart(sourceFile) && + (isInCommentRange(getLeadingCommentRanges(sourceFile.text, tokenAtPosition.pos)) || + isInCommentRange(getTrailingCommentRanges(sourceFile.text, tokenAtPosition.pos))); - if (token && position <= token.getStart(sourceFile)) { - const commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos); + function isInCommentRange(commentRanges: CommentRange[]): boolean { + return forEach(commentRanges, c => isPositionInCommentRange(c, position, sourceFile.text) && (!predicate || predicate(c))); + } + } + function isPositionInCommentRange({ pos, end, kind }: ts.CommentRange, position: number, text: string): boolean { + if (pos < position && position < end) { + return true; + } + else if (position === end) { // The end marker of a single-line comment does not include the newline character. // In the following case, we are inside a comment (^ denotes the cursor position): // @@ -902,15 +878,13 @@ namespace ts { // /* asdf */^ // // Internally, we represent the end of the comment at the newline and closing '/', respectively. - return predicate ? - forEach(commentRanges, c => c.pos < position && - (c.kind === SyntaxKind.SingleLineCommentTrivia ? position <= c.end : position < c.end) && - predicate(c)) : - forEach(commentRanges, c => c.pos < position && - (c.kind === SyntaxKind.SingleLineCommentTrivia ? position <= c.end : position < c.end)); + return kind === SyntaxKind.SingleLineCommentTrivia || + // true for unterminated multi-line comment + !(text.charCodeAt(end - 1) === CharacterCodes.slash && text.charCodeAt(end - 2) === CharacterCodes.asterisk); + } + else { + return false; } - - return false; } export function hasDocComment(sourceFile: SourceFile, position: number) { @@ -1093,21 +1067,17 @@ namespace ts { } export function isInReferenceComment(sourceFile: SourceFile, position: number): boolean { - return isInCommentHelper(sourceFile, position, isReferenceComment); - - function isReferenceComment(c: CommentRange): boolean { + return isInComment(sourceFile, position, /*tokenAtPosition*/ undefined, c => { const commentText = sourceFile.text.substring(c.pos, c.end); return tripleSlashDirectivePrefixRegex.test(commentText); - } + }); } export function isInNonReferenceComment(sourceFile: SourceFile, position: number): boolean { - return isInCommentHelper(sourceFile, position, isNonReferenceComment); - - function isNonReferenceComment(c: CommentRange): boolean { + return isInComment(sourceFile, position, /*tokenAtPosition*/ undefined, c => { const commentText = sourceFile.text.substring(c.pos, c.end); return !tripleSlashDirectivePrefixRegex.test(commentText); - } + }); } export function createTextSpanFromNode(node: Node, sourceFile?: SourceFile): TextSpan { From 0820f692705e4b1118b0c9a8f57783073f80f8e6 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 16 May 2017 15:28:32 -0700 Subject: [PATCH 79/83] respond to comments --- src/compiler/checker.ts | 48 +++++++++++++++++++-------------------- src/compiler/emitter.ts | 2 +- src/compiler/factory.ts | 15 ++++++------ src/compiler/types.ts | 6 ++--- src/compiler/utilities.ts | 10 ++++---- src/compiler/visitor.ts | 2 -- 6 files changed, 40 insertions(+), 43 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0f2e5e9e0f..e426a7bdba 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2279,7 +2279,7 @@ namespace ts { } function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { - const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName); + const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName); Debug.assert(typeNode !== undefined, "should always get typenode?"); const options = { removeComments: true }; const writer = createTextWriter(""); @@ -2361,7 +2361,7 @@ namespace ts { function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { const inTypeAlias = context.flags & NodeBuilderFlags.InTypeAlias; - context.flags &= ~(NodeBuilderFlags.InTypeAlias); + context.flags &= ~NodeBuilderFlags.InTypeAlias; if (!type) { context.encounteredError = true; @@ -2419,7 +2419,7 @@ namespace ts { return createKeywordTypeNode(SyntaxKind.ObjectKeyword); } if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { - if (context.flags & NodeBuilderFlags.inObjectTypeLiteral) { + if (context.flags & NodeBuilderFlags.InObjectTypeLiteral) { if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowThisInObjectLiteral)) { context.encounteredError = true; } @@ -2441,12 +2441,12 @@ namespace ts { if (!inTypeAlias && type.aliasSymbol && isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { const name = symbolToTypeReferenceName(type.aliasSymbol); - const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, context); + const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context); return createTypeReferenceNode(name, typeArgumentNodes); } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { const types = type.flags & TypeFlags.Union ? formatUnionTypes((type).types) : (type).types; - const typeNodes = types && mapToTypeNodeArray(types, context); + const typeNodes = mapToTypeNodes(types, context); if (typeNodes && typeNodes.length > 0) { const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes); return unionOrIntersectionTypeNode; @@ -2567,7 +2567,7 @@ namespace ts { } const savedFlags = context.flags; - context.flags |= NodeBuilderFlags.inObjectTypeLiteral; + context.flags |= NodeBuilderFlags.InObjectTypeLiteral; const members = createTypeNodesFromResolvedType(resolved); context.flags = savedFlags; const typeLiteralNode = createTypeLiteralNode(members); @@ -2598,8 +2598,7 @@ namespace ts { } else if (type.target.objectFlags & ObjectFlags.Tuple) { if (typeArguments.length > 0) { - const slice = typeArguments.slice(0, getTypeReferenceArity(type)); - const tupleConstituentNodes = slice && mapToTypeNodeArray(slice, context); + const tupleConstituentNodes = mapToTypeNodes(typeArguments.slice(0, getTypeReferenceArity(type)), context); if (tupleConstituentNodes && tupleConstituentNodes.length > 0) { return createTupleTypeNode(tupleConstituentNodes); } @@ -2625,8 +2624,8 @@ namespace ts { // When type parameters are their own type arguments for the whole group (i.e. we have // the default outer type arguments), we don't show the group. if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { - const slice = typeArguments.slice(start, i); - const typeArgumentNodes = slice && createNodeArray(mapToTypeNodeArray(slice, context)); + const typeArgumentSlice = mapToTypeNodes(typeArguments.slice(start, i), context); + const typeArgumentNodes = typeArgumentSlice && createNodeArray(typeArgumentSlice); const namePart = symbolToTypeReferenceName(parent); (namePart.kind === SyntaxKind.Identifier ? namePart : namePart.right).typeArguments = typeArgumentNodes; @@ -2654,10 +2653,9 @@ namespace ts { } let typeArgumentNodes: TypeNode[] | undefined; - if (some(typeArguments)) { + if (typeArguments.length > 0) { const typeParameterCount = (type.target.typeParameters || emptyArray).length; - const slice = typeArguments && typeArguments.slice(i, typeParameterCount); - typeArgumentNodes = slice && mapToTypeNodeArray(slice, context); + typeArgumentNodes = mapToTypeNodes(typeArguments.slice(i, typeParameterCount), context); } if (typeArgumentNodes) { @@ -2740,17 +2738,19 @@ namespace ts { } } - function mapToTypeNodeArray(types: Type[], context: NodeBuilderContext): TypeNode[] { - const result = []; - for (let i = 0; i < types.length; ++i) { - const type = types[i]; - const typeNode = typeToTypeNodeHelper(type, context); - if (typeNode) { - result.push(typeNode); + function mapToTypeNodes(types: Type[], context: NodeBuilderContext): TypeNode[] { + if (some(types)) { + const result = []; + for (let i = 0; i < types.length; ++i) { + const type = types[i]; + const typeNode = typeToTypeNodeHelper(type, context); + if (typeNode) { + result.push(typeNode); + } } - } - return result; + return result; + } } function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, context: NodeBuilderContext): IndexSignatureDeclaration { @@ -2890,9 +2890,7 @@ namespace ts { } } - if (typeParameters && typeParameters.length > 0) { - typeParameterNodes = mapToTypeNodeArray(typeParameters, context); - } + typeParameterNodes = mapToTypeNodes(typeParameters, context); } const symbolName = getNameOfSymbol(symbol, context); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 826b636e71..7917480975 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2655,7 +2655,7 @@ namespace ts { if (isIdentifier(textSourceNode)) { return getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? `"${escapeString(getTextOfNode(textSourceNode))}"` : - `"${escapeNonAsciiCharacters(escapeString(getTextOfNode(textSourceNode)))}"`; + `"${escapeNonAsciiString(getTextOfNode(textSourceNode))}"`; } else { return getLiteralTextOfNode(textSourceNode); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 18e71f94ee..1a5f1fbac5 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3607,16 +3607,17 @@ namespace ts { } export function parenthesizeElementTypeMembers(members: TypeNode[]) { - // TODO: does this lose `originalNode` ptr? - return createNodeArray(members.map(parenthesizeElementTypeMember)); + return createNodeArray(sameMap(members, parenthesizeElementTypeMember)); } export function parenthesizeTypeParameters(typeParameters: TypeNode[]) { - if (typeParameters && typeParameters.length > 0) { - const nodeArray = createNodeArray(typeParameters); - const firstEntry = nodeArray[0]; - if (isFunctionOrConstructor(firstEntry) && firstEntry.typeParameters) { - nodeArray[0] = createParenthesizedType(firstEntry); + if (some(typeParameters)) { + const nodeArray = createNodeArray() as NodeArray; + for (let i = 0; i < typeParameters.length; ++i) { + const entry = typeParameters[i]; + nodeArray.push(i === 0 && isFunctionOrConstructorTypeNode(entry) && entry.typeParameters ? + createParenthesizedType(entry) : + entry); } return nodeArray; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4bc97c56c0..3ac3caa121 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -580,7 +580,7 @@ namespace ts { /*@internal*/ autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier. /*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name. isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace - /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics. + /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics. } // Transient identifier node (marked by id === -1) @@ -2599,10 +2599,10 @@ namespace ts { AllowEmptyUnionOrIntersection = 1 << 14, AllowEmptyTuple = 1 << 15, - ignoreErrors = AllowThisInObjectLiteral | AllowQualifedNameInPlaceOfIdentifier | AllowAnonymousIdentifier | AllowEmptyUnionOrIntersection | AllowEmptyTuple, + IgnoreErrors = AllowThisInObjectLiteral | AllowQualifedNameInPlaceOfIdentifier | AllowAnonymousIdentifier | AllowEmptyUnionOrIntersection | AllowEmptyTuple, // State - inObjectTypeLiteral = 1 << 20, + InObjectTypeLiteral = 1 << 20, InTypeAlias = 1 << 23, // Writing type in type alias declaration } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 9dac18eec8..c8e481bc2e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -328,9 +328,8 @@ namespace ts { return getSourceTextOfNodeFromSourceFile(sourceFile, node); } - const escapeText = getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? - (text: string) => escapeString(text) : - (text: string) => escapeNonAsciiCharacters(escapeString(text)); + const escapeText = getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? escapeString : escapeNonAsciiString; + // If we can't reach the original source text, use the canonical form if it's a number, // or a (possibly escaped) quoted form of the original text if it's string-like. switch (node.kind) { @@ -880,7 +879,7 @@ namespace ts { return false; } - export function isFunctionOrConstructor(node: Node): node is FunctionTypeNode | ConstructorTypeNode { + export function isFunctionOrConstructorTypeNode(node: Node): node is FunctionTypeNode | ConstructorTypeNode { switch (node.kind) { case SyntaxKind.FunctionType: case SyntaxKind.ConstructorType: @@ -2468,7 +2467,8 @@ namespace ts { } const nonAsciiCharacters = /[^\u0000-\u007F]/g; - export function escapeNonAsciiCharacters(s: string): string { + export function escapeNonAsciiString(s: string): string { + s = escapeString(s); // Replace non-ASCII characters with '\uNNNN' escapes if any exist. // Otherwise just return the original string. return nonAsciiCharacters.test(s) ? diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index c62af0da79..f8fe92c184 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -988,8 +988,6 @@ namespace ts { result = reduceNode((node).initializer, cbNode, result); break; - case SyntaxKind.PropertySignature: - case SyntaxKind.MethodDeclaration: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result); From 0ff187c8aca03f17093a8b3688b9aaf3cc55da2b Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 17 May 2017 08:12:23 -0700 Subject: [PATCH 80/83] Remove 'isDeclarationFile()' function, use '.isDeclarationFile' --- src/compiler/binder.ts | 10 +++++----- src/compiler/declarationEmitter.ts | 2 +- src/compiler/factory.ts | 2 +- src/compiler/program.ts | 13 ++++++------- src/compiler/transformer.ts | 2 +- src/compiler/transformers/es2015.ts | 2 +- src/compiler/transformers/es2016.ts | 2 +- src/compiler/transformers/es2017.ts | 2 +- src/compiler/transformers/esnext.ts | 2 +- src/compiler/transformers/generators.ts | 3 +-- src/compiler/transformers/jsx.ts | 2 +- src/compiler/transformers/module/es2015.ts | 2 +- src/compiler/transformers/module/module.ts | 2 +- src/compiler/transformers/module/system.ts | 4 +--- src/compiler/transformers/ts.ts | 2 +- src/compiler/utilities.ts | 8 ++------ src/harness/projectsRunner.ts | 2 +- 17 files changed, 27 insertions(+), 35 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b6074162ff..1940231a6d 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -149,7 +149,7 @@ namespace ts { inStrictMode = bindInStrictMode(file, opts); classifiableNames = createMap(); symbolCount = 0; - skipTransformFlagAggregation = isDeclarationFile(file); + skipTransformFlagAggregation = file.isDeclarationFile; Symbol = objectAllocator.getSymbolConstructor(); @@ -182,7 +182,7 @@ namespace ts { return bindSourceFile; function bindInStrictMode(file: SourceFile, opts: CompilerOptions): boolean { - if ((opts.alwaysStrict === undefined ? opts.strict : opts.alwaysStrict) && !isDeclarationFile(file)) { + if ((opts.alwaysStrict === undefined ? opts.strict : opts.alwaysStrict) && !file.isDeclarationFile) { // bind in strict mode source files with alwaysStrict option return true; } @@ -2527,7 +2527,7 @@ namespace ts { } function bindFunctionDeclaration(node: FunctionDeclaration) { - if (!isDeclarationFile(file) && !isInAmbientContext(node)) { + if (!file.isDeclarationFile && !isInAmbientContext(node)) { if (isAsyncFunction(node)) { emitFlags |= NodeFlags.HasAsyncFunctions; } @@ -2544,7 +2544,7 @@ namespace ts { } function bindFunctionExpression(node: FunctionExpression) { - if (!isDeclarationFile(file) && !isInAmbientContext(node)) { + if (!file.isDeclarationFile && !isInAmbientContext(node)) { if (isAsyncFunction(node)) { emitFlags |= NodeFlags.HasAsyncFunctions; } @@ -2558,7 +2558,7 @@ namespace ts { } function bindPropertyOrMethodOrAccessor(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) { - if (!isDeclarationFile(file) && !isInAmbientContext(node)) { + if (!file.isDeclarationFile && !isInAmbientContext(node)) { if (isAsyncFunction(node)) { emitFlags |= NodeFlags.HasAsyncFunctions; } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 7c842de277..4d06b41f37 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -1840,7 +1840,7 @@ namespace ts { function writeReferencePath(referencedFile: SourceFile, addBundledFileReference: boolean, emitOnlyDtsFiles: boolean): boolean { let declFileName: string; let addedBundledEmitReference = false; - if (isDeclarationFile(referencedFile)) { + if (referencedFile.isDeclarationFile) { // Declaration file, use declaration file name declFileName = referencedFile.fileName; } diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index fbb387f034..270ca0cb4d 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3858,7 +3858,7 @@ namespace ts { if (file.moduleName) { return createLiteral(file.moduleName); } - if (!isDeclarationFile(file) && (options.out || options.outFile)) { + if (!file.isDeclarationFile && (options.out || options.outFile)) { return createLiteral(getExternalModuleNameFromPath(host, file.fileName)); } return undefined; diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 8233ab4802..2fde21afec 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1309,7 +1309,7 @@ namespace ts { } function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { - return isDeclarationFile(sourceFile) ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken); + return sourceFile.isDeclarationFile ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken); } function getOptionsDiagnostics(): Diagnostic[] { @@ -1348,7 +1348,6 @@ namespace ts { const isJavaScriptFile = isSourceFileJavaScript(file); const isExternalModuleFile = isExternalModule(file); - const isDtsFile = isDeclarationFile(file); let imports: LiteralExpression[]; let moduleAugmentations: LiteralExpression[]; @@ -1401,7 +1400,7 @@ namespace ts { } break; case SyntaxKind.ModuleDeclaration: - if (isAmbientModule(node) && (inAmbientModule || hasModifier(node, ModifierFlags.Ambient) || isDeclarationFile(file))) { + if (isAmbientModule(node) && (inAmbientModule || hasModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) { const moduleName = (node).name; // Ambient module declarations can be interpreted as augmentations for some existing external modules. // This will happen in two cases: @@ -1412,7 +1411,7 @@ namespace ts { (moduleAugmentations || (moduleAugmentations = [])).push(moduleName); } else if (!inAmbientModule) { - if (isDtsFile) { + if (file.isDeclarationFile) { // for global .d.ts files record name of ambient module (ambientModules || (ambientModules = [])).push(moduleName.text); } @@ -1730,7 +1729,7 @@ namespace ts { const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory)); for (const sourceFile of sourceFiles) { - if (!isDeclarationFile(sourceFile)) { + if (!sourceFile.isDeclarationFile) { const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory)); if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) { programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, options.rootDir)); @@ -1843,13 +1842,13 @@ namespace ts { const languageVersion = options.target || ScriptTarget.ES3; const outFile = options.outFile || options.out; - const firstNonAmbientExternalModuleSourceFile = forEach(files, f => isExternalModule(f) && !isDeclarationFile(f) ? f : undefined); + const firstNonAmbientExternalModuleSourceFile = forEach(files, f => isExternalModule(f) && !f.isDeclarationFile ? f : undefined); if (options.isolatedModules) { if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015) { programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher)); } - const firstNonExternalModuleSourceFile = forEach(files, f => !isExternalModule(f) && !isDeclarationFile(f) ? f : undefined); + const firstNonExternalModuleSourceFile = forEach(files, f => !isExternalModule(f) && !f.isDeclarationFile ? f : undefined); if (firstNonExternalModuleSourceFile) { const span = getErrorSpanForNode(firstNonExternalModuleSourceFile, firstNonExternalModuleSourceFile); programDiagnostics.add(createFileDiagnostic(firstNonExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_namespaces_when_the_isolatedModules_flag_is_provided)); diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index bb1732b57e..75f9c43c6f 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -165,7 +165,7 @@ namespace ts { }; function transformRoot(node: T) { - return node && (!isSourceFile(node) || !isDeclarationFile(node)) ? transformation(node) : node; + return node && (!isSourceFile(node) || !node.isDeclarationFile) ? transformation(node) : node; } /** diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index ad9a6b9939..63c1014516 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -295,7 +295,7 @@ namespace ts { return transformSourceFile; function transformSourceFile(node: SourceFile) { - if (isDeclarationFile(node)) { + if (node.isDeclarationFile) { return node; } diff --git a/src/compiler/transformers/es2016.ts b/src/compiler/transformers/es2016.ts index 1118e6ad9b..a946899177 100644 --- a/src/compiler/transformers/es2016.ts +++ b/src/compiler/transformers/es2016.ts @@ -9,7 +9,7 @@ namespace ts { return transformSourceFile; function transformSourceFile(node: SourceFile) { - if (isDeclarationFile(node)) { + if (node.isDeclarationFile) { return node; } diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index 3bbb3b3123..3565547d78 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -47,7 +47,7 @@ namespace ts { return transformSourceFile; function transformSourceFile(node: SourceFile) { - if (isDeclarationFile(node)) { + if (node.isDeclarationFile) { return node; } diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 81ebd0b8f5..6e2f70b5c3 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -33,7 +33,7 @@ namespace ts { return transformSourceFile; function transformSourceFile(node: SourceFile) { - if (isDeclarationFile(node)) { + if (node.isDeclarationFile) { return node; } diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index 286892f9d3..9aadd6bc68 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -293,8 +293,7 @@ namespace ts { return transformSourceFile; function transformSourceFile(node: SourceFile) { - if (isDeclarationFile(node) - || (node.transformFlags & TransformFlags.ContainsGenerator) === 0) { + if (node.isDeclarationFile || (node.transformFlags & TransformFlags.ContainsGenerator) === 0) { return node; } diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index e9455490a5..09f361d1b1 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -15,7 +15,7 @@ namespace ts { * @param node A SourceFile node. */ function transformSourceFile(node: SourceFile) { - if (isDeclarationFile(node)) { + if (node.isDeclarationFile) { return node; } diff --git a/src/compiler/transformers/module/es2015.ts b/src/compiler/transformers/module/es2015.ts index 660293e074..3951d08109 100644 --- a/src/compiler/transformers/module/es2015.ts +++ b/src/compiler/transformers/module/es2015.ts @@ -16,7 +16,7 @@ namespace ts { return transformSourceFile; function transformSourceFile(node: SourceFile) { - if (isDeclarationFile(node)) { + if (node.isDeclarationFile) { return node; } diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index d387a1a3a2..b3e544a3f8 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -55,7 +55,7 @@ namespace ts { * @param node The SourceFile node. */ function transformSourceFile(node: SourceFile) { - if (isDeclarationFile(node) || !(isExternalModule(node) || compilerOptions.isolatedModules)) { + if (node.isDeclarationFile || !(isExternalModule(node) || compilerOptions.isolatedModules)) { return node; } diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 5711d9f111..3355ad3563 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -50,9 +50,7 @@ namespace ts { * @param node The SourceFile node. */ function transformSourceFile(node: SourceFile) { - if (isDeclarationFile(node) - || !(isExternalModule(node) - || compilerOptions.isolatedModules)) { + if (node.isDeclarationFile || !(isExternalModule(node) || compilerOptions.isolatedModules)) { return node; } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 6597840922..a2e8c192da 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -76,7 +76,7 @@ namespace ts { * @param node A SourceFile node. */ function transformSourceFile(node: SourceFile) { - if (isDeclarationFile(node)) { + if (node.isDeclarationFile) { return node; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 8d570f7063..befb1c4ba7 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -587,10 +587,6 @@ namespace ts { return (file.externalModuleIndicator || file.commonJsModuleIndicator) !== undefined; } - export function isDeclarationFile(file: SourceFile): boolean { - return file.isDeclarationFile; - } - export function isConstEnumDeclaration(node: Node): boolean { return node.kind === SyntaxKind.EnumDeclaration && isConst(node); } @@ -2575,7 +2571,7 @@ namespace ts { export function getExternalModuleNameFromDeclaration(host: EmitHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): string { const file = resolver.getExternalModuleFileFromDeclaration(declaration); - if (!file || isDeclarationFile(file)) { + if (!file || file.isDeclarationFile) { return undefined; } return getResolvedExternalModuleName(host, file); @@ -2648,7 +2644,7 @@ namespace ts { /** Don't call this for `--outFile`, just for `--outDir` or plain emit. `--outFile` needs additional checks. */ export function sourceFileMayBeEmitted(sourceFile: SourceFile, options: CompilerOptions, isSourceFileFromExternalLibrary: (file: SourceFile) => boolean) { - return !(options.noEmitForJsFiles && isSourceFileJavaScript(sourceFile)) && !isDeclarationFile(sourceFile) && !isSourceFileFromExternalLibrary(sourceFile); + return !(options.noEmitForJsFiles && isSourceFileJavaScript(sourceFile)) && !sourceFile.isDeclarationFile && !isSourceFileFromExternalLibrary(sourceFile); } /** diff --git a/src/harness/projectsRunner.ts b/src/harness/projectsRunner.ts index b0efcf4c38..28d59fe35b 100644 --- a/src/harness/projectsRunner.ts +++ b/src/harness/projectsRunner.ts @@ -372,7 +372,7 @@ class ProjectRunner extends RunnerBase { const compilerOptions = compilerResult.program.getCompilerOptions(); ts.forEach(compilerResult.program.getSourceFiles(), sourceFile => { - if (ts.isDeclarationFile(sourceFile)) { + if (sourceFile.isDeclarationFile) { allInputFiles.unshift({ emittedFileName: sourceFile.fileName, code: sourceFile.text }); } else if (!(compilerOptions.outFile || compilerOptions.out)) { From b9c3a992e1fb2fc1f437986a9dee113ab6c98f71 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 17 May 2017 08:26:00 -0700 Subject: [PATCH 81/83] getAllPossiblePropertiesOfTypes: Skip primitives --- src/compiler/checker.ts | 4 ++++ src/compiler/types.ts | 1 + tests/cases/fourslash/completionListOfUnion.ts | 2 ++ 3 files changed, 7 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2d46488665..953a72e2ec 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5785,6 +5785,10 @@ namespace ts { if (type.flags & TypeFlags.Union) { const props = createMap(); for (const memberType of (type as UnionType).types) { + if (memberType.flags & TypeFlags.Primitive) { + continue; + } + for (const { name } of getPropertiesOfType(memberType)) { if (!props.has(name)) { props.set(name, createUnionOrIntersectionProperty(type as UnionType, name)); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0283c45f2e..d0962ac41d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2587,6 +2587,7 @@ namespace ts { /** * For a union, will include a property if it's defined in *any* of the member types. * So for `{ a } | { b }`, this will include both `a` and `b`. + * Does not include properties of primitive types. */ /* @internal */ getAllPossiblePropertiesOfType(type: Type): Symbol[]; } diff --git a/tests/cases/fourslash/completionListOfUnion.ts b/tests/cases/fourslash/completionListOfUnion.ts index 6026615f8c..8e6d1f20a3 100644 --- a/tests/cases/fourslash/completionListOfUnion.ts +++ b/tests/cases/fourslash/completionListOfUnion.ts @@ -10,9 +10,11 @@ ////f({ /*f*/ }); goTo.marker("x"); +verify.completionListCount(3); verify.completionListContains("a", "(property) a: string | number"); verify.completionListContains("b", "(property) b: number | boolean"); verify.completionListContains("c", "(property) c: string"); goTo.marker("f"); verify.completionListContains("a", "(property) a: number"); +// Also contains array members From 6a7b6d367b9a2b85e9389b598aa06d7f2ad45d75 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 17 May 2017 11:59:33 -0700 Subject: [PATCH 82/83] Accept new baselines --- tests/baselines/reference/enumErrors.errors.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/baselines/reference/enumErrors.errors.txt b/tests/baselines/reference/enumErrors.errors.txt index 096722fc4b..af719d47ae 100644 --- a/tests/baselines/reference/enumErrors.errors.txt +++ b/tests/baselines/reference/enumErrors.errors.txt @@ -7,10 +7,10 @@ tests/cases/conformance/enums/enumErrors.ts(26,9): error TS2322: Type 'true' is tests/cases/conformance/enums/enumErrors.ts(27,9): error TS2322: Type 'Date' is not assignable to type 'E11'. tests/cases/conformance/enums/enumErrors.ts(28,9): error TS2304: Cannot find name 'window'. tests/cases/conformance/enums/enumErrors.ts(29,9): error TS2322: Type '{}' is not assignable to type 'E11'. -tests/cases/conformance/enums/enumErrors.ts(35,9): error TS2551: Computed values are not permitted in an enum with string valued members. -tests/cases/conformance/enums/enumErrors.ts(36,9): error TS2551: Computed values are not permitted in an enum with string valued members. -tests/cases/conformance/enums/enumErrors.ts(37,9): error TS2551: Computed values are not permitted in an enum with string valued members. -tests/cases/conformance/enums/enumErrors.ts(38,9): error TS2551: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumErrors.ts(35,9): error TS2553: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumErrors.ts(36,9): error TS2553: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumErrors.ts(37,9): error TS2553: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumErrors.ts(38,9): error TS2553: Computed values are not permitted in an enum with string valued members. ==== tests/cases/conformance/enums/enumErrors.ts (13 errors) ==== @@ -68,15 +68,15 @@ tests/cases/conformance/enums/enumErrors.ts(38,9): error TS2551: Computed values A = '', B = new Date(), ~~~~~~~~~~ -!!! error TS2551: Computed values are not permitted in an enum with string valued members. +!!! error TS2553: Computed values are not permitted in an enum with string valued members. C = window, ~~~~~~ -!!! error TS2551: Computed values are not permitted in an enum with string valued members. +!!! error TS2553: Computed values are not permitted in an enum with string valued members. D = {}, ~~ -!!! error TS2551: Computed values are not permitted in an enum with string valued members. +!!! error TS2553: Computed values are not permitted in an enum with string valued members. E = 1 + 1, ~~~~~ -!!! error TS2551: Computed values are not permitted in an enum with string valued members. +!!! error TS2553: Computed values are not permitted in an enum with string valued members. } \ No newline at end of file From c4c9bf70c429fd5a22537691f841cfc5867db0b9 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 17 May 2017 12:51:37 -0700 Subject: [PATCH 83/83] Add `| undefined` to test --- tests/cases/fourslash/completionListOfUnion.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cases/fourslash/completionListOfUnion.ts b/tests/cases/fourslash/completionListOfUnion.ts index 8e6d1f20a3..5ffaf89e5b 100644 --- a/tests/cases/fourslash/completionListOfUnion.ts +++ b/tests/cases/fourslash/completionListOfUnion.ts @@ -2,8 +2,8 @@ // @strictNullChecks: true -// Non-objects should be skipped, so `| number | null` should have no effect on completions. -////const x: { a: number, b: number } | { a: string, c: string } | { b: boolean } | number | null = { /*x*/ }; +// Primitives should be skipped, so `| number | null | undefined` should have no effect on completions. +////const x: { a: number, b: number } | { a: string, c: string } | { b: boolean } | number | null | undefined = { /*x*/ }; ////interface I { a: number; } ////function f(...args: Array) {}