diff --git a/.travis.yml b/.travis.yml index 4126683eb62..bfc07e2b510 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,8 @@ matrix: node_js: stable osx_image: xcode7.3 env: workerCount=2 + allow_failures: + - os: osx branches: only: @@ -32,3 +34,6 @@ install: cache: directories: - node_modules + +git: + depth: 1 diff --git a/Gulpfile.ts b/Gulpfile.ts index b9b5d2068b2..d677b042250 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -35,6 +35,7 @@ import merge2 = require("merge2"); import intoStream = require("into-stream"); import * as os from "os"; import Linter = require("tslint"); +import fold = require("travis-fold"); const gulp = helpMaker(originalGulp); const mochaParallel = require("./scripts/mocha-parallel.js"); const {runTestsInParallel} = mochaParallel; @@ -964,6 +965,7 @@ gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are: const fileMatcher = RegExp(cmdLineOptions["files"]); const lintOptions = getLinterOptions(); let failed = 0; + if (fold.isTravis()) console.log(fold.start("lint")); return gulp.src(lintTargets) .pipe(insert.transform((contents, file) => { if (!fileMatcher.test(file.path)) return contents; @@ -975,6 +977,7 @@ gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are: return contents; // TODO (weswig): Automatically apply fixes? :3 })) .on("end", () => { + if (fold.isTravis()) console.log(fold.end("lint")); if (failed > 0) { console.error("Linter errors."); process.exit(1); diff --git a/Jakefile.js b/Jakefile.js index a5650a56b16..0624c92f162 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -5,6 +5,7 @@ var os = require("os"); var path = require("path"); var child_process = require("child_process"); var Linter = require("tslint"); +var fold = require("travis-fold"); var runTestsInParallel = require("./scripts/mocha-parallel").runTestsInParallel; // Variables @@ -560,9 +561,19 @@ compileFile( desc("Builds language service server library"); task("lssl", [tsserverLibraryFile, tsserverLibraryDefinitionFile]); +desc("Emit the start of the build fold"); +task("build-fold-start", [] , function() { + if (fold.isTravis()) console.log(fold.start("build")); +}); + +desc("Emit the end of the build fold"); +task("build-fold-end", [] , function() { + if (fold.isTravis()) console.log(fold.end("build")); +}); + // Local target to build the compiler and services desc("Builds the full compiler and services"); -task("local", ["generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile, builtGeneratedDiagnosticMessagesJSON, "lssl"]); +task("local", ["build-fold-start", "generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile, builtGeneratedDiagnosticMessagesJSON, "lssl", "build-fold-end"]); // Local target to build only tsc.js desc("Builds only the compiler"); @@ -998,12 +1009,22 @@ var tslintRulesOutFiles = tslintRules.map(function(p) { return path.join(builtLocalDirectory, "tslint", p + ".js"); }); desc("Compiles tslint rules to js"); -task("build-rules", tslintRulesOutFiles); +task("build-rules", ["build-rules-start"].concat(tslintRulesOutFiles).concat(["build-rules-end"])); tslintRulesFiles.forEach(function(ruleFile, i) { compileFile(tslintRulesOutFiles[i], [ruleFile], [ruleFile], [], /*useBuiltCompiler*/ false, { noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint")}); }); +desc("Emit the start of the build-rules fold"); +task("build-rules-start", [] , function() { + if (fold.isTravis()) console.log(fold.start("build-rules")); +}); + +desc("Emit the end of the build-rules fold"); +task("build-rules-end", [] , function() { + if (fold.isTravis()) console.log(fold.end("build-rules")); +}); + function getLinterOptions() { return { configuration: require("./tslint.json"), @@ -1047,6 +1068,7 @@ var lintTargets = compilerSources desc("Runs tslint on the compiler sources. Optional arguments are: f[iles]=regex"); task("lint", ["build-rules"], function() { + if (fold.isTravis()) console.log(fold.start("lint")); var lintOptions = getLinterOptions(); var failed = 0; var fileMatcher = RegExp(process.env.f || process.env.file || process.env.files || ""); @@ -1062,6 +1084,7 @@ task("lint", ["build-rules"], function() { done[target] = true; } } + if (fold.isTravis()) console.log(fold.end("lint")); if (failed > 0) { fail('Linter errors.', failed); } diff --git a/package.json b/package.json index 9f3122c3374..25d8f0c42ea 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,8 @@ }, "devDependencies": { "@types/browserify": "latest", - "@types/convert-source-map": "latest", "@types/chai": "latest", + "@types/convert-source-map": "latest", "@types/del": "latest", "@types/glob": "latest", "@types/gulp": "latest", @@ -72,6 +72,7 @@ "run-sequence": "latest", "sorcery": "latest", "through2": "latest", + "travis-fold": "latest", "ts-node": "latest", "tslint": "next", "typescript": "next" diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 2547dd2cd5a..573bd0b7e35 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1900,20 +1900,20 @@ namespace ts { } function bindExportAssignment(node: ExportAssignment | BinaryExpression) { - const boundExpression = node.kind === SyntaxKind.ExportAssignment ? (node).expression : (node).right; if (!container.symbol || !container.symbol.exports) { // Export assignment in some sort of block construct bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node)); } - else if (boundExpression.kind === SyntaxKind.Identifier && node.kind === SyntaxKind.ExportAssignment) { - // An export default clause with an identifier exports all meanings of that identifier - declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes); - } else { // An export default clause with an expression exports a value // We want to exclude both class and function here, this is necessary to issue an error when there are both // default export-assignment and default export function and class declaration. - declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Property, SymbolFlags.Class | SymbolFlags.Function | SymbolFlags.Property); + const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node) + // An export default clause with an EntityNameExpression exports all meanings of that identifier + ? SymbolFlags.Alias + // An export default clause with any other expression exports a value + : SymbolFlags.Property; + declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.Property | SymbolFlags.AliasExcludes | SymbolFlags.Class | SymbolFlags.Function); //SymbolFlags.Class | SymbolFlags.Function | SymbolFlags.Property); } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1f2eaea833d..71fdefdc4c9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -664,7 +664,7 @@ namespace ts { // Resolve a given name for a given meaning at a given location. An error is reported if the name was not found and // the nameNotFoundMessage argument is not undefined. Returns the resolved symbol, or undefined if no symbol with // the given name can be found. - function resolveName(location: Node, name: string, meaning: SymbolFlags, nameNotFoundMessage: DiagnosticMessage, nameArg: string | Identifier): Symbol { + function resolveName(location: Node | undefined, name: string, meaning: SymbolFlags, nameNotFoundMessage: DiagnosticMessage, nameArg: string | Identifier): Symbol { let result: Symbol; let lastLocation: Node; let propertyWithInvalidInitializer: Node; @@ -881,7 +881,8 @@ namespace ts { if (!result) { if (nameNotFoundMessage) { - if (!checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg) && + if (!errorLocation || + !checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg) && !checkAndReportErrorForExtendingInterface(errorLocation)) { error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg)); } @@ -930,7 +931,7 @@ namespace ts { } function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: string, nameArg: string | Identifier): boolean { - if (!errorLocation || (errorLocation.kind === SyntaxKind.Identifier && (isTypeReferenceIdentifier(errorLocation)) || isInTypeQuery(errorLocation))) { + if ((errorLocation.kind === SyntaxKind.Identifier && (isTypeReferenceIdentifier(errorLocation)) || isInTypeQuery(errorLocation))) { return false; } @@ -968,28 +969,30 @@ namespace ts { function checkAndReportErrorForExtendingInterface(errorLocation: Node): boolean { - let parentClassExpression = errorLocation; - while (parentClassExpression) { - const kind = parentClassExpression.kind; - if (kind === SyntaxKind.Identifier || kind === SyntaxKind.PropertyAccessExpression) { - parentClassExpression = parentClassExpression.parent; - continue; - } - if (kind === SyntaxKind.ExpressionWithTypeArguments) { - break; - } - return false; - } - if (!parentClassExpression) { - return false; - } - const expression = (parentClassExpression).expression; - if (resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true)) { + const expression = getEntityNameForExtendingInterface(errorLocation); + const isError = !!(expression && resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true)); + if (isError) { error(errorLocation, Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, getTextOfNode(expression)); - return true; } - return false; + return isError; } + /** + * Climbs up parents to an ExpressionWithTypeArguments, and returns its expression, + * but returns undefined if that expression is not an EntityNameExpression. + */ + function getEntityNameForExtendingInterface(node: Node): EntityNameExpression | undefined { + switch (node.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.PropertyAccessExpression: + return node.parent ? getEntityNameForExtendingInterface(node.parent) : undefined; + case SyntaxKind.ExpressionWithTypeArguments: + Debug.assert(isEntityNameExpression((node).expression)); + return (node).expression; + default: + return undefined; + } + } + function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void { Debug.assert((result.flags & SymbolFlags.BlockScopedVariable) !== 0); @@ -1033,7 +1036,7 @@ namespace ts { } function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration { - return forEach(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined); + return find(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined); } function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol { @@ -1168,7 +1171,7 @@ namespace ts { } function getTargetOfExportAssignment(node: ExportAssignment): Symbol { - return resolveEntityName(node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace); + return resolveEntityName(node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace); } function getTargetOfAliasDeclaration(node: Declaration): Symbol { @@ -1278,7 +1281,7 @@ namespace ts { } // Resolves a qualified name and any involved aliases - function resolveEntityName(name: EntityName | Expression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean): Symbol { + function resolveEntityName(name: EntityNameOrEntityNameExpression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean): Symbol | undefined { if (nodeIsMissing(name)) { return undefined; } @@ -1293,7 +1296,7 @@ namespace ts { } } else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) { - const left = name.kind === SyntaxKind.QualifiedName ? (name).left : (name).expression; + const left = name.kind === SyntaxKind.QualifiedName ? (name).left : (name).expression; const right = name.kind === SyntaxKind.QualifiedName ? (name).right : (name).name; const namespace = resolveEntityName(left, SymbolFlags.Namespace, ignoreErrors); @@ -1538,8 +1541,8 @@ namespace ts { function createType(flags: TypeFlags): Type { const result = new Type(checker, flags); - result.id = typeCount; typeCount++; + result.id = typeCount; return result; } @@ -1849,7 +1852,7 @@ namespace ts { } } - function isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult { + function isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult { // get symbol of the first identifier of the entityName let meaning: SymbolFlags; if (entityName.parent.kind === SyntaxKind.TypeQuery || isExpressionWithTypeArgumentsInClassExtendsClause(entityName.parent)) { @@ -3679,7 +3682,7 @@ namespace ts { const baseTypeNodes = getInterfaceBaseTypeNodes(declaration); if (baseTypeNodes) { for (const node of baseTypeNodes) { - if (isSupportedExpressionWithTypeArguments(node)) { + if (isEntityNameExpression(node.expression)) { const baseSymbol = resolveEntityName(node.expression, SymbolFlags.Type, /*ignoreErrors*/ true); if (!baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) || getDeclaredTypeOfClassOrInterface(baseSymbol).thisType) { return false; @@ -4000,6 +4003,9 @@ namespace ts { return createTypeReference((type).target, concatenate((type).typeArguments, [thisArgument || (type).target.thisType])); } + if (type.flags & TypeFlags.Tuple) { + return createTupleType((type as TupleType).elementTypes, thisArgument); + } return type; } @@ -4103,7 +4109,8 @@ namespace ts { function resolveTupleTypeMembers(type: TupleType) { const arrayElementType = getUnionType(type.elementTypes); // Make the tuple type itself the 'this' type by including an extra type argument - const arrayType = resolveStructuredTypeMembers(createTypeFromGenericGlobalType(globalArrayType, [arrayElementType, type])); + // (Unless it's provided in the case that the tuple is a type parameter constraint) + const arrayType = resolveStructuredTypeMembers(createTypeFromGenericGlobalType(globalArrayType, [arrayElementType, type.thisType || type])); const members = createTupleTypeMemberSymbols(type.elementTypes); addInheritedMembers(members, arrayType.properties); setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexInfo, arrayType.numberIndexInfo); @@ -5041,7 +5048,7 @@ namespace ts { return getDeclaredTypeOfSymbol(symbol); } - function getTypeReferenceName(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference): LeftHandSideExpression | EntityName { + function getTypeReferenceName(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference): EntityNameOrEntityNameExpression | undefined { switch (node.kind) { case SyntaxKind.TypeReference: return (node).typeName; @@ -5050,8 +5057,9 @@ namespace ts { case SyntaxKind.ExpressionWithTypeArguments: // We only support expressions that are simple qualified names. For other // expressions this produces undefined. - if (isSupportedExpressionWithTypeArguments(node)) { - return (node).expression; + const expr = (node).expression; + if (isEntityNameExpression(expr)) { + return expr; } // fall through; @@ -5062,7 +5070,7 @@ namespace ts { function resolveTypeReferenceName( node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, - typeReferenceName: LeftHandSideExpression | EntityName) { + typeReferenceName: EntityNameExpression | EntityName) { if (!typeReferenceName) { return unknownSymbol; @@ -5103,15 +5111,14 @@ namespace ts { const typeReferenceName = getTypeReferenceName(node); symbol = resolveTypeReferenceName(node, typeReferenceName); type = getTypeReferenceType(node, symbol); - - links.resolvedSymbol = symbol; - links.resolvedType = type; } else { // We only support expressions that are simple qualified names. For other expressions this produces undefined. - const typeNameOrExpression = node.kind === SyntaxKind.TypeReference ? (node).typeName : - isSupportedExpressionWithTypeArguments(node) ? (node).expression : - undefined; + const typeNameOrExpression: EntityNameOrEntityNameExpression = node.kind === SyntaxKind.TypeReference + ? (node).typeName + : isEntityNameExpression((node).expression) + ? (node).expression + : undefined; symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol; type = symbol === unknownSymbol ? unknownType : symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? getTypeFromClassOrInterfaceReference(node, symbol) : @@ -5230,15 +5237,16 @@ namespace ts { return links.resolvedType; } - function createTupleType(elementTypes: Type[]) { - const id = getTypeListId(elementTypes); - return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes)); + function createTupleType(elementTypes: Type[], thisType?: Type) { + const id = getTypeListId(elementTypes) + "," + (thisType ? thisType.id : 0); + return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes, thisType)); } - function createNewTupleType(elementTypes: Type[]) { + function createNewTupleType(elementTypes: Type[], thisType?: Type) { const propagatedFlags = getPropagatingFlagsOfTypes(elementTypes, /*excludeKinds*/ 0); const type = createObjectType(TypeFlags.Tuple | propagatedFlags); type.elementTypes = elementTypes; + type.thisType = thisType; return type; } @@ -7837,14 +7845,17 @@ namespace ts { } function isDiscriminantProperty(type: Type, name: string) { - if (type && type.flags & TypeFlags.Union) { - const prop = getPropertyOfType(type, name); - if (prop && prop.flags & SymbolFlags.SyntheticProperty) { - if ((prop).isDiscriminantProperty === undefined) { - (prop).isDiscriminantProperty = !(prop).hasCommonType && - isUnitUnionType(getTypeOfSymbol(prop)); + if (type) { + const nonNullType = getNonNullableType(type); + if (nonNullType.flags & TypeFlags.Union) { + const prop = getPropertyOfType(nonNullType, name); + if (prop && prop.flags & SymbolFlags.SyntheticProperty) { + if ((prop).isDiscriminantProperty === undefined) { + (prop).isDiscriminantProperty = !(prop).hasCommonType && + isUnitUnionType(getTypeOfSymbol(prop)); + } + return (prop).isDiscriminantProperty; } - return (prop).isDiscriminantProperty; } } return false; @@ -16379,7 +16390,7 @@ namespace ts { const implementedTypeNodes = getClassImplementsHeritageClauseElements(node); if (implementedTypeNodes) { for (const typeRefNode of implementedTypeNodes) { - if (!isSupportedExpressionWithTypeArguments(typeRefNode)) { + if (!isEntityNameExpression(typeRefNode.expression)) { error(typeRefNode.expression, Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments); } checkTypeReferenceNode(typeRefNode); @@ -16621,7 +16632,7 @@ namespace ts { checkObjectTypeForDuplicateDeclarations(node); } forEach(getInterfaceBaseTypeNodes(node), heritageElement => { - if (!isSupportedExpressionWithTypeArguments(heritageElement)) { + if (!isEntityNameExpression(heritageElement.expression)) { error(heritageElement.expression, Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments); } checkTypeReferenceNode(heritageElement); @@ -17086,20 +17097,21 @@ namespace ts { } } - function getFirstIdentifier(node: EntityName | Expression): Identifier { - while (true) { - if (node.kind === SyntaxKind.QualifiedName) { - node = (node).left; - } - else if (node.kind === SyntaxKind.PropertyAccessExpression) { - node = (node).expression; - } - else { - break; - } + function getFirstIdentifier(node: EntityNameOrEntityNameExpression): Identifier { + switch (node.kind) { + case SyntaxKind.Identifier: + return node; + case SyntaxKind.QualifiedName: + do { + node = (node).left; + } while (node.kind !== SyntaxKind.Identifier); + return node; + case SyntaxKind.PropertyAccessExpression: + do { + node = (node).expression; + } while (node.kind !== SyntaxKind.Identifier); + return node; } - Debug.assert(node.kind === SyntaxKind.Identifier); - return node; } function checkExternalImportOrExportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): boolean { @@ -17798,7 +17810,7 @@ namespace ts { return getLeftSideOfImportEqualsOrExportAssignment(node) !== undefined; } - function getSymbolOfEntityNameOrPropertyAccessExpression(entityName: EntityName | PropertyAccessExpression): Symbol { + function getSymbolOfEntityNameOrPropertyAccessExpression(entityName: EntityName | PropertyAccessExpression): Symbol | undefined { if (isDeclarationName(entityName)) { return getSymbolOfNode(entityName.parent); } @@ -17817,22 +17829,20 @@ namespace ts { } } - if (entityName.parent.kind === SyntaxKind.ExportAssignment) { - return resolveEntityName(entityName, + if (entityName.parent.kind === SyntaxKind.ExportAssignment && isEntityNameExpression(entityName)) { + return resolveEntityName(entityName, /*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); } - if (entityName.kind !== SyntaxKind.PropertyAccessExpression) { - if (isInRightSideOfImportOrExportAssignment(entityName)) { - // Since we already checked for ExportAssignment, this really could only be an Import - const importEqualsDeclaration = getAncestor(entityName, SyntaxKind.ImportEqualsDeclaration); - Debug.assert(importEqualsDeclaration !== undefined); - return getSymbolOfPartOfRightHandSideOfImportEquals(entityName, importEqualsDeclaration, /*dontResolveAlias*/ true); - } + if (entityName.kind !== SyntaxKind.PropertyAccessExpression && isInRightSideOfImportOrExportAssignment(entityName)) { + // Since we already checked for ExportAssignment, this really could only be an Import + const importEqualsDeclaration = getAncestor(entityName, SyntaxKind.ImportEqualsDeclaration); + Debug.assert(importEqualsDeclaration !== undefined); + return getSymbolOfPartOfRightHandSideOfImportEquals(entityName, importEqualsDeclaration, /*dontResolveAlias*/ true); } if (isRightSideOfQualifiedNameOrPropertyAccess(entityName)) { - entityName = entityName.parent; + entityName = entityName.parent; } if (isHeritageClauseElementIdentifier(entityName)) { @@ -18545,7 +18555,7 @@ namespace ts { }; // defined here to avoid outer scope pollution - function getTypeReferenceDirectivesForEntityName(node: EntityName | PropertyAccessExpression): string[] { + function getTypeReferenceDirectivesForEntityName(node: EntityNameOrEntityNameExpression): string[] { // program does not have any files with type reference directives - bail out if (!fileToDirective) { return undefined; diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 6c87ad82955..549410159b0 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -81,7 +81,7 @@ namespace ts { * returns a truthy value, then returns that value. * If no such value is found, the callback is applied to each element of array and undefined is returned. */ - export function forEach(array: T[], callback: (element: T, index: number) => U): U { + export function forEach(array: T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { if (array) { for (let i = 0, len = array.length; i < len; i++) { const result = callback(array[i], i); @@ -93,6 +93,17 @@ namespace ts { return undefined; } + /** Like `forEach`, but assumes existence of array and fails if no truthy value is found. */ + export function find(array: T[], callback: (element: T, index: number) => U | undefined): U { + for (let i = 0, len = array.length; i < len; i++) { + const result = callback(array[i], i); + if (result) { + return result; + } + } + Debug.fail(); + } + export function contains(array: T[], value: T): boolean { if (array) { for (const v of array) { diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index d93a8a0aed0..c93784cd9e0 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -441,7 +441,7 @@ namespace ts { } } - function emitEntityName(entityName: EntityName | PropertyAccessExpression) { + function emitEntityName(entityName: EntityNameOrEntityNameExpression) { const visibilityResult = resolver.isEntityNameVisible(entityName, // Aliases can be written asynchronously so use correct enclosing declaration entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration ? entityName.parent : enclosingDeclaration); @@ -452,9 +452,9 @@ namespace ts { } function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) { - if (isSupportedExpressionWithTypeArguments(node)) { + if (isEntityNameExpression(node.expression)) { Debug.assert(node.expression.kind === SyntaxKind.Identifier || node.expression.kind === SyntaxKind.PropertyAccessExpression); - emitEntityName(node.expression); + emitEntityName(node.expression); if (node.typeArguments) { write("<"); emitCommaList(node.typeArguments, emitType); @@ -1019,7 +1019,7 @@ namespace ts { } function emitTypeOfTypeReference(node: ExpressionWithTypeArguments) { - if (isSupportedExpressionWithTypeArguments(node)) { + if (isEntityNameExpression(node.expression)) { emitTypeWithNewGetSymbolAccessibilityDiagnostic(node, getHeritageClauseVisibilityError); } else if (!isImplementsList && node.expression.kind === SyntaxKind.NullKeyword) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a6e860450c6..74a47f3dbc2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -982,13 +982,19 @@ namespace ts { multiLine?: boolean; } + export type EntityNameExpression = Identifier | PropertyAccessEntityNameExpression; + export type EntityNameOrEntityNameExpression = EntityName | EntityNameExpression; + // @kind(SyntaxKind.PropertyAccessExpression) export interface PropertyAccessExpression extends MemberExpression, Declaration { expression: LeftHandSideExpression; name: Identifier; } - - export type IdentifierOrPropertyAccess = Identifier | PropertyAccessExpression; + /** Brand for a PropertyAccessExpression which, like a QualifiedName, consists of a sequence of identifiers separated by dots. */ + export interface PropertyAccessEntityNameExpression extends PropertyAccessExpression { + _propertyAccessExpressionLikeQualifiedNameBrand?: any; + expression: EntityNameExpression; + } // @kind(SyntaxKind.ElementAccessExpression) export interface ElementAccessExpression extends MemberExpression { @@ -2031,7 +2037,7 @@ namespace ts { writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeBaseConstructorTypeOfClass(node: ClassLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessibilityResult; - isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult; + 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; getReferencedValueDeclaration(reference: Identifier): Declaration; @@ -2040,7 +2046,7 @@ namespace ts { moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean; isArgumentsLocalBinding(node: Identifier): boolean; getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): SourceFile; - getTypeReferenceDirectivesForEntityName(name: EntityName | PropertyAccessExpression): string[]; + getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): string[]; getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[]; } @@ -2371,6 +2377,7 @@ namespace ts { export interface TupleType extends ObjectType { elementTypes: Type[]; // Element types + thisType?: Type; // This-type of tuple (only needed for tuples that are constraints of type parameters) } export interface UnionOrIntersectionType extends Type { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2cfaf1f5cfb..df9f4f95252 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1033,14 +1033,14 @@ namespace ts { && (node).expression.kind === SyntaxKind.SuperKeyword; } - - export function getEntityNameFromTypeNode(node: TypeNode): EntityName | Expression { + export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression { if (node) { switch (node.kind) { case SyntaxKind.TypeReference: return (node).typeName; case SyntaxKind.ExpressionWithTypeArguments: - return (node).expression; + Debug.assert(isEntityNameExpression((node).expression)); + return (node).expression; case SyntaxKind.Identifier: case SyntaxKind.QualifiedName: return (node); @@ -1694,8 +1694,8 @@ namespace ts { // import * as from ... // import { x as } from ... // export { x as } from ... - // export = ... - // export default ... + // export = + // export default export function isAliasSymbolDeclaration(node: Node): boolean { return node.kind === SyntaxKind.ImportEqualsDeclaration || node.kind === SyntaxKind.NamespaceExportDeclaration || @@ -1703,7 +1703,11 @@ namespace ts { node.kind === SyntaxKind.NamespaceImport || node.kind === SyntaxKind.ImportSpecifier || node.kind === SyntaxKind.ExportSpecifier || - node.kind === SyntaxKind.ExportAssignment && (node).expression.kind === SyntaxKind.Identifier; + node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node); + } + + export function exportAssignmentIsAlias(node: ExportAssignment): boolean { + return isEntityNameExpression(node.expression); } export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration | InterfaceDeclaration) { @@ -2681,22 +2685,9 @@ namespace ts { isClassLike(node.parent.parent); } - // Returns false if this heritage clause element's expression contains something unsupported - // (i.e. not a name or dotted name). - export function isSupportedExpressionWithTypeArguments(node: ExpressionWithTypeArguments): boolean { - return isSupportedExpressionWithTypeArgumentsRest(node.expression); - } - - function isSupportedExpressionWithTypeArgumentsRest(node: Expression): boolean { - if (node.kind === SyntaxKind.Identifier) { - return true; - } - else if (isPropertyAccessExpression(node)) { - return isSupportedExpressionWithTypeArgumentsRest(node.expression); - } - else { - return false; - } + export function isEntityNameExpression(node: Expression): node is EntityNameExpression { + return node.kind === SyntaxKind.Identifier || + node.kind === SyntaxKind.PropertyAccessExpression && isEntityNameExpression((node).expression); } export function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index f27e7e1c174..e8e0a11f615 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -750,7 +750,7 @@ namespace Harness { export function readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]) { const fs = new Utils.VirtualFileSystem(path, useCaseSensitiveFileNames()); - for (const file in listFiles(path)) { + for (const file of listFiles(path)) { fs.addFile(file); } return ts.matchFiles(path, extension, exclude, include, useCaseSensitiveFileNames(), getCurrentDirectory(), path => { diff --git a/src/harness/unittests/session.ts b/src/harness/unittests/session.ts index c5285544329..d5e6daa5d60 100644 --- a/src/harness/unittests/session.ts +++ b/src/harness/unittests/session.ts @@ -106,7 +106,7 @@ namespace ts.server { describe("onMessage", () => { it("should not throw when commands are executed with invalid arguments", () => { let i = 0; - for (name in CommandNames) { + for (const name in CommandNames) { if (!Object.prototype.hasOwnProperty.call(CommandNames, name)) { continue; } diff --git a/src/lib/es2015.iterable.d.ts b/src/lib/es2015.iterable.d.ts index e1b9d99762b..de339e2bf2c 100644 --- a/src/lib/es2015.iterable.d.ts +++ b/src/lib/es2015.iterable.d.ts @@ -63,6 +63,26 @@ interface ArrayConstructor { from(iterable: Iterable): Array; } +interface ReadonlyArray { + /** Iterator */ + [Symbol.iterator](): IterableIterator; + + /** + * Returns an array of key, value pairs for every entry in the array + */ + entries(): IterableIterator<[number, T]>; + + /** + * Returns an list of keys in the array + */ + keys(): IterableIterator; + + /** + * Returns an list of values in the array + */ + values(): IterableIterator; +} + interface IArguments { /** Iterator */ [Symbol.iterator](): IterableIterator; diff --git a/tests/baselines/reference/discriminantsAndNullOrUndefined.js b/tests/baselines/reference/discriminantsAndNullOrUndefined.js new file mode 100644 index 00000000000..153950f8ab5 --- /dev/null +++ b/tests/baselines/reference/discriminantsAndNullOrUndefined.js @@ -0,0 +1,44 @@ +//// [discriminantsAndNullOrUndefined.ts] + +// Repro from #10228 + +interface A { kind: 'A'; } +interface B { kind: 'B'; } + +type C = A | B | undefined; + +function never(_: never): never { + throw new Error(); +} + +function useA(_: A): void { } +function useB(_: B): void { } + +declare var c: C; + +if (c !== undefined) { + switch (c.kind) { + case 'A': useA(c); break; + case 'B': useB(c); break; + default: never(c); + } +} + +//// [discriminantsAndNullOrUndefined.js] +// Repro from #10228 +function never(_) { + throw new Error(); +} +function useA(_) { } +function useB(_) { } +if (c !== undefined) { + switch (c.kind) { + case 'A': + useA(c); + break; + case 'B': + useB(c); + break; + default: never(c); + } +} diff --git a/tests/baselines/reference/discriminantsAndNullOrUndefined.symbols b/tests/baselines/reference/discriminantsAndNullOrUndefined.symbols new file mode 100644 index 00000000000..3f95fcf3a3f --- /dev/null +++ b/tests/baselines/reference/discriminantsAndNullOrUndefined.symbols @@ -0,0 +1,61 @@ +=== tests/cases/compiler/discriminantsAndNullOrUndefined.ts === + +// Repro from #10228 + +interface A { kind: 'A'; } +>A : Symbol(A, Decl(discriminantsAndNullOrUndefined.ts, 0, 0)) +>kind : Symbol(A.kind, Decl(discriminantsAndNullOrUndefined.ts, 3, 13)) + +interface B { kind: 'B'; } +>B : Symbol(B, Decl(discriminantsAndNullOrUndefined.ts, 3, 26)) +>kind : Symbol(B.kind, Decl(discriminantsAndNullOrUndefined.ts, 4, 13)) + +type C = A | B | undefined; +>C : Symbol(C, Decl(discriminantsAndNullOrUndefined.ts, 4, 26)) +>A : Symbol(A, Decl(discriminantsAndNullOrUndefined.ts, 0, 0)) +>B : Symbol(B, Decl(discriminantsAndNullOrUndefined.ts, 3, 26)) + +function never(_: never): never { +>never : Symbol(never, Decl(discriminantsAndNullOrUndefined.ts, 6, 27)) +>_ : Symbol(_, Decl(discriminantsAndNullOrUndefined.ts, 8, 15)) + + throw new Error(); +>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +} + +function useA(_: A): void { } +>useA : Symbol(useA, Decl(discriminantsAndNullOrUndefined.ts, 10, 1)) +>_ : Symbol(_, Decl(discriminantsAndNullOrUndefined.ts, 12, 14)) +>A : Symbol(A, Decl(discriminantsAndNullOrUndefined.ts, 0, 0)) + +function useB(_: B): void { } +>useB : Symbol(useB, Decl(discriminantsAndNullOrUndefined.ts, 12, 29)) +>_ : Symbol(_, Decl(discriminantsAndNullOrUndefined.ts, 13, 14)) +>B : Symbol(B, Decl(discriminantsAndNullOrUndefined.ts, 3, 26)) + +declare var c: C; +>c : Symbol(c, Decl(discriminantsAndNullOrUndefined.ts, 15, 11)) +>C : Symbol(C, Decl(discriminantsAndNullOrUndefined.ts, 4, 26)) + +if (c !== undefined) { +>c : Symbol(c, Decl(discriminantsAndNullOrUndefined.ts, 15, 11)) +>undefined : Symbol(undefined) + + switch (c.kind) { +>c.kind : Symbol(kind, Decl(discriminantsAndNullOrUndefined.ts, 3, 13), Decl(discriminantsAndNullOrUndefined.ts, 4, 13)) +>c : Symbol(c, Decl(discriminantsAndNullOrUndefined.ts, 15, 11)) +>kind : Symbol(kind, Decl(discriminantsAndNullOrUndefined.ts, 3, 13), Decl(discriminantsAndNullOrUndefined.ts, 4, 13)) + + case 'A': useA(c); break; +>useA : Symbol(useA, Decl(discriminantsAndNullOrUndefined.ts, 10, 1)) +>c : Symbol(c, Decl(discriminantsAndNullOrUndefined.ts, 15, 11)) + + case 'B': useB(c); break; +>useB : Symbol(useB, Decl(discriminantsAndNullOrUndefined.ts, 12, 29)) +>c : Symbol(c, Decl(discriminantsAndNullOrUndefined.ts, 15, 11)) + + default: never(c); +>never : Symbol(never, Decl(discriminantsAndNullOrUndefined.ts, 6, 27)) +>c : Symbol(c, Decl(discriminantsAndNullOrUndefined.ts, 15, 11)) + } +} diff --git a/tests/baselines/reference/discriminantsAndNullOrUndefined.types b/tests/baselines/reference/discriminantsAndNullOrUndefined.types new file mode 100644 index 00000000000..7a2918ab83b --- /dev/null +++ b/tests/baselines/reference/discriminantsAndNullOrUndefined.types @@ -0,0 +1,68 @@ +=== tests/cases/compiler/discriminantsAndNullOrUndefined.ts === + +// Repro from #10228 + +interface A { kind: 'A'; } +>A : A +>kind : "A" + +interface B { kind: 'B'; } +>B : B +>kind : "B" + +type C = A | B | undefined; +>C : C +>A : A +>B : B + +function never(_: never): never { +>never : (_: never) => never +>_ : never + + throw new Error(); +>new Error() : Error +>Error : ErrorConstructor +} + +function useA(_: A): void { } +>useA : (_: A) => void +>_ : A +>A : A + +function useB(_: B): void { } +>useB : (_: B) => void +>_ : B +>B : B + +declare var c: C; +>c : C +>C : C + +if (c !== undefined) { +>c !== undefined : boolean +>c : C +>undefined : undefined + + switch (c.kind) { +>c.kind : "A" | "B" +>c : A | B +>kind : "A" | "B" + + case 'A': useA(c); break; +>'A' : "A" +>useA(c) : void +>useA : (_: A) => void +>c : A + + case 'B': useB(c); break; +>'B' : "B" +>useB(c) : void +>useB : (_: B) => void +>c : B + + default: never(c); +>never(c) : never +>never : (_: never) => never +>c : never + } +} diff --git a/tests/baselines/reference/exportDefaultProperty.js b/tests/baselines/reference/exportDefaultProperty.js new file mode 100644 index 00000000000..10ba6d6419a --- /dev/null +++ b/tests/baselines/reference/exportDefaultProperty.js @@ -0,0 +1,76 @@ +//// [tests/cases/compiler/exportDefaultProperty.ts] //// + +//// [declarations.d.ts] +// This test is just like exportEqualsProperty, but with `export default`. + +declare namespace foo.bar { + export type X = number; + export const X: number; +} + +declare module "foobar" { + export default foo.bar; +} + +declare module "foobarx" { + export default foo.bar.X; +} + +//// [a.ts] +namespace A { + export class B { constructor(b: number) {} } + export namespace B { export const b: number = 0; } +} +export default A.B; + +//// [b.ts] +export default "foo".length; + +//// [index.ts] +/// +import fooBar from "foobar"; +import X = fooBar.X; +import X2 from "foobarx"; +const x: X = X; +const x2: X2 = X2; + +import B from "./a"; +const b: B = new B(B.b); + +import fooLength from "./b"; +fooLength + 1; + + +//// [a.js] +"use strict"; +var A; +(function (A) { + var B = (function () { + function B(b) { + } + return B; + }()); + A.B = B; + var B; + (function (B) { + B.b = 0; + })(B = A.B || (A.B = {})); +})(A || (A = {})); +exports.__esModule = true; +exports["default"] = A.B; +//// [b.js] +"use strict"; +exports.__esModule = true; +exports["default"] = "foo".length; +//// [index.js] +"use strict"; +/// +var foobar_1 = require("foobar"); +var X = foobar_1["default"].X; +var foobarx_1 = require("foobarx"); +var x = X; +var x2 = foobarx_1["default"]; +var a_1 = require("./a"); +var b = new a_1["default"](a_1["default"].b); +var b_1 = require("./b"); +b_1["default"] + 1; diff --git a/tests/baselines/reference/exportDefaultProperty.symbols b/tests/baselines/reference/exportDefaultProperty.symbols new file mode 100644 index 00000000000..f9edcd154cc --- /dev/null +++ b/tests/baselines/reference/exportDefaultProperty.symbols @@ -0,0 +1,92 @@ +=== tests/cases/compiler/index.ts === +/// +import fooBar from "foobar"; +>fooBar : Symbol(fooBar, Decl(index.ts, 1, 6)) + +import X = fooBar.X; +>X : Symbol(X, Decl(index.ts, 1, 28)) +>fooBar : Symbol(fooBar, Decl(index.ts, 1, 6)) +>X : Symbol(fooBar.X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16)) + +import X2 from "foobarx"; +>X2 : Symbol(X2, Decl(index.ts, 3, 6)) + +const x: X = X; +>x : Symbol(x, Decl(index.ts, 4, 5)) +>X : Symbol(X, Decl(index.ts, 1, 28)) +>X : Symbol(X, Decl(index.ts, 1, 28)) + +const x2: X2 = X2; +>x2 : Symbol(x2, Decl(index.ts, 5, 5)) +>X2 : Symbol(X2, Decl(index.ts, 3, 6)) +>X2 : Symbol(X2, Decl(index.ts, 3, 6)) + +import B from "./a"; +>B : Symbol(B, Decl(index.ts, 7, 6)) + +const b: B = new B(B.b); +>b : Symbol(b, Decl(index.ts, 8, 5)) +>B : Symbol(B, Decl(index.ts, 7, 6)) +>B : Symbol(B, Decl(index.ts, 7, 6)) +>B.b : Symbol(B.b, Decl(a.ts, 2, 37)) +>B : Symbol(B, Decl(index.ts, 7, 6)) +>b : Symbol(B.b, Decl(a.ts, 2, 37)) + +import fooLength from "./b"; +>fooLength : Symbol(fooLength, Decl(index.ts, 10, 6)) + +fooLength + 1; +>fooLength : Symbol(fooLength, Decl(index.ts, 10, 6)) + +=== tests/cases/compiler/declarations.d.ts === +// This test is just like exportEqualsProperty, but with `export default`. + +declare namespace foo.bar { +>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0)) +>bar : Symbol(bar, Decl(declarations.d.ts, 2, 22)) + + export type X = number; +>X : Symbol(X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16)) + + export const X: number; +>X : Symbol(X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16)) +} + +declare module "foobar" { + export default foo.bar; +>foo.bar : Symbol(default, Decl(declarations.d.ts, 2, 22)) +>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0)) +>bar : Symbol(default, Decl(declarations.d.ts, 2, 22)) +} + +declare module "foobarx" { + export default foo.bar.X; +>foo.bar.X : Symbol(default, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16)) +>foo.bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22)) +>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0)) +>bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22)) +>X : Symbol(default, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16)) +} + +=== tests/cases/compiler/a.ts === +namespace A { +>A : Symbol(A, Decl(a.ts, 0, 0)) + + export class B { constructor(b: number) {} } +>B : Symbol(B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48)) +>b : Symbol(b, Decl(a.ts, 1, 33)) + + export namespace B { export const b: number = 0; } +>B : Symbol(B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48)) +>b : Symbol(b, Decl(a.ts, 2, 37)) +} +export default A.B; +>A.B : Symbol(default, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48)) +>A : Symbol(A, Decl(a.ts, 0, 0)) +>B : Symbol(default, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48)) + +=== tests/cases/compiler/b.ts === +export default "foo".length; +>"foo".length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + diff --git a/tests/baselines/reference/exportDefaultProperty.types b/tests/baselines/reference/exportDefaultProperty.types new file mode 100644 index 00000000000..47cfabfbc16 --- /dev/null +++ b/tests/baselines/reference/exportDefaultProperty.types @@ -0,0 +1,97 @@ +=== tests/cases/compiler/index.ts === +/// +import fooBar from "foobar"; +>fooBar : typeof fooBar + +import X = fooBar.X; +>X : number +>fooBar : typeof fooBar +>X : number + +import X2 from "foobarx"; +>X2 : number + +const x: X = X; +>x : number +>X : number +>X : number + +const x2: X2 = X2; +>x2 : number +>X2 : number +>X2 : number + +import B from "./a"; +>B : typeof B + +const b: B = new B(B.b); +>b : B +>B : B +>new B(B.b) : B +>B : typeof B +>B.b : number +>B : typeof B +>b : number + +import fooLength from "./b"; +>fooLength : number + +fooLength + 1; +>fooLength + 1 : number +>fooLength : number +>1 : number + +=== tests/cases/compiler/declarations.d.ts === +// This test is just like exportEqualsProperty, but with `export default`. + +declare namespace foo.bar { +>foo : typeof foo +>bar : typeof bar + + export type X = number; +>X : number + + export const X: number; +>X : number +} + +declare module "foobar" { + export default foo.bar; +>foo.bar : typeof default +>foo : typeof foo +>bar : typeof default +} + +declare module "foobarx" { + export default foo.bar.X; +>foo.bar.X : number +>foo.bar : typeof foo.bar +>foo : typeof foo +>bar : typeof foo.bar +>X : number +} + +=== tests/cases/compiler/a.ts === +namespace A { +>A : typeof A + + export class B { constructor(b: number) {} } +>B : B +>b : number + + export namespace B { export const b: number = 0; } +>B : typeof B +>b : number +>0 : number +} +export default A.B; +>A.B : typeof default +>A : typeof A +>B : typeof default + +=== tests/cases/compiler/b.ts === +export default "foo".length; +>"foo".length : number +>"foo" : string +>length : number + diff --git a/tests/baselines/reference/exportEqualsProperty.js b/tests/baselines/reference/exportEqualsProperty.js new file mode 100644 index 00000000000..2fd8a8c8511 --- /dev/null +++ b/tests/baselines/reference/exportEqualsProperty.js @@ -0,0 +1,72 @@ +//// [tests/cases/compiler/exportEqualsProperty.ts] //// + +//// [declarations.d.ts] +// This test is just like exportDefaultProperty, but with `export =`. + +declare namespace foo.bar { + export type X = number; + export const X: number; +} + +declare module "foobar" { + export = foo.bar; +} + +declare module "foobarx" { + export = foo.bar.X; +} + +//// [a.ts] +namespace A { + export class B { constructor(b: number) {} } + export namespace B { export const b: number = 0; } +} +export = A.B; + +//// [b.ts] +export = "foo".length; + +//// [index.ts] +/// +import { X } from "foobar"; +import X2 = require("foobarx"); +const x: X = X; +const x2: X2 = X2; + +import B = require("./a"); +const b: B = new B(B.b); + +import fooLength = require("./b"); +fooLength + 1; + + +//// [a.js] +"use strict"; +var A; +(function (A) { + var B = (function () { + function B(b) { + } + return B; + }()); + A.B = B; + var B; + (function (B) { + B.b = 0; + })(B = A.B || (A.B = {})); +})(A || (A = {})); +module.exports = A.B; +//// [b.js] +"use strict"; +module.exports = "foo".length; +//// [index.js] +"use strict"; +/// +var foobar_1 = require("foobar"); +var X2 = require("foobarx"); +var x = foobar_1.X; +var x2 = X2; +var B = require("./a"); +var b = new B(B.b); +var fooLength = require("./b"); +fooLength + 1; diff --git a/tests/baselines/reference/exportEqualsProperty.symbols b/tests/baselines/reference/exportEqualsProperty.symbols new file mode 100644 index 00000000000..43c9ed32518 --- /dev/null +++ b/tests/baselines/reference/exportEqualsProperty.symbols @@ -0,0 +1,87 @@ +=== tests/cases/compiler/index.ts === +/// +import { X } from "foobar"; +>X : Symbol(X, Decl(index.ts, 1, 8)) + +import X2 = require("foobarx"); +>X2 : Symbol(X2, Decl(index.ts, 1, 27)) + +const x: X = X; +>x : Symbol(x, Decl(index.ts, 3, 5)) +>X : Symbol(X, Decl(index.ts, 1, 8)) +>X : Symbol(X, Decl(index.ts, 1, 8)) + +const x2: X2 = X2; +>x2 : Symbol(x2, Decl(index.ts, 4, 5)) +>X2 : Symbol(X2, Decl(index.ts, 1, 27)) +>X2 : Symbol(X2, Decl(index.ts, 1, 27)) + +import B = require("./a"); +>B : Symbol(B, Decl(index.ts, 4, 18)) + +const b: B = new B(B.b); +>b : Symbol(b, Decl(index.ts, 7, 5)) +>B : Symbol(B, Decl(index.ts, 4, 18)) +>B : Symbol(B, Decl(index.ts, 4, 18)) +>B.b : Symbol(B.b, Decl(a.ts, 2, 37)) +>B : Symbol(B, Decl(index.ts, 4, 18)) +>b : Symbol(B.b, Decl(a.ts, 2, 37)) + +import fooLength = require("./b"); +>fooLength : Symbol(fooLength, Decl(index.ts, 7, 24)) + +fooLength + 1; +>fooLength : Symbol(fooLength, Decl(index.ts, 7, 24)) + +=== tests/cases/compiler/declarations.d.ts === +// This test is just like exportDefaultProperty, but with `export =`. + +declare namespace foo.bar { +>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0)) +>bar : Symbol(bar, Decl(declarations.d.ts, 2, 22)) + + export type X = number; +>X : Symbol(X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16)) + + export const X: number; +>X : Symbol(X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16)) +} + +declare module "foobar" { + export = foo.bar; +>foo.bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22)) +>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0)) +>bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22)) +} + +declare module "foobarx" { + export = foo.bar.X; +>foo.bar.X : Symbol(foo.bar.X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16)) +>foo.bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22)) +>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0)) +>bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22)) +>X : Symbol(foo.bar.X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16)) +} + +=== tests/cases/compiler/a.ts === +namespace A { +>A : Symbol(A, Decl(a.ts, 0, 0)) + + export class B { constructor(b: number) {} } +>B : Symbol(B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48)) +>b : Symbol(b, Decl(a.ts, 1, 33)) + + export namespace B { export const b: number = 0; } +>B : Symbol(B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48)) +>b : Symbol(b, Decl(a.ts, 2, 37)) +} +export = A.B; +>A.B : Symbol(A.B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48)) +>A : Symbol(A, Decl(a.ts, 0, 0)) +>B : Symbol(A.B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48)) + +=== tests/cases/compiler/b.ts === +export = "foo".length; +>"foo".length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + diff --git a/tests/baselines/reference/exportEqualsProperty.types b/tests/baselines/reference/exportEqualsProperty.types new file mode 100644 index 00000000000..a92af53b12b --- /dev/null +++ b/tests/baselines/reference/exportEqualsProperty.types @@ -0,0 +1,92 @@ +=== tests/cases/compiler/index.ts === +/// +import { X } from "foobar"; +>X : number + +import X2 = require("foobarx"); +>X2 : number + +const x: X = X; +>x : number +>X : number +>X : number + +const x2: X2 = X2; +>x2 : number +>X2 : number +>X2 : number + +import B = require("./a"); +>B : typeof B + +const b: B = new B(B.b); +>b : B +>B : B +>new B(B.b) : B +>B : typeof B +>B.b : number +>B : typeof B +>b : number + +import fooLength = require("./b"); +>fooLength : number + +fooLength + 1; +>fooLength + 1 : number +>fooLength : number +>1 : number + +=== tests/cases/compiler/declarations.d.ts === +// This test is just like exportDefaultProperty, but with `export =`. + +declare namespace foo.bar { +>foo : typeof foo +>bar : typeof bar + + export type X = number; +>X : number + + export const X: number; +>X : number +} + +declare module "foobar" { + export = foo.bar; +>foo.bar : typeof foo.bar +>foo : typeof foo +>bar : typeof foo.bar +} + +declare module "foobarx" { + export = foo.bar.X; +>foo.bar.X : number +>foo.bar : typeof foo.bar +>foo : typeof foo +>bar : typeof foo.bar +>X : number +} + +=== tests/cases/compiler/a.ts === +namespace A { +>A : typeof A + + export class B { constructor(b: number) {} } +>B : B +>b : number + + export namespace B { export const b: number = 0; } +>B : typeof B +>b : number +>0 : number +} +export = A.B; +>A.B : typeof A.B +>A : typeof A +>B : typeof A.B + +=== tests/cases/compiler/b.ts === +export = "foo".length; +>"foo".length : number +>"foo" : string +>length : number + diff --git a/tests/baselines/reference/thisInTupleTypeParameterConstraints.js b/tests/baselines/reference/thisInTupleTypeParameterConstraints.js new file mode 100644 index 00000000000..c63fbf61991 --- /dev/null +++ b/tests/baselines/reference/thisInTupleTypeParameterConstraints.js @@ -0,0 +1,29 @@ +//// [thisInTupleTypeParameterConstraints.ts] +/// + +interface Boolean {} +interface IArguments {} +interface Function {} +interface Number {} +interface RegExp {} +interface Object {} +interface String {} + +interface Array { + // 4 methods will run out of memory if this-types are not instantiated + // correctly for tuple types that are type parameter constraints + map(arg: this): void; + reduceRight(arg: this): void; + reduce(arg: this): void; + reduce2(arg: this): void; +} + +declare function f number]>(a: T): void; +let x: [(x: number) => number]; +f(x); + + +//// [thisInTupleTypeParameterConstraints.js] +/// +var x; +f(x); diff --git a/tests/baselines/reference/thisInTupleTypeParameterConstraints.symbols b/tests/baselines/reference/thisInTupleTypeParameterConstraints.symbols new file mode 100644 index 00000000000..4d2bef22c55 --- /dev/null +++ b/tests/baselines/reference/thisInTupleTypeParameterConstraints.symbols @@ -0,0 +1,66 @@ +=== tests/cases/compiler/thisInTupleTypeParameterConstraints.ts === +/// + +interface Boolean {} +>Boolean : Symbol(Boolean, Decl(thisInTupleTypeParameterConstraints.ts, 0, 0)) + +interface IArguments {} +>IArguments : Symbol(IArguments, Decl(thisInTupleTypeParameterConstraints.ts, 2, 20)) + +interface Function {} +>Function : Symbol(Function, Decl(thisInTupleTypeParameterConstraints.ts, 3, 23)) + +interface Number {} +>Number : Symbol(Number, Decl(thisInTupleTypeParameterConstraints.ts, 4, 21)) + +interface RegExp {} +>RegExp : Symbol(RegExp, Decl(thisInTupleTypeParameterConstraints.ts, 5, 19)) + +interface Object {} +>Object : Symbol(Object, Decl(thisInTupleTypeParameterConstraints.ts, 6, 19)) + +interface String {} +>String : Symbol(String, Decl(thisInTupleTypeParameterConstraints.ts, 7, 19)) + +interface Array { +>Array : Symbol(Array, Decl(thisInTupleTypeParameterConstraints.ts, 8, 19)) +>T : Symbol(T, Decl(thisInTupleTypeParameterConstraints.ts, 10, 16)) + + // 4 methods will run out of memory if this-types are not instantiated + // correctly for tuple types that are type parameter constraints + map(arg: this): void; +>map : Symbol(Array.map, Decl(thisInTupleTypeParameterConstraints.ts, 10, 20)) +>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 13, 8)) +>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 13, 11)) + + reduceRight(arg: this): void; +>reduceRight : Symbol(Array.reduceRight, Decl(thisInTupleTypeParameterConstraints.ts, 13, 28)) +>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 14, 16)) +>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 14, 19)) + + reduce(arg: this): void; +>reduce : Symbol(Array.reduce, Decl(thisInTupleTypeParameterConstraints.ts, 14, 36)) +>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 15, 11)) +>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 15, 14)) + + reduce2(arg: this): void; +>reduce2 : Symbol(Array.reduce2, Decl(thisInTupleTypeParameterConstraints.ts, 15, 31)) +>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 16, 12)) +>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 16, 15)) +} + +declare function f number]>(a: T): void; +>f : Symbol(f, Decl(thisInTupleTypeParameterConstraints.ts, 17, 1)) +>T : Symbol(T, Decl(thisInTupleTypeParameterConstraints.ts, 19, 19)) +>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 19, 31)) +>a : Symbol(a, Decl(thisInTupleTypeParameterConstraints.ts, 19, 54)) +>T : Symbol(T, Decl(thisInTupleTypeParameterConstraints.ts, 19, 19)) + +let x: [(x: number) => number]; +>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 20, 3)) +>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 20, 9)) + +f(x); +>f : Symbol(f, Decl(thisInTupleTypeParameterConstraints.ts, 17, 1)) +>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 20, 3)) + diff --git a/tests/baselines/reference/thisInTupleTypeParameterConstraints.types b/tests/baselines/reference/thisInTupleTypeParameterConstraints.types new file mode 100644 index 00000000000..7daafe02bfc --- /dev/null +++ b/tests/baselines/reference/thisInTupleTypeParameterConstraints.types @@ -0,0 +1,67 @@ +=== tests/cases/compiler/thisInTupleTypeParameterConstraints.ts === +/// + +interface Boolean {} +>Boolean : Boolean + +interface IArguments {} +>IArguments : IArguments + +interface Function {} +>Function : Function + +interface Number {} +>Number : Number + +interface RegExp {} +>RegExp : RegExp + +interface Object {} +>Object : Object + +interface String {} +>String : String + +interface Array { +>Array : T[] +>T : T + + // 4 methods will run out of memory if this-types are not instantiated + // correctly for tuple types that are type parameter constraints + map(arg: this): void; +>map : (arg: this) => void +>U : U +>arg : this + + reduceRight(arg: this): void; +>reduceRight : (arg: this) => void +>U : U +>arg : this + + reduce(arg: this): void; +>reduce : (arg: this) => void +>U : U +>arg : this + + reduce2(arg: this): void; +>reduce2 : (arg: this) => void +>U : U +>arg : this +} + +declare function f number]>(a: T): void; +>f : number]>(a: T) => void +>T : T +>x : number +>a : T +>T : T + +let x: [(x: number) => number]; +>x : [(x: number) => number] +>x : number + +f(x); +>f(x) : void +>f : number]>(a: T) => void +>x : [(x: number) => number] + diff --git a/tests/cases/compiler/discriminantsAndNullOrUndefined.ts b/tests/cases/compiler/discriminantsAndNullOrUndefined.ts new file mode 100644 index 00000000000..8346fa8adea --- /dev/null +++ b/tests/cases/compiler/discriminantsAndNullOrUndefined.ts @@ -0,0 +1,25 @@ +// @strictNullChecks: true + +// Repro from #10228 + +interface A { kind: 'A'; } +interface B { kind: 'B'; } + +type C = A | B | undefined; + +function never(_: never): never { + throw new Error(); +} + +function useA(_: A): void { } +function useB(_: B): void { } + +declare var c: C; + +if (c !== undefined) { + switch (c.kind) { + case 'A': useA(c); break; + case 'B': useB(c); break; + default: never(c); + } +} \ No newline at end of file diff --git a/tests/cases/compiler/exportDefaultProperty.ts b/tests/cases/compiler/exportDefaultProperty.ts new file mode 100644 index 00000000000..4a4b4139025 --- /dev/null +++ b/tests/cases/compiler/exportDefaultProperty.ts @@ -0,0 +1,39 @@ +// This test is just like exportEqualsProperty, but with `export default`. + +// @Filename: declarations.d.ts +declare namespace foo.bar { + export type X = number; + export const X: number; +} + +declare module "foobar" { + export default foo.bar; +} + +declare module "foobarx" { + export default foo.bar.X; +} + +// @Filename: a.ts +namespace A { + export class B { constructor(b: number) {} } + export namespace B { export const b: number = 0; } +} +export default A.B; + +// @Filename: b.ts +export default "foo".length; + +// @Filename: index.ts +/// +import fooBar from "foobar"; +import X = fooBar.X; +import X2 from "foobarx"; +const x: X = X; +const x2: X2 = X2; + +import B from "./a"; +const b: B = new B(B.b); + +import fooLength from "./b"; +fooLength + 1; diff --git a/tests/cases/compiler/exportEqualsProperty.ts b/tests/cases/compiler/exportEqualsProperty.ts new file mode 100644 index 00000000000..0d14815a5bd --- /dev/null +++ b/tests/cases/compiler/exportEqualsProperty.ts @@ -0,0 +1,38 @@ +// This test is just like exportDefaultProperty, but with `export =`. + +// @Filename: declarations.d.ts +declare namespace foo.bar { + export type X = number; + export const X: number; +} + +declare module "foobar" { + export = foo.bar; +} + +declare module "foobarx" { + export = foo.bar.X; +} + +// @Filename: a.ts +namespace A { + export class B { constructor(b: number) {} } + export namespace B { export const b: number = 0; } +} +export = A.B; + +// @Filename: b.ts +export = "foo".length; + +// @Filename: index.ts +/// +import { X } from "foobar"; +import X2 = require("foobarx"); +const x: X = X; +const x2: X2 = X2; + +import B = require("./a"); +const b: B = new B(B.b); + +import fooLength = require("./b"); +fooLength + 1; diff --git a/tests/cases/compiler/thisInTupleTypeParameterConstraints.ts b/tests/cases/compiler/thisInTupleTypeParameterConstraints.ts new file mode 100644 index 00000000000..b6d0d338d85 --- /dev/null +++ b/tests/cases/compiler/thisInTupleTypeParameterConstraints.ts @@ -0,0 +1,22 @@ +/// + +interface Boolean {} +interface IArguments {} +interface Function {} +interface Number {} +interface RegExp {} +interface Object {} +interface String {} + +interface Array { + // 4 methods will run out of memory if this-types are not instantiated + // correctly for tuple types that are type parameter constraints + map(arg: this): void; + reduceRight(arg: this): void; + reduce(arg: this): void; + reduce2(arg: this): void; +} + +declare function f number]>(a: T): void; +let x: [(x: number) => number]; +f(x);