diff --git a/package.json b/package.json index 7b8abfaae43..261cdfa64b7 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,8 @@ "browserify": "latest", "istanbul": "latest", "mocha-fivemat-progress-reporter": "latest", - "tslint": "latest", + "tslint": "next", + "typescript": "next", "tsd": "latest" }, "scripts": { diff --git a/scripts/tslint/booleanTriviaRule.ts b/scripts/tslint/booleanTriviaRule.ts index be32a870ff4..93c312ab870 100644 --- a/scripts/tslint/booleanTriviaRule.ts +++ b/scripts/tslint/booleanTriviaRule.ts @@ -1,6 +1,5 @@ -/// -/// - +import * as Lint from "tslint/lib/lint"; +import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_STRING_FACTORY = (name: string, currently: string) => `Tag boolean argument as '${name}' (currently '${currently}')`; @@ -19,7 +18,7 @@ class BooleanTriviaWalker extends Lint.RuleWalker { visitCallExpression(node: ts.CallExpression) { super.visitCallExpression(node); - if (node.arguments) { + if (node.arguments) { const targetCallSignature = this.checker.getResolvedSignature(node); if (!!targetCallSignature) { const targetParameters = targetCallSignature.getParameters(); @@ -37,7 +36,7 @@ class BooleanTriviaWalker extends Lint.RuleWalker { let triviaContent: string; const ranges = ts.getLeadingCommentRanges(arg.getFullText(), 0); if (ranges && ranges.length === 1 && ranges[0].kind === ts.SyntaxKind.MultiLineCommentTrivia) { - triviaContent = arg.getFullText().slice(ranges[0].pos + 2, ranges[0].end - 2); //+/-2 to remove /**/ + triviaContent = arg.getFullText().slice(ranges[0].pos + 2, ranges[0].end - 2); // +/-2 to remove /**/ } if (triviaContent !== param.getName()) { this.addFailure(this.createFailure(arg.getStart(source), arg.getWidth(source), Rule.FAILURE_STRING_FACTORY(param.getName(), triviaContent))); @@ -45,6 +44,6 @@ class BooleanTriviaWalker extends Lint.RuleWalker { } } } - } + } } } diff --git a/scripts/tslint/nextLineRule.ts b/scripts/tslint/nextLineRule.ts index 6d803fc7f88..d25652f7bce 100644 --- a/scripts/tslint/nextLineRule.ts +++ b/scripts/tslint/nextLineRule.ts @@ -1,5 +1,5 @@ -/// -/// +import * as Lint from "tslint/lib/lint"; +import * as ts from "typescript"; const OPTION_CATCH = "check-catch"; const OPTION_ELSE = "check-else"; diff --git a/scripts/tslint/noNullRule.ts b/scripts/tslint/noNullRule.ts index 2a2c5bc3717..8e9deca996b 100644 --- a/scripts/tslint/noNullRule.ts +++ b/scripts/tslint/noNullRule.ts @@ -1,5 +1,5 @@ -/// -/// +import * as Lint from "tslint/lib/lint"; +import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/scripts/tslint/preferConstRule.ts b/scripts/tslint/preferConstRule.ts index 29160a9c634..e4ffa396fb7 100644 --- a/scripts/tslint/preferConstRule.ts +++ b/scripts/tslint/preferConstRule.ts @@ -1,5 +1,5 @@ -/// -/// +import * as Lint from "tslint/lib/lint"; +import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { @@ -101,13 +101,13 @@ class PreferConstWalker extends Lint.RuleWalker { this.visitBindingLiteralExpression(node as (ts.ArrayLiteralExpression | ts.ObjectLiteralExpression)); } } - + private visitBindingLiteralExpression(node: ts.ArrayLiteralExpression | ts.ObjectLiteralExpression) { if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) { const pattern = node as ts.ObjectLiteralExpression; for (const element of pattern.properties) { if (element.name.kind === ts.SyntaxKind.Identifier) { - this.markAssignment(element.name as ts.Identifier) + this.markAssignment(element.name as ts.Identifier); } else if (isBindingPattern(element.name)) { this.visitBindingPatternIdentifiers(element.name as ts.BindingPattern); diff --git a/scripts/tslint/typeOperatorSpacingRule.ts b/scripts/tslint/typeOperatorSpacingRule.ts index 23925493340..4196d024768 100644 --- a/scripts/tslint/typeOperatorSpacingRule.ts +++ b/scripts/tslint/typeOperatorSpacingRule.ts @@ -1,5 +1,5 @@ -/// -/// +import * as Lint from "tslint/lib/lint"; +import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 2993ec3aa0c..8b88da5b749 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -175,9 +175,14 @@ namespace ts { symbol.members = {}; } - if (symbolFlags & SymbolFlags.Value && !symbol.valueDeclaration) { - symbol.valueDeclaration = node; - } + if (symbolFlags & SymbolFlags.Value) { + const valueDeclaration = symbol.valueDeclaration; + if (!valueDeclaration || + (valueDeclaration.kind !== node.kind && valueDeclaration.kind === SyntaxKind.ModuleDeclaration)) { + // other kinds of value declarations take precedence over modules + symbol.valueDeclaration = node; + } + } } // Should not be called on a declaration with a computed property name, diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3083f50e979..36ca3eeb760 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -122,8 +122,8 @@ namespace ts { const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - const anySignature = createSignature(undefined, undefined, emptyArray, anyType, undefined, 0, false, false); - const unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, undefined, 0, false, false); + const anySignature = createSignature(undefined, undefined, emptyArray, anyType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); + const unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); const globals: SymbolTable = {}; @@ -200,6 +200,10 @@ namespace ts { "symbol": { type: esSymbolType, flags: TypeFlags.ESSymbol + }, + "undefined": { + type: undefinedType, + flags: TypeFlags.ContainsUndefinedOrNull } }; @@ -295,7 +299,12 @@ namespace ts { target.constEnumOnlyModule = false; } target.flags |= source.flags; - if (!target.valueDeclaration && source.valueDeclaration) target.valueDeclaration = source.valueDeclaration; + if (source.valueDeclaration && + (!target.valueDeclaration || + (target.valueDeclaration.kind === SyntaxKind.ModuleDeclaration && source.valueDeclaration.kind !== SyntaxKind.ModuleDeclaration))) { + // other kinds of value declarations take precedence over modules + target.valueDeclaration = source.valueDeclaration; + } forEach(source.declarations, node => { target.declarations.push(node); }); @@ -2267,7 +2276,7 @@ namespace ts { return false; } resolutionTargets.push(target); - resolutionResults.push(true); + resolutionResults.push(/*items*/ true); resolutionPropertyNames.push(propertyName); return true; } @@ -3339,7 +3348,7 @@ namespace ts { function getDefaultConstructSignatures(classType: InterfaceType): Signature[] { if (!hasClassBaseType(classType)) { - return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, false, false)]; + return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)]; } const baseConstructorType = getBaseConstructorTypeOfClass(classType); const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); @@ -3964,7 +3973,7 @@ namespace ts { } function getSignatureInstantiation(signature: Signature, typeArguments: Type[]): Signature { - return instantiateSignature(signature, createTypeMapper(signature.typeParameters, typeArguments), true); + return instantiateSignature(signature, createTypeMapper(signature.typeParameters, typeArguments), /*eraseTypeParameters*/ true); } function getErasedSignature(signature: Signature): Signature { @@ -3974,7 +3983,7 @@ namespace ts { signature.erasedSignatureCache = instantiateSignature(getErasedSignature(signature.target), signature.mapper); } else { - signature.erasedSignatureCache = instantiateSignature(signature, createTypeEraser(signature.typeParameters), true); + signature.erasedSignatureCache = instantiateSignature(signature, createTypeEraser(signature.typeParameters), /*eraseTypeParameters*/ true); } } return signature.erasedSignatureCache; @@ -5090,7 +5099,7 @@ namespace ts { let result = Ternary.True; const sourceTypes = source.types; for (const sourceType of sourceTypes) { - const related = typeRelatedToSomeType(sourceType, target, false); + const related = typeRelatedToSomeType(sourceType, target, /*reportErrors*/ false); if (!related) { return Ternary.False; } @@ -5488,7 +5497,7 @@ namespace ts { const saveErrorInfo = errorInfo; let related = isRelatedTo(s, t, reportErrors); if (!related) { - related = isRelatedTo(t, s, false); + related = isRelatedTo(t, s, /*reportErrors*/ false); if (!related) { if (reportErrors) { reportError(Diagnostics.Types_of_parameters_0_and_1_are_incompatible, @@ -5615,7 +5624,7 @@ namespace ts { let related: Ternary; if (sourceStringType && sourceNumberType) { // If we know for sure we're testing both string and numeric index types then only report errors from the second one - related = isRelatedTo(sourceStringType, targetType, false) || isRelatedTo(sourceNumberType, targetType, reportErrors); + related = isRelatedTo(sourceStringType, targetType, /*reportErrors*/ false) || isRelatedTo(sourceNumberType, targetType, reportErrors); } else { related = isRelatedTo(sourceStringType || sourceNumberType, targetType, reportErrors); @@ -6470,6 +6479,10 @@ namespace ts { assumeTrue = !assumeTrue; } const typeInfo = primitiveTypeInfo[right.text]; + // Don't narrow `undefined` + if (typeInfo && typeInfo.type === undefinedType) { + return type; + } // If the type to be narrowed is any and we're checking a primitive with assumeTrue=true, return the primitive if (!!(type.flags & TypeFlags.Any) && typeInfo && assumeTrue) { return typeInfo.type; @@ -11348,11 +11361,17 @@ namespace ts { const errorNode: Node = (subsequentNode).name || subsequentNode; // TODO(jfreeman): These are methods, so handle computed name case if (node.name && (subsequentNode).name && (node.name).text === ((subsequentNode).name).text) { - // the only situation when this is possible (same kind\same name but different symbol) - mixed static and instance class members - Debug.assert(node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature); - Debug.assert((node.flags & NodeFlags.Static) !== (subsequentNode.flags & NodeFlags.Static)); - const diagnostic = node.flags & NodeFlags.Static ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static; - error(errorNode, diagnostic); + const reportError = + (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) && + (node.flags & NodeFlags.Static) !== (subsequentNode.flags & NodeFlags.Static); + // we can get here in two cases + // 1. mixed static and instance class members + // 2. something with the same name was defined before the set of overloads that prevents them from merging + // here we'll report error only for the first case since for second we should already report error in binder + if (reportError) { + const diagnostic = node.flags & NodeFlags.Static ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static; + error(errorNode, diagnostic); + } return; } else if (nodeIsPresent((subsequentNode).body)) { diff --git a/src/compiler/core.ts b/src/compiler/core.ts index b6efb449c76..c93f3aebc2d 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -847,7 +847,7 @@ namespace ts { } export function fail(message?: string): void { - Debug.assert(false, message); + Debug.assert(/*expression*/ false, message); } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index b6082df7553..64be8151eed 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1254,7 +1254,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi function emitCommaList(nodes: Node[]) { if (nodes) { - emitList(nodes, 0, nodes.length, /*multiline*/ false, /*trailingComma*/ false); + emitList(nodes, 0, nodes.length, /*multiLine*/ false, /*trailingComma*/ false); } } @@ -2153,7 +2153,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } else if (languageVersion >= ScriptTarget.ES6 || !forEach(elements, isSpreadElementExpression)) { write("["); - emitLinePreservingList(node, node.elements, elements.hasTrailingComma, /*spacesBetweenBraces:*/ false); + emitLinePreservingList(node, node.elements, elements.hasTrailingComma, /*spacesBetweenBraces*/ false); write("]"); } else { @@ -2177,7 +2177,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // then try to preserve the original shape of the object literal. // Otherwise just try to preserve the formatting. if (numElements === properties.length) { - emitLinePreservingList(node, properties, /* allowTrailingComma */ languageVersion >= ScriptTarget.ES5, /* spacesBetweenBraces */ true); + emitLinePreservingList(node, properties, /*allowTrailingComma*/ languageVersion >= ScriptTarget.ES5, /*spacesBetweenBraces*/ true); } else { const multiLine = (node.flags & NodeFlags.MultiLine) !== 0; @@ -2727,7 +2727,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(".bind.apply("); emit(target); write(", [void 0].concat("); - emitListWithSpread(node.arguments, /*needsUniqueCopy*/ false, /*multiline*/ false, /*trailingComma*/ false, /*useConcat*/ false); + emitListWithSpread(node.arguments, /*needsUniqueCopy*/ false, /*multiLine*/ false, /*trailingComma*/ false, /*useConcat*/ false); write(")))"); write("()"); } @@ -2944,7 +2944,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi synthesizedLHS = createSynthesizedNode(SyntaxKind.ElementAccessExpression, /*startsOnNewLine*/ false); - const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldEmitCommaBeforeAssignment*/ false); + const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefineTempVariablesInPlace*/ false, /*shouldEmitCommaBeforeAssignment*/ false); synthesizedLHS.expression = identifier; if (leftHandSideExpression.argumentExpression.kind !== SyntaxKind.NumericLiteral && @@ -2963,7 +2963,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write("("); synthesizedLHS = createSynthesizedNode(SyntaxKind.PropertyAccessExpression, /*startsOnNewLine*/ false); - const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldemitCommaBeforeAssignment*/ false); + const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefineTempVariablesInPlace*/ false, /*shouldEmitCommaBeforeAssignment*/ false); synthesizedLHS.expression = identifier; (synthesizedLHS).dotToken = leftHandSideExpression.dotToken; @@ -3143,10 +3143,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi function emitDoStatementWorker(node: DoStatement, loop: ConvertedLoop) { write("do"); if (loop) { - emitConvertedLoopCall(loop, /* emitAsBlock */ true); + emitConvertedLoopCall(loop, /*emitAsBlock*/ true); } else { - emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true); + emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true); } if (node.statement.kind === SyntaxKind.Block) { write(" "); @@ -3169,10 +3169,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(")"); if (loop) { - emitConvertedLoopCall(loop, /* emitAsBlock */ true); + emitConvertedLoopCall(loop, /*emitAsBlock*/ true); } else { - emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true); + emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true); } } @@ -3494,8 +3494,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(`switch(${loopResultVariable}) {`); increaseIndent(); - emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalBreaks, /* isBreak */ true, loopResultVariable, outerLoop); - emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalContinues, /* isBreak */ false, loopResultVariable, outerLoop); + emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalBreaks, /*isBreak*/ true, loopResultVariable, outerLoop); + emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalContinues, /*isBreak*/ false, loopResultVariable, outerLoop); decreaseIndent(); writeLine(); @@ -3559,10 +3559,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(")"); if (loop) { - emitConvertedLoopCall(loop, /* emitAsBlock */ true); + emitConvertedLoopCall(loop, /*emitAsBlock*/ true); } else { - emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true); + emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true); } } @@ -3600,10 +3600,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitToken(SyntaxKind.CloseParenToken, node.expression.end); if (loop) { - emitConvertedLoopCall(loop, /* emitAsBlock */ true); + emitConvertedLoopCall(loop, /*emitAsBlock*/ true); } else { - emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true); + emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true); } } @@ -3743,10 +3743,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (loop) { writeLine(); - emitConvertedLoopCall(loop, /* emitAsBlock */ false); + emitConvertedLoopCall(loop, /*emitAsBlock*/ false); } else { - emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ false); + emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ false); } writeLine(); @@ -3780,11 +3780,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi let labelMarker: string; if (node.kind === SyntaxKind.BreakStatement) { labelMarker = `break-${node.label.text}`; - setLabeledJump(convertedLoopState, /* isBreak */ true, node.label.text, labelMarker); + setLabeledJump(convertedLoopState, /*isBreak*/ true, node.label.text, labelMarker); } else { labelMarker = `continue-${node.label.text}`; - setLabeledJump(convertedLoopState, /* isBreak */ false, node.label.text, labelMarker); + setLabeledJump(convertedLoopState, /*isBreak*/ false, node.label.text, labelMarker); } write(`return "${labelMarker}";`); } @@ -4210,7 +4210,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi let index: Expression; const nameIsComputed = propName.kind === SyntaxKind.ComputedPropertyName; if (nameIsComputed) { - index = ensureIdentifier((propName).expression, /* reuseIdentifierExpression */ false); + index = ensureIdentifier((propName).expression, /*reuseIdentifierExpressions*/ false); } else { // We create a synthetic copy of the identifier in order to avoid the rewriting that might @@ -4965,8 +4965,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi increaseIndent(); writeLine(); emitLeadingComments(node.body); + emitStart(body); write("return "); emit(body); + emitEnd(body); write(";"); emitTrailingComments(node.body); @@ -5340,7 +5342,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitEnd(baseTypeElement); } } - emitPropertyDeclarations(node, getInitializedProperties(node, /*static:*/ false)); + emitPropertyDeclarations(node, getInitializedProperties(node, /*isStatic*/ false)); if (ctor) { let statements: Node[] = (ctor.body).statements; if (superCall) { @@ -5462,7 +5464,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // // This keeps the expression as an expression, while ensuring that the static parts // of it have been initialized by the time it is used. - const staticProperties = getInitializedProperties(node, /*static:*/ true); + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); const isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === SyntaxKind.ClassExpression; let tempVariable: Identifier; @@ -5524,7 +5526,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi for (var property of staticProperties) { write(","); writeLine(); - emitPropertyDeclaration(node, property, /*receiver:*/ tempVariable, /*isExpression:*/ true); + emitPropertyDeclaration(node, property, /*receiver*/ tempVariable, /*isExpression*/ true); } write(","); writeLine(); @@ -5598,7 +5600,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi writeLine(); emitConstructor(node, baseTypeNode); emitMemberFunctionsForES5AndLower(node); - emitPropertyDeclarations(node, getInitializedProperties(node, /*static:*/ true)); + emitPropertyDeclarations(node, getInitializedProperties(node, /*isStatic*/ true)); writeLine(); emitDecoratorsOfClass(node); writeLine(); @@ -8054,11 +8056,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi * Emit comments associated with node that will not be emitted into JS file */ function emitCommentsOnNotEmittedNode(node: Node) { - emitLeadingCommentsWorker(node, /*isEmittedNode:*/ false); + emitLeadingCommentsWorker(node, /*isEmittedNode*/ false); } function emitLeadingComments(node: Node) { - return emitLeadingCommentsWorker(node, /*isEmittedNode:*/ true); + return emitLeadingCommentsWorker(node, /*isEmittedNode*/ true); } function emitLeadingCommentsWorker(node: Node, isEmittedNode: boolean) { @@ -8087,7 +8089,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitNewLineBeforeLeadingComments(currentLineMap, writer, node, leadingComments); // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space - emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator:*/ true, newLine, writeComment); + emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment); } function emitTrailingComments(node: Node) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 4d870b002ec..d15e79aa125 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -727,10 +727,10 @@ namespace ts { const contextFlagsToClear = context & contextFlags; if (contextFlagsToClear) { // clear the requested context flags - setContextFlag(false, contextFlagsToClear); + setContextFlag(/*val*/ false, contextFlagsToClear); const result = func(); // restore the context flags we just cleared - setContextFlag(true, contextFlagsToClear); + setContextFlag(/*val*/ true, contextFlagsToClear); return result; } @@ -748,10 +748,10 @@ namespace ts { const contextFlagsToSet = context & ~contextFlags; if (contextFlagsToSet) { // set the requested context flags - setContextFlag(true, contextFlagsToSet); + setContextFlag(/*val*/ true, contextFlagsToSet); const result = func(); // reset the context flags we just set - setContextFlag(false, contextFlagsToSet); + setContextFlag(/*val*/ false, contextFlagsToSet); return result; } @@ -1103,11 +1103,11 @@ namespace ts { } function parsePropertyName(): PropertyName { - return parsePropertyNameWorker(/*allowComputedPropertyNames:*/ true); + return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true); } function parseSimplePropertyName(): Identifier | LiteralExpression { - return parsePropertyNameWorker(/*allowComputedPropertyNames:*/ false); + return parsePropertyNameWorker(/*allowComputedPropertyNames*/ false); } function isSimplePropertyName() { @@ -1390,7 +1390,7 @@ namespace ts { function isInSomeParsingContext(): boolean { for (let kind = 0; kind < ParsingContext.Count; kind++) { if (parsingContext & (1 << kind)) { - if (isListElement(kind, /* inErrorRecovery */ true) || isListTerminator(kind)) { + if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) { return true; } } @@ -1407,7 +1407,7 @@ namespace ts { result.pos = getNodePos(); while (!isListTerminator(kind)) { - if (isListElement(kind, /* inErrorRecovery */ false)) { + if (isListElement(kind, /*inErrorRecovery*/ false)) { const element = parseListElement(kind, parseElement); result.push(element); @@ -1756,7 +1756,7 @@ namespace ts { let commaStart = -1; // Meaning the previous token was not a comma while (true) { - if (isListElement(kind, /* inErrorRecovery */ false)) { + if (isListElement(kind, /*inErrorRecovery*/ false)) { result.push(parseListElement(kind, parseElement)); commaStart = scanner.getTokenPos(); if (parseOptional(SyntaxKind.CommaToken)) { @@ -1864,7 +1864,7 @@ namespace ts { // Report that we need an identifier. However, report it right after the dot, // and not on the next token. This is because the next token might actually // be an identifier and the error would be quite confusing. - return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentToken*/ true, Diagnostics.Identifier_expected); + return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); } } @@ -2614,7 +2614,7 @@ namespace ts { // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator const saveDecoratorContext = inDecoratorContext(); if (saveDecoratorContext) { - setDecoratorContext(false); + setDecoratorContext(/*val*/ false); } let expr = parseAssignmentExpressionOrHigher(); @@ -2624,7 +2624,7 @@ namespace ts { } if (saveDecoratorContext) { - setDecoratorContext(true); + setDecoratorContext(/*val*/ true); } return expr; } @@ -2778,7 +2778,7 @@ namespace ts { node.parameters.pos = parameter.pos; node.parameters.end = parameter.end; - node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>"); + node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>"); node.body = parseArrowFunctionExpressionBody(/*isAsync*/ false); return finishNode(node); @@ -3578,7 +3578,7 @@ namespace ts { parseExpected(SyntaxKind.GreaterThanToken); } else { - parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*advance*/ false); + parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); scanJsxText(); } node = createNode(SyntaxKind.JsxSelfClosingElement, fullStart); @@ -3614,7 +3614,7 @@ namespace ts { parseExpected(SyntaxKind.CloseBraceToken); } else { - parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*advance*/ false); + parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false); scanJsxText(); } @@ -3659,7 +3659,7 @@ namespace ts { parseExpected(SyntaxKind.GreaterThanToken); } else { - parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*advance*/ false); + parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); scanJsxText(); } return finishNode(node); @@ -3978,7 +3978,7 @@ namespace ts { // function BindingIdentifier[opt](FormalParameters){ FunctionBody } const saveDecoratorContext = inDecoratorContext(); if (saveDecoratorContext) { - setDecoratorContext(false); + setDecoratorContext(/*val*/ false); } const node = createNode(SyntaxKind.FunctionExpression); @@ -3998,7 +3998,7 @@ namespace ts { node.body = parseFunctionBlock(/*allowYield*/ isGenerator, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ false); if (saveDecoratorContext) { - setDecoratorContext(true); + setDecoratorContext(/*val*/ true); } return finishNode(node); @@ -4044,13 +4044,13 @@ namespace ts { // arrow function. The body of the function is not in [Decorator] context. const saveDecoratorContext = inDecoratorContext(); if (saveDecoratorContext) { - setDecoratorContext(false); + setDecoratorContext(/*val*/ false); } const block = parseBlock(ignoreMissingOpenBrace, diagnosticMessage); if (saveDecoratorContext) { - setDecoratorContext(true); + setDecoratorContext(/*val*/ true); } setYieldContext(savedYieldContext); @@ -6167,7 +6167,7 @@ namespace ts { if (sourceFile.statements.length === 0) { // If we don't have any statements in the current source file, then there's no real // way to incrementally parse. So just do a full parse instead. - return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setNodeParents*/ true); + return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true); } // Make sure we're not trying to incrementally update a source file more than once. Once @@ -6231,7 +6231,7 @@ namespace ts { // inconsistent tree. Setting the parents on the new tree should be very fast. We // will immediately bail out of walking any subtrees when we can see that their parents // are already correct. - const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /* setParentNode */ true); + const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true); return result; } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 80995afe5aa..8048c8aaad7 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -369,13 +369,13 @@ namespace ts { } if (!tryReuseStructureFromOldProgram()) { - forEach(rootNames, name => processRootFile(name, false)); + forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false)); // Do not process the default library if: // - The '--noLib' flag is used. // - A 'no-default-lib' reference comment is encountered in // processing the root files. if (!skipDefaultLib) { - processRootFile(host.getDefaultLibFileName(options), true); + processRootFile(host.getDefaultLibFileName(options), /*isDefaultLib*/ true); } } @@ -870,7 +870,7 @@ namespace ts { let imports: LiteralExpression[]; for (const node of file.statements) { - collect(node, /* allowRelativeModuleNames */ true, /* collectOnlyRequireCalls */ false); + collect(node, /*allowRelativeModuleNames*/ true, /*collectOnlyRequireCalls*/ false); } file.imports = imports || emptyArray; @@ -906,7 +906,7 @@ namespace ts { // TypeScript 1.0 spec (April 2014): 12.1.6 // An ExternalImportDeclaration in anAmbientExternalModuleDeclaration may reference other external modules // only through top - level external module names. Relative external module names are not permitted. - collect(node, /* allowRelativeModuleNames */ false, collectOnlyRequireCalls); + collect(node, /*allowRelativeModuleNames*/ false, collectOnlyRequireCalls); }); } break; @@ -918,7 +918,7 @@ namespace ts { (imports || (imports = [])).push((node).arguments[0]); } else { - forEachChild(node, node => collect(node, allowRelativeModuleNames, /* collectOnlyRequireCalls */ true)); + forEachChild(node, node => collect(node, allowRelativeModuleNames, /*collectOnlyRequireCalls*/ true)); } } } @@ -1039,7 +1039,7 @@ namespace ts { function processReferencedFiles(file: SourceFile, basePath: string) { forEach(file.referencedFiles, ref => { const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName); - processSourceFile(referencedFileName, /* isDefaultLib */ false, file, ref.pos, ref.end); + processSourceFile(referencedFileName, /*isDefaultLib*/ false, file, ref.pos, ref.end); }); } @@ -1057,7 +1057,7 @@ namespace ts { const resolution = resolutions[i]; setResolvedModule(file, moduleNames[i], resolution); if (resolution && !options.noResolve) { - const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /* isDefaultLib */ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end); + const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /*isDefaultLib*/ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end); if (importedFile && resolution.isExternalLibraryImport) { if (!isExternalModule(importedFile)) { diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 9703ef8517b..4289d910608 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -1634,11 +1634,11 @@ namespace ts { } function lookAhead(callback: () => T): T { - return speculationHelper(callback, /*isLookahead:*/ true); + return speculationHelper(callback, /*isLookahead*/ true); } function tryScan(callback: () => T): T { - return speculationHelper(callback, /*isLookahead:*/ false); + return speculationHelper(callback, /*isLookahead*/ false); } function setText(newText: string, start: number, length: number) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7dc1c018153..e99cdee676b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2180,17 +2180,17 @@ namespace ts { /* @internal */ export interface CommandLineOptionBase { name: string; - type: string | Map; // "string", "number", "boolean", or an object literal mapping named values to actual values - isFilePath?: boolean; // True if option value is a path or fileName - shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help' - description?: DiagnosticMessage; // The message describing what the command line switch does - paramType?: DiagnosticMessage; // The name to be used for a non-boolean option's parameter + type: "string" | "number" | "boolean" | Map; // a value of a primitive type, or an object literal mapping named values to actual values + isFilePath?: boolean; // True if option value is a path or fileName + shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help' + description?: DiagnosticMessage; // The message describing what the command line switch does + paramType?: DiagnosticMessage; // The name to be used for a non-boolean option's parameter experimental?: boolean; } /* @internal */ export interface CommandLineOptionOfPrimitiveType extends CommandLineOptionBase { - type: string; // "string" | "number" | "boolean" + type: "string" | "number" | "boolean"; } /* @internal */ diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 84999302bb7..5e142776979 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -49,7 +49,7 @@ class CompilerBaselineRunner extends RunnerBase { let testCaseContent: { settings: Harness.TestCaseParser.CompilerSettings; testUnitData: Harness.TestCaseParser.TestUnitData[]; }; let units: Harness.TestCaseParser.TestUnitData[]; - let tcSettings: Harness.TestCaseParser.CompilerSettings; + let harnessSettings: Harness.TestCaseParser.CompilerSettings; let lastUnit: Harness.TestCaseParser.TestUnitData; let rootDir: string; @@ -58,46 +58,43 @@ class CompilerBaselineRunner extends RunnerBase { let program: ts.Program; let options: ts.CompilerOptions; // equivalent to the files that will be passed on the command line - let toBeCompiled: { unitName: string; content: string }[]; + let toBeCompiled: Harness.Compiler.TestFile[]; // equivalent to other files on the file system not directly passed to the compiler (ie things that are referenced by other files) - let otherFiles: { unitName: string; content: string }[]; - let harnessCompiler: Harness.Compiler.HarnessCompiler; + let otherFiles: Harness.Compiler.TestFile[]; before(() => { justName = fileName.replace(/^.*[\\\/]/, ""); // strips the fileName from the path. content = Harness.IO.readFile(fileName); testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, fileName); units = testCaseContent.testUnitData; - tcSettings = testCaseContent.settings; + harnessSettings = testCaseContent.settings; lastUnit = units[units.length - 1]; rootDir = lastUnit.originalFilePath.indexOf("conformance") === -1 ? "tests/cases/compiler/" : lastUnit.originalFilePath.substring(0, lastUnit.originalFilePath.lastIndexOf("/")) + "/"; - harnessCompiler = Harness.Compiler.getCompiler(); // We need to assemble the list of input files for the compiler and other related files on the 'filesystem' (ie in a multi-file test) // If the last file in a test uses require or a triple slash reference we'll assume all other files will be brought in via references, // otherwise, assume all files are just meant to be in the same compilation session without explicit references to one another. toBeCompiled = []; otherFiles = []; if (/require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) { - toBeCompiled.push({ unitName: rootDir + lastUnit.name, content: lastUnit.content }); + toBeCompiled.push({ unitName: ts.combinePaths(rootDir, lastUnit.name), content: lastUnit.content }); units.forEach(unit => { if (unit.name !== lastUnit.name) { - otherFiles.push({ unitName: rootDir + unit.name, content: unit.content }); + otherFiles.push({ unitName: ts.combinePaths(rootDir, unit.name), content: unit.content }); } }); } else { toBeCompiled = units.map(unit => { - return { unitName: rootDir + unit.name, content: unit.content }; + return { unitName: ts.combinePaths(rootDir, unit.name), content: unit.content }; }); } - options = harnessCompiler.compileFiles(toBeCompiled, otherFiles, function (compileResult, _program) { - result = compileResult; - // The program will be used by typeWriter - program = _program; - }, function (settings) { - harnessCompiler.setCompilerSettings(tcSettings); - }); + const output = Harness.Compiler.HarnessCompiler.compileFiles( + toBeCompiled, otherFiles, harnessSettings, /* options */ undefined, /* currentDirectory */ undefined); + + options = output.options; + result = output.result; + program = output.program; }); after(() => { @@ -107,7 +104,7 @@ class CompilerBaselineRunner extends RunnerBase { content = undefined; testCaseContent = undefined; units = undefined; - tcSettings = undefined; + harnessSettings = undefined; lastUnit = undefined; rootDir = undefined; result = undefined; @@ -115,14 +112,13 @@ class CompilerBaselineRunner extends RunnerBase { options = undefined; toBeCompiled = undefined; otherFiles = undefined; - harnessCompiler = undefined; }); function getByteOrderMarkText(file: Harness.Compiler.GeneratedFile): string { return file.writeByteOrderMark ? "\u00EF\u00BB\u00BF" : ""; } - function getErrorBaseline(toBeCompiled: { unitName: string; content: string }[], otherFiles: { unitName: string; content: string }[], result: Harness.Compiler.CompilerResult) { + function getErrorBaseline(toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], result: Harness.Compiler.CompilerResult) { return Harness.Compiler.getErrorBaseline(toBeCompiled.concat(otherFiles), result.errors); } @@ -184,9 +180,9 @@ class CompilerBaselineRunner extends RunnerBase { } } - const declFileCompilationResult = harnessCompiler.compileDeclarationFiles(toBeCompiled, otherFiles, result, function (settings) { - harnessCompiler.setCompilerSettings(tcSettings); - }, options); + const declFileCompilationResult = + Harness.Compiler.HarnessCompiler.compileDeclarationFiles( + toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined); if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) { jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n"; @@ -259,8 +255,8 @@ class CompilerBaselineRunner extends RunnerBase { const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName)); - const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ true); - const pullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ false); + const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true); + const pullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ false); const fullResults: ts.Map = {}; const pullResults: ts.Map = {}; @@ -274,14 +270,14 @@ class CompilerBaselineRunner extends RunnerBase { // The second gives symbols for all identifiers. let e1: Error, e2: Error; try { - checkBaseLines(/*isSymbolBaseLine:*/ false); + checkBaseLines(/*isSymbolBaseLine*/ false); } catch (e) { e1 = e; } try { - checkBaseLines(/*isSymbolBaseLine:*/ true); + checkBaseLines(/*isSymbolBaseLine*/ true); } catch (e) { e2 = e; @@ -367,7 +363,6 @@ class CompilerBaselineRunner extends RunnerBase { public initializeTests() { describe(this.testSuiteName + " tests", () => { describe("Setup compiler for compiler baselines", () => { - const harnessCompiler = Harness.Compiler.getCompiler(); this.parseOptions(); }); diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index f5802787198..84a9c0e771f 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -385,9 +385,9 @@ namespace FourSlash { } // Opens a file given its 0-based index or fileName - public openFile(index: number): void; - public openFile(name: string): void; - public openFile(indexOrName: any) { + public openFile(index: number, content?: string): void; + public openFile(name: string, content?: string): void; + public openFile(indexOrName: any, content?: string) { const fileToOpen: FourSlashFile = this.findFile(indexOrName); fileToOpen.fileName = ts.normalizeSlashes(fileToOpen.fileName); this.activeFile = fileToOpen; @@ -395,7 +395,7 @@ namespace FourSlash { this.scenarioActions.push(``); // Let the host know that this file is now open - this.languageServiceAdapterHost.openFile(fileToOpen.fileName); + this.languageServiceAdapterHost.openFile(fileToOpen.fileName, content); } public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, negative: boolean) { @@ -514,7 +514,7 @@ namespace FourSlash { this.scenarioActions.push(``); if (actual !== expected) { - this.printErrorLog(false, errors); + this.printErrorLog(/*expectErrors*/ false, errors); const errorMsg = "Actual number of errors (" + actual + ") does not match expected number (" + expected + ")"; Harness.IO.log(errorMsg); this.raiseError(errorMsg); @@ -577,7 +577,7 @@ namespace FourSlash { public verifyMemberListCount(expectedCount: number, negative: boolean) { if (expectedCount === 0) { if (negative) { - this.verifyMemberListIsEmpty(false); + this.verifyMemberListIsEmpty(/*negative*/ false); return; } else { @@ -1357,7 +1357,7 @@ namespace FourSlash { if (this.enableFormatting) { const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeOptions); if (edits.length) { - offset += this.applyEdits(this.activeFile.fileName, edits, true); + offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); // this.checkPostEditInletiants(); } } @@ -1399,7 +1399,7 @@ namespace FourSlash { if (this.enableFormatting) { const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeOptions); if (edits.length) { - offset += this.applyEdits(this.activeFile.fileName, edits, true); + offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); } } } @@ -1459,7 +1459,7 @@ namespace FourSlash { if (this.enableFormatting) { const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeOptions); if (edits.length) { - offset += this.applyEdits(this.activeFile.fileName, edits, true); + offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); // this.checkPostEditInletiants(); } } @@ -1487,7 +1487,7 @@ namespace FourSlash { if (this.enableFormatting) { const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeOptions); if (edits.length) { - offset += this.applyEdits(this.activeFile.fileName, edits, true); + offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); this.checkPostEditInletiants(); } } @@ -1573,7 +1573,7 @@ namespace FourSlash { this.scenarioActions.push(""); const edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, this.formatCodeOptions); - this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, true); + this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); this.fixCaretPosition(); } @@ -1581,7 +1581,7 @@ namespace FourSlash { this.taoInvalidReason = "formatSelection NYI"; const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, end, this.formatCodeOptions); - this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, true); + this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); this.fixCaretPosition(); } @@ -2393,10 +2393,16 @@ namespace FourSlash { // here we cache the JS output and reuse it for every test. let fourslashJsOutput: string; { - const host = Harness.Compiler.createCompilerHost([{ unitName: Harness.Compiler.fourslashFileName, content: undefined }], + const fourslashFile: Harness.Compiler.TestFileWithPath = { + unitName: Harness.Compiler.fourslashFileName, + content: undefined, + path: ts.toPath(Harness.Compiler.fourslashFileName, Harness.IO.getCurrentDirectory(), Harness.Compiler.getCanonicalFileName) + }; + const host = Harness.Compiler.createCompilerHost([fourslashFile], (fn, contents) => fourslashJsOutput = contents, ts.ScriptTarget.Latest, - Harness.IO.useCaseSensitiveFileNames()); + Harness.IO.useCaseSensitiveFileNames(), + Harness.IO.getCurrentDirectory()); const program = ts.createProgram([Harness.Compiler.fourslashFileName], { noResolve: true, target: ts.ScriptTarget.ES3 }, host); @@ -2410,15 +2416,28 @@ namespace FourSlash { currentTestState = new TestState(basePath, testType, testData); + const currentDirectory = Harness.IO.getCurrentDirectory(); + const useCaseSensitiveFileNames = Harness.IO.useCaseSensitiveFileNames(); + const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames); + let result = ""; + const fourslashFile: Harness.Compiler.TestFileWithPath = { + unitName: Harness.Compiler.fourslashFileName, + content: undefined, + path: ts.toPath(Harness.Compiler.fourslashFileName, currentDirectory, getCanonicalFileName) + }; + const testFile: Harness.Compiler.TestFileWithPath = { + unitName: fileName, + content: content, + path: ts.toPath(fileName, currentDirectory, getCanonicalFileName) + }; + const host = Harness.Compiler.createCompilerHost( - [ - { unitName: Harness.Compiler.fourslashFileName, content: undefined }, - { unitName: fileName, content: content } - ], + [ fourslashFile, testFile ], (fn, contents) => result = contents, ts.ScriptTarget.Latest, - Harness.IO.useCaseSensitiveFileNames()); + useCaseSensitiveFileNames, + currentDirectory); const program = ts.createProgram([Harness.Compiler.fourslashFileName, fileName], { outFile: "fourslashTestOutput.js", noResolve: true, target: ts.ScriptTarget.ES3 }, host); diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 0c6eb379f2c..2717864faf7 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -630,7 +630,7 @@ namespace Harness { function getResolvedPathFromServer(path: string) { const xhr = new XMLHttpRequest(); try { - xhr.open("GET", path + "?resolve", false); + xhr.open("GET", path + "?resolve", /*async*/ false); xhr.send(); } catch (e) { @@ -649,7 +649,7 @@ namespace Harness { export function getFileFromServerSync(url: string): XHRResponse { const xhr = new XMLHttpRequest(); try { - xhr.open("GET", url, false); + xhr.open("GET", url, /*async*/ false); xhr.send(); } catch (e) { @@ -664,7 +664,7 @@ namespace Harness { const xhr = new XMLHttpRequest(); try { const actionMsg = "?action=" + action; - xhr.open("POST", url + actionMsg, false); + xhr.open("POST", url + actionMsg, /*async*/ false); xhr.setRequestHeader("Access-Control-Allow-Origin", "*"); xhr.send(contents); } @@ -905,41 +905,34 @@ namespace Harness { } export function createCompilerHost( - inputFiles: { unitName: string; content: string; }[], + inputFiles: TestFileWithPath[], writeFile: (fn: string, contents: string, writeByteOrderMark: boolean) => void, scriptTarget: ts.ScriptTarget, useCaseSensitiveFileNames: boolean, // the currentDirectory is needed for rwcRunner to passed in specified current directory to compiler host - currentDirectory?: string, + currentDirectory: string, newLineKind?: ts.NewLineKind): ts.CompilerHost { // Local get canonical file name function, that depends on passed in parameter for useCaseSensitiveFileNames - function getCanonicalFileName(fileName: string): string { - return useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(); - } + const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames); - const filemap: { [fileName: string]: ts.SourceFile; } = {}; - const getCurrentDirectory = currentDirectory === undefined ? Harness.IO.getCurrentDirectory : () => currentDirectory; + const fileMap: ts.FileMap = ts.createFileMap(); // Register input files - function register(file: { unitName: string; content: string; }) { + function register(file: TestFileWithPath) { if (file.content !== undefined) { const fileName = ts.normalizePath(file.unitName); const sourceFile = createSourceFileAndAssertInvariants(fileName, file.content, scriptTarget); - filemap[getCanonicalFileName(fileName)] = sourceFile; - filemap[getCanonicalFileName(ts.getNormalizedAbsolutePath(fileName, getCurrentDirectory()))] = sourceFile; + fileMap.set(file.path, sourceFile); } }; inputFiles.forEach(register); function getSourceFile(fn: string, languageVersion: ts.ScriptTarget) { fn = ts.normalizePath(fn); - if (Object.prototype.hasOwnProperty.call(filemap, getCanonicalFileName(fn))) { - return filemap[getCanonicalFileName(fn)]; - } - else if (currentDirectory) { - const canonicalAbsolutePath = getCanonicalFileName(ts.getNormalizedAbsolutePath(fn, currentDirectory)); - return Object.prototype.hasOwnProperty.call(filemap, getCanonicalFileName(canonicalAbsolutePath)) ? filemap[canonicalAbsolutePath] : undefined; + const path = ts.toPath(fn, currentDirectory, getCanonicalFileName); + if (fileMap.contains(path)) { + return fileMap.get(path); } else if (fn === fourslashFileName) { const tsFn = "tests/cases/fourslash/" + fourslashFileName; @@ -961,7 +954,7 @@ namespace Harness { Harness.IO.newLine(); return { - getCurrentDirectory, + getCurrentDirectory: () => currentDirectory, getSourceFile, getDefaultLibFileName: options => defaultLibFileName, writeFile, @@ -1036,95 +1029,74 @@ namespace Harness { } } - export class HarnessCompiler { - private inputFiles: { unitName: string; content: string }[] = []; - private compileOptions: ts.CompilerOptions; - private settings: Harness.TestCaseParser.CompilerSettings = {}; + export interface TestFile { + unitName: string; + content: string; + } + export interface TestFileWithPath extends TestFile { + path: ts.Path; + } - private lastErrors: ts.Diagnostic[]; + export interface CompilationOutput { + result: CompilerResult; + program: ts.Program; + options: ts.CompilerOptions & HarnessOptions; + } - public reset() { - this.inputFiles = []; - this.settings = {}; - this.lastErrors = []; - } - - public reportCompilationErrors() { - return this.lastErrors; - } - - public setCompilerSettings(tcSettings: Harness.TestCaseParser.CompilerSettings) { - this.settings = tcSettings; - } - - public addInputFiles(files: { unitName: string; content: string }[]) { - files.forEach(file => this.addInputFile(file)); - } - - public addInputFile(file: { unitName: string; content: string }) { - this.inputFiles.push(file); - } - - public setCompilerOptions(options?: ts.CompilerOptions) { - this.compileOptions = options || { noResolve: false }; - } - - public emitAll(ioHost?: IEmitterIOHost) { - this.compileFiles(this.inputFiles, - /*otherFiles*/ [], - /*onComplete*/ result => { - result.files.forEach(writeFile); - result.declFilesCode.forEach(writeFile); - result.sourceMaps.forEach(writeFile); - }, - /*settingsCallback*/ () => { }, - this.compileOptions); - - function writeFile(file: GeneratedFile) { - ioHost.writeFile(file.fileName, file.code, false); - } - } - - public compileFiles(inputFiles: { unitName: string; content: string }[], - otherFiles: { unitName: string; content: string }[], - onComplete: (result: CompilerResult, program: ts.Program) => void, - settingsCallback?: (settings: ts.CompilerOptions) => void, - options?: ts.CompilerOptions & HarnessOptions, + export namespace HarnessCompiler { + export function compileFiles( + inputFiles: TestFile[], + otherFiles: TestFile[], + harnessSettings: TestCaseParser.CompilerSettings, + compilerOptions: ts.CompilerOptions, // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file - currentDirectory?: string) { + currentDirectory: string): CompilationOutput { - options = options || { noResolve: false }; + const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.clone(compilerOptions) : { noResolve: false }; options.target = options.target || ts.ScriptTarget.ES3; options.module = options.module || ts.ModuleKind.None; options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed; options.noErrorTruncation = true; options.skipDefaultLibCheck = true; - if (settingsCallback) { - settingsCallback(null); - } - const newLine = "\r\n"; + currentDirectory = currentDirectory || Harness.IO.getCurrentDirectory(); // Parse settings - setCompilerOptionsFromHarnessSetting(this.settings, options); + let useCaseSensitiveFileNames = Harness.IO.useCaseSensitiveFileNames(); + if (harnessSettings) { + setCompilerOptionsFromHarnessSetting(harnessSettings, options); + } + if (options.useCaseSensitiveFileNames !== undefined) { + useCaseSensitiveFileNames = options.useCaseSensitiveFileNames; + } + const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames); + const inputFilesWithPath = inputFiles.map(f => { + return { unitName: f.unitName, content: f.content, path: ts.toPath(f.unitName, currentDirectory, getCanonicalFileName) }; + }); + const otherFilesWithPath = otherFiles.map(f => { + return { unitName: f.unitName, content: f.content, path: ts.toPath(f.unitName, currentDirectory, getCanonicalFileName) }; + }); // Files from built\local that are requested by test "@includeBuiltFiles" to be in the context. // Treat them as library files, so include them in build, but not in baselines. - const includeBuiltFiles: { unitName: string; content: string }[] = []; + const includeBuiltFiles: TestFileWithPath[] = []; if (options.includeBuiltFile) { const builtFileName = libFolder + options.includeBuiltFile; - includeBuiltFiles.push({ unitName: builtFileName, content: normalizeLineEndings(IO.readFile(builtFileName), newLine) }); + const builtFile: TestFileWithPath = { + unitName: builtFileName, + content: normalizeLineEndings(IO.readFile(builtFileName), newLine), + path: ts.toPath(builtFileName, currentDirectory, getCanonicalFileName) + }; + includeBuiltFiles.push(builtFile); } - const useCaseSensitiveFileNames = options.useCaseSensitiveFileNames !== undefined ? options.useCaseSensitiveFileNames : Harness.IO.useCaseSensitiveFileNames(); - const fileOutputs: GeneratedFile[] = []; const programFiles = inputFiles.concat(includeBuiltFiles).map(file => file.unitName); const compilerHost = createCompilerHost( - inputFiles.concat(includeBuiltFiles).concat(otherFiles), + inputFilesWithPath.concat(includeBuiltFiles).concat(otherFilesWithPath), (fn, contents, writeByteOrderMark) => fileOutputs.push({ fileName: fn, code: contents, writeByteOrderMark: writeByteOrderMark }), options.target, useCaseSensitiveFileNames, currentDirectory, options.newLine); const program = ts.createProgram(programFiles, options, compilerHost); @@ -1132,40 +1104,35 @@ namespace Harness { const emitResult = program.emit(); const errors = ts.getPreEmitDiagnostics(program); - this.lastErrors = errors; const result = new CompilerResult(fileOutputs, errors, program, Harness.IO.getCurrentDirectory(), emitResult.sourceMaps); - onComplete(result, program); - - return options; + return { result, program, options }; } - public compileDeclarationFiles(inputFiles: { unitName: string; content: string; }[], - otherFiles: { unitName: string; content: string; }[], + export function compileDeclarationFiles(inputFiles: TestFile[], + otherFiles: TestFile[], result: CompilerResult, - settingsCallback?: (settings: ts.CompilerOptions) => void, - options?: ts.CompilerOptions, + harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions, + options: ts.CompilerOptions, // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file - currentDirectory?: string) { + currentDirectory: string) { if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) { throw new Error("There were no errors and declFiles generated did not match number of js files generated"); } - const declInputFiles: { unitName: string; content: string }[] = []; - const declOtherFiles: { unitName: string; content: string }[] = []; - let declResult: Harness.Compiler.CompilerResult; + const declInputFiles: TestFile[] = []; + const declOtherFiles: TestFile[] = []; // if the .d.ts is non-empty, confirm it compiles correctly as well if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) { ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles)); ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles)); - this.compileFiles(declInputFiles, declOtherFiles, function (compileResult) { declResult = compileResult; }, - settingsCallback, options, currentDirectory); + const output = this.compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory); - return { declInputFiles, declOtherFiles, declResult }; + return { declInputFiles, declOtherFiles, declResult: output.result }; } - function addDtsFile(file: { unitName: string; content: string }, dtsFiles: { unitName: string; content: string }[]) { + function addDtsFile(file: TestFile, dtsFiles: TestFile[]) { if (isDTS(file.unitName)) { dtsFiles.push(file); } @@ -1202,7 +1169,7 @@ namespace Harness { return ts.forEach(result.declFilesCode, declFile => declFile.fileName === dTsFileName ? declFile : undefined); } - function findUnit(fileName: string, units: { unitName: string; content: string; }[]) { + function findUnit(fileName: string, units: TestFile[]) { return ts.forEach(units, unit => unit.unitName === fileName ? unit : undefined); } } @@ -1232,7 +1199,7 @@ namespace Harness { return errorOutput; } - export function getErrorBaseline(inputFiles: { unitName: string; content: string }[], diagnostics: ts.Diagnostic[]) { + export function getErrorBaseline(inputFiles: TestFile[], diagnostics: ts.Diagnostic[]) { diagnostics.sort(ts.compareDiagnostics); const outputLines: string[] = []; // Count up all errors that were found in files other than lib.d.ts so we don't miss any @@ -1373,16 +1340,6 @@ namespace Harness { } } - /** The harness' compiler instance used when tests are actually run. Reseting or changing settings of this compiler instance must be done within a test case (i.e., describe/it) */ - let harnessCompiler: HarnessCompiler; - - /** Returns the singleton harness compiler instance for generating and running tests. - If required a fresh compiler instance will be created, otherwise the existing singleton will be re-used. - */ - export function getCompiler() { - return harnessCompiler = harnessCompiler || new HarnessCompiler(); - } - // This does not need to exist strictly speaking, but many tests will need to be updated if it's removed export function compileString(code: string, unitName: string, callback: (result: CompilerResult) => void) { // NEWTODO: Re-implement 'compileString' @@ -1713,12 +1670,9 @@ namespace Harness { return filePath.indexOf(Harness.libFolder) === 0; } - export function getDefaultLibraryFile(io: Harness.IO): { unitName: string, content: string } { + export function getDefaultLibraryFile(io: Harness.IO): Harness.Compiler.TestFile { const libFile = Harness.userSpecifiedRoot + Harness.libFolder + "lib.d.ts"; - return { - unitName: libFile, - content: io.readFile(libFile) - }; + return { unitName: libFile, content: io.readFile(libFile) }; } if (Error) (Error).stackTraceLimit = 1; diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index faf0ad28eb5..0c267c38f14 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -153,7 +153,7 @@ namespace Harness.LanguageService { throw new Error("No script with name '" + fileName + "'"); } - public openFile(fileName: string): void { + public openFile(fileName: string, content?: string): void { } /** @@ -493,9 +493,9 @@ namespace Harness.LanguageService { this.client = client; } - openFile(fileName: string): void { - super.openFile(fileName); - this.client.openFile(fileName); + openFile(fileName: string, content?: string): void { + super.openFile(fileName, content); + this.client.openFile(fileName, content); } editScript(fileName: string, start: number, end: number, newText: string) { diff --git a/src/harness/loggedIO.ts b/src/harness/loggedIO.ts index bf56f1aa3ea..0bae91f7976 100644 --- a/src/harness/loggedIO.ts +++ b/src/harness/loggedIO.ts @@ -174,7 +174,7 @@ namespace Playback { return true; } else { - return findResultByFields(replayLog.fileExists, { path }, false); + return findResultByFields(replayLog.fileExists, { path }, /*defaultValue*/ false); } }) ); diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index a350eda08f3..fc1397b294c 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -27,8 +27,8 @@ namespace RWC { export function runRWCTest(jsonPath: string) { describe("Testing a RWC project: " + jsonPath, () => { - let inputFiles: { unitName: string; content: string; }[] = []; - let otherFiles: { unitName: string; content: string; }[] = []; + let inputFiles: Harness.Compiler.TestFile[] = []; + let otherFiles: Harness.Compiler.TestFile[] = []; let compilerResult: Harness.Compiler.CompilerResult; let compilerOptions: ts.CompilerOptions; let baselineOpts: Harness.Baseline.BaselineOptions = { @@ -55,7 +55,6 @@ namespace RWC { }); it("can compile", () => { - const harnessCompiler = Harness.Compiler.getCompiler(); let opts: ts.ParsedCommandLine; const ioLog: IOLog = JSON.parse(Harness.IO.readFile(jsonPath)); @@ -71,8 +70,6 @@ namespace RWC { }); runWithIOLog(ioLog, oldIO => { - harnessCompiler.reset(); - let fileNames = opts.fileNames; const tsconfigFile = ts.forEach(ioLog.filesRead, f => isTsConfigFile(f) ? f : undefined); @@ -128,17 +125,21 @@ namespace RWC { opts.options.noLib = true; // Emit the results - compilerOptions = harnessCompiler.compileFiles( + compilerOptions = null; + const output = Harness.Compiler.HarnessCompiler.compileFiles( inputFiles, otherFiles, - newCompilerResults => { compilerResult = newCompilerResults; }, - /*settingsCallback*/ undefined, opts.options, + /* harnessOptions */ undefined, + opts.options, // Since each RWC json file specifies its current directory in its json file, we need // to pass this information in explicitly instead of acquiring it from the process. currentDirectory); + + compilerOptions = output.options; + compilerResult = output.result; }); - function getHarnessCompilerInputUnit(fileName: string) { + function getHarnessCompilerInputUnit(fileName: string): Harness.Compiler.TestFile { const unitName = ts.normalizeSlashes(Harness.IO.resolvePath(fileName)); let content: string = null; try { @@ -201,8 +202,9 @@ namespace RWC { it("has the expected errors in generated declaration files", () => { if (compilerOptions.declaration && !compilerResult.errors.length) { Harness.Baseline.runBaseline("has the expected errors in generated declaration files", baseName + ".dts.errors.txt", () => { - const declFileCompilationResult = Harness.Compiler.getCompiler().compileDeclarationFiles(inputFiles, otherFiles, compilerResult, - /*settingscallback*/ undefined, compilerOptions, currentDirectory); + const declFileCompilationResult = Harness.Compiler.HarnessCompiler.compileDeclarationFiles( + inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory); + if (declFileCompilationResult.declResult.errors.length === 0) { return null; } diff --git a/src/harness/sourceMapRecorder.ts b/src/harness/sourceMapRecorder.ts index ce0a6a6528e..75246a9a266 100644 --- a/src/harness/sourceMapRecorder.ts +++ b/src/harness/sourceMapRecorder.ts @@ -190,7 +190,7 @@ namespace Harness.SourceMapRecoder { return { error: errorDecodeOfEncodedMapping, sourceMapSpan: decodeOfEncodedMapping }; } - createErrorIfCondition(true, "No encoded entry found"); + createErrorIfCondition(/*condition*/ true, "No encoded entry found"); } export function hasCompletedDecoding() { diff --git a/src/harness/test262Runner.ts b/src/harness/test262Runner.ts index f25e0c79b63..859f10dc4cc 100644 --- a/src/harness/test262Runner.ts +++ b/src/harness/test262Runner.ts @@ -5,9 +5,9 @@ class Test262BaselineRunner extends RunnerBase { private static basePath = "internal/cases/test262"; private static helpersFilePath = "tests/cases/test262-harness/helpers.d.ts"; - private static helperFile = { + private static helperFile: Harness.Compiler.TestFile = { unitName: Test262BaselineRunner.helpersFilePath, - content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath) + content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath), }; private static testFileExtensionRegex = /\.js$/; private static options: ts.CompilerOptions = { @@ -31,7 +31,7 @@ class Test262BaselineRunner extends RunnerBase { let testState: { filename: string; compilerResult: Harness.Compiler.CompilerResult; - inputFiles: { unitName: string; content: string }[]; + inputFiles: Harness.Compiler.TestFile[]; program: ts.Program; }; @@ -40,8 +40,9 @@ class Test262BaselineRunner extends RunnerBase { const testFilename = ts.removeFileExtension(filePath).replace(/\//g, "_") + ".test"; const testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, testFilename); - const inputFiles = testCaseContent.testUnitData.map(unit => { - return { unitName: Test262BaselineRunner.getTestFilePath(unit.name), content: unit.content }; + const inputFiles: Harness.Compiler.TestFile[] = testCaseContent.testUnitData.map(unit => { + const unitName = Test262BaselineRunner.getTestFilePath(unit.name); + return { unitName, content: unit.content }; }); // Emit the results @@ -52,10 +53,15 @@ class Test262BaselineRunner extends RunnerBase { program: undefined, }; - Harness.Compiler.getCompiler().compileFiles([Test262BaselineRunner.helperFile].concat(inputFiles), /*otherFiles*/ [], (compilerResult, program) => { - testState.compilerResult = compilerResult; - testState.program = program; - }, /*settingsCallback*/ undefined, Test262BaselineRunner.options); + const output = Harness.Compiler.HarnessCompiler.compileFiles( + [Test262BaselineRunner.helperFile].concat(inputFiles), + /*otherFiles*/ [], + /* harnessOptions */ undefined, + Test262BaselineRunner.options, + /* currentDirectory */ undefined + ); + testState.compilerResult = output.result; + testState.program = output.program; }); after(() => { diff --git a/src/server/client.ts b/src/server/client.ts index ae234750d88..08939b2b44a 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -120,8 +120,8 @@ namespace ts.server { return response; } - openFile(fileName: string): void { - var args: protocol.FileRequestArgs = { file: fileName }; + openFile(fileName: string, content?: string): void { + var args: protocol.OpenRequestArgs = { file: fileName, fileContent: content }; this.processRequest(CommandNames.Open, args); } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 7c9b6f2dcc4..0305b7595c2 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -388,7 +388,7 @@ namespace ts.server { } openReferencedFile(filename: string) { - return this.projectService.openFile(filename, false); + return this.projectService.openFile(filename, /*openedByClient*/ false); } getRootFiles() { @@ -1006,14 +1006,15 @@ namespace ts.server { /** * @param filename is absolute pathname + * @param fileContent is a known version of the file content that is more up to date than the one on disk */ - openFile(fileName: string, openedByClient: boolean) { + openFile(fileName: string, openedByClient: boolean, fileContent?: string) { fileName = ts.normalizePath(fileName); let info = ts.lookUp(this.filenameToScriptInfo, fileName); if (!info) { let content: string; if (this.host.fileExists(fileName)) { - content = this.host.readFile(fileName); + content = fileContent || this.host.readFile(fileName); } if (!content) { if (openedByClient) { @@ -1030,6 +1031,9 @@ namespace ts.server { } } if (info) { + if (fileContent) { + info.svc.reload(fileContent); + } if (openedByClient) { info.isOpen = true; } @@ -1060,10 +1064,11 @@ namespace ts.server { /** * Open file whose contents is managed by the client * @param filename is absolute pathname + * @param fileContent is a known version of the file content that is more up to date than the one on disk */ - openClientFile(fileName: string) { + openClientFile(fileName: string, fileContent?: string) { this.openOrUpdateConfiguredProjectForFile(fileName); - const info = this.openFile(fileName, true); + const info = this.openFile(fileName, /*openedByClient*/ true, fileContent); this.addOpenFile(info); this.printProjects(); return info; @@ -1272,7 +1277,7 @@ namespace ts.server { for (const fileName of fileNamesToAdd) { let info = this.getScriptInfo(fileName); if (!info) { - info = this.openFile(fileName, false); + info = this.openFile(fileName, /*openedByClient*/ false); } else { // if the root file was opened by client, it would belong to either diff --git a/src/server/protocol.d.ts b/src/server/protocol.d.ts index ad1fc5e92de..3a669753323 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.d.ts @@ -513,6 +513,11 @@ declare namespace ts.server.protocol { * Information found in an "open" request. */ export interface OpenRequestArgs extends FileRequestArgs { + /** + * Used when a version of the file content is known to be more up to date than the one on disk. + * Then the known content will be used upon opening instead of the disk copy + */ + fileContent?: string; } /** diff --git a/src/server/session.ts b/src/server/session.ts index 770256cc9f7..dae2384ce54 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -532,9 +532,13 @@ namespace ts.server { }; } - private openClientFile(fileName: string) { + /** + * @param fileName is the name of the file to be opened + * @param fileContent is a version of the file content that is known to be more up to date than the one on disk + */ + private openClientFile(fileName: string, fileContent?: string) { const file = ts.normalizePath(fileName); - this.projectService.openClientFile(file); + this.projectService.openClientFile(file, fileContent); } private getQuickInfo(line: number, offset: number, fileName: string): protocol.QuickInfoResponseBody { @@ -897,7 +901,7 @@ namespace ts.server { } getDiagnosticsForProject(delay: number, fileName: string) { - const { configFileName, fileNames } = this.getProjectInfo(fileName, true); + const { configFileName, fileNames } = this.getProjectInfo(fileName, /*needFileNameList*/ true); // No need to analyze lib.d.ts let fileNamesInProject = fileNames.filter((value, index, array) => value.indexOf("lib.d.ts") < 0); @@ -968,7 +972,7 @@ namespace ts.server { }, [CommandNames.Open]: (request: protocol.Request) => { const openArgs = request.arguments; - this.openClientFile(openArgs.file); + this.openClientFile(openArgs.file, openArgs.fileContent); return {responseRequired: false}; }, [CommandNames.Quickinfo]: (request: protocol.Request) => { diff --git a/tests/baselines/reference/ambientClassDeclarationWithExtends.js b/tests/baselines/reference/ambientClassDeclarationWithExtends.js index 5fd4d5b4b28..940efb8899f 100644 --- a/tests/baselines/reference/ambientClassDeclarationWithExtends.js +++ b/tests/baselines/reference/ambientClassDeclarationWithExtends.js @@ -1,6 +1,40 @@ -//// [ambientClassDeclarationWithExtends.ts] +//// [tests/cases/compiler/ambientClassDeclarationWithExtends.ts] //// + +//// [ambientClassDeclarationExtends_singleFile.ts] declare class A { } declare class B extends A { } + +declare class C { + public foo; +} +namespace D { var x; } +declare class D extends C { } + +var d: C = new D(); + +//// [ambientClassDeclarationExtends_file1.ts] + +declare class E { + public bar; +} +namespace F { var y; } + +//// [ambientClassDeclarationExtends_file2.ts] + +declare class F extends E { } +var f: E = new F(); -//// [ambientClassDeclarationWithExtends.js] +//// [ambientClassDeclarationExtends_singleFile.js] +var D; +(function (D) { + var x; +})(D || (D = {})); +var d = new D(); +//// [ambientClassDeclarationExtends_file1.js] +var F; +(function (F) { + var y; +})(F || (F = {})); +//// [ambientClassDeclarationExtends_file2.js] +var f = new F(); diff --git a/tests/baselines/reference/ambientClassDeclarationWithExtends.symbols b/tests/baselines/reference/ambientClassDeclarationWithExtends.symbols index 71d1e1a66d8..023ae6bf582 100644 --- a/tests/baselines/reference/ambientClassDeclarationWithExtends.symbols +++ b/tests/baselines/reference/ambientClassDeclarationWithExtends.symbols @@ -1,8 +1,50 @@ -=== tests/cases/compiler/ambientClassDeclarationWithExtends.ts === +=== tests/cases/compiler/ambientClassDeclarationExtends_singleFile.ts === declare class A { } ->A : Symbol(A, Decl(ambientClassDeclarationWithExtends.ts, 0, 0)) +>A : Symbol(A, Decl(ambientClassDeclarationExtends_singleFile.ts, 0, 0)) declare class B extends A { } ->B : Symbol(B, Decl(ambientClassDeclarationWithExtends.ts, 0, 19)) ->A : Symbol(A, Decl(ambientClassDeclarationWithExtends.ts, 0, 0)) +>B : Symbol(B, Decl(ambientClassDeclarationExtends_singleFile.ts, 0, 19)) +>A : Symbol(A, Decl(ambientClassDeclarationExtends_singleFile.ts, 0, 0)) + +declare class C { +>C : Symbol(C, Decl(ambientClassDeclarationExtends_singleFile.ts, 1, 29)) + + public foo; +>foo : Symbol(foo, Decl(ambientClassDeclarationExtends_singleFile.ts, 3, 17)) +} +namespace D { var x; } +>D : Symbol(D, Decl(ambientClassDeclarationExtends_singleFile.ts, 5, 1), Decl(ambientClassDeclarationExtends_singleFile.ts, 6, 22)) +>x : Symbol(x, Decl(ambientClassDeclarationExtends_singleFile.ts, 6, 17)) + +declare class D extends C { } +>D : Symbol(D, Decl(ambientClassDeclarationExtends_singleFile.ts, 5, 1), Decl(ambientClassDeclarationExtends_singleFile.ts, 6, 22)) +>C : Symbol(C, Decl(ambientClassDeclarationExtends_singleFile.ts, 1, 29)) + +var d: C = new D(); +>d : Symbol(d, Decl(ambientClassDeclarationExtends_singleFile.ts, 9, 3)) +>C : Symbol(C, Decl(ambientClassDeclarationExtends_singleFile.ts, 1, 29)) +>D : Symbol(D, Decl(ambientClassDeclarationExtends_singleFile.ts, 5, 1), Decl(ambientClassDeclarationExtends_singleFile.ts, 6, 22)) + +=== tests/cases/compiler/ambientClassDeclarationExtends_file1.ts === + +declare class E { +>E : Symbol(E, Decl(ambientClassDeclarationExtends_file1.ts, 0, 0)) + + public bar; +>bar : Symbol(bar, Decl(ambientClassDeclarationExtends_file1.ts, 1, 17)) +} +namespace F { var y; } +>F : Symbol(F, Decl(ambientClassDeclarationExtends_file1.ts, 3, 1), Decl(ambientClassDeclarationExtends_file2.ts, 0, 0)) +>y : Symbol(y, Decl(ambientClassDeclarationExtends_file1.ts, 4, 17)) + +=== tests/cases/compiler/ambientClassDeclarationExtends_file2.ts === + +declare class F extends E { } +>F : Symbol(F, Decl(ambientClassDeclarationExtends_file1.ts, 3, 1), Decl(ambientClassDeclarationExtends_file2.ts, 0, 0)) +>E : Symbol(E, Decl(ambientClassDeclarationExtends_file1.ts, 0, 0)) + +var f: E = new F(); +>f : Symbol(f, Decl(ambientClassDeclarationExtends_file2.ts, 2, 3)) +>E : Symbol(E, Decl(ambientClassDeclarationExtends_file1.ts, 0, 0)) +>F : Symbol(F, Decl(ambientClassDeclarationExtends_file1.ts, 3, 1), Decl(ambientClassDeclarationExtends_file2.ts, 0, 0)) diff --git a/tests/baselines/reference/ambientClassDeclarationWithExtends.types b/tests/baselines/reference/ambientClassDeclarationWithExtends.types index 7609856882b..c7f22eeb65f 100644 --- a/tests/baselines/reference/ambientClassDeclarationWithExtends.types +++ b/tests/baselines/reference/ambientClassDeclarationWithExtends.types @@ -1,4 +1,4 @@ -=== tests/cases/compiler/ambientClassDeclarationWithExtends.ts === +=== tests/cases/compiler/ambientClassDeclarationExtends_singleFile.ts === declare class A { } >A : A @@ -6,3 +6,47 @@ declare class B extends A { } >B : B >A : A +declare class C { +>C : C + + public foo; +>foo : any +} +namespace D { var x; } +>D : typeof D +>x : any + +declare class D extends C { } +>D : D +>C : C + +var d: C = new D(); +>d : C +>C : C +>new D() : D +>D : typeof D + +=== tests/cases/compiler/ambientClassDeclarationExtends_file1.ts === + +declare class E { +>E : E + + public bar; +>bar : any +} +namespace F { var y; } +>F : typeof F +>y : any + +=== tests/cases/compiler/ambientClassDeclarationExtends_file2.ts === + +declare class F extends E { } +>F : F +>E : E + +var f: E = new F(); +>f : E +>E : E +>new F() : F +>F : typeof F + diff --git a/tests/baselines/reference/mixedStaticAndInstanceClassMembers.errors.txt b/tests/baselines/reference/mixedStaticAndInstanceClassMembers.errors.txt new file mode 100644 index 00000000000..d52b17a58a0 --- /dev/null +++ b/tests/baselines/reference/mixedStaticAndInstanceClassMembers.errors.txt @@ -0,0 +1,27 @@ +tests/cases/compiler/mixedStaticAndInstanceClassMembers.ts(4,5): error TS2387: Function overload must be static. +tests/cases/compiler/mixedStaticAndInstanceClassMembers.ts(12,12): error TS2388: Function overload must not be static. +tests/cases/compiler/mixedStaticAndInstanceClassMembers.ts(13,5): error TS2387: Function overload must be static. + + +==== tests/cases/compiler/mixedStaticAndInstanceClassMembers.ts (3 errors) ==== + class A { + f() {} + static m1 (a: string): void; + m1 (a: number): void; + ~~ +!!! error TS2387: Function overload must be static. + m1 (a: any): void { + } + } + + class B { + f() {} + m1 (a: string): void; + static m1 (a: number): void; + ~~ +!!! error TS2388: Function overload must not be static. + m1 (a: any): void { + ~~ +!!! error TS2387: Function overload must be static. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/mixedStaticAndInstanceClassMembers.js b/tests/baselines/reference/mixedStaticAndInstanceClassMembers.js new file mode 100644 index 00000000000..427bbf65aa1 --- /dev/null +++ b/tests/baselines/reference/mixedStaticAndInstanceClassMembers.js @@ -0,0 +1,34 @@ +//// [mixedStaticAndInstanceClassMembers.ts] +class A { + f() {} + static m1 (a: string): void; + m1 (a: number): void; + m1 (a: any): void { + } +} + +class B { + f() {} + m1 (a: string): void; + static m1 (a: number): void; + m1 (a: any): void { + } +} + +//// [mixedStaticAndInstanceClassMembers.js] +var A = (function () { + function A() { + } + A.prototype.f = function () { }; + A.prototype.m1 = function (a) { + }; + return A; +})(); +var B = (function () { + function B() { + } + B.prototype.f = function () { }; + B.prototype.m1 = function (a) { + }; + return B; +})(); diff --git a/tests/baselines/reference/nonMergedDeclarationsAndOverloads.errors.txt b/tests/baselines/reference/nonMergedDeclarationsAndOverloads.errors.txt new file mode 100644 index 00000000000..252cd6880d4 --- /dev/null +++ b/tests/baselines/reference/nonMergedDeclarationsAndOverloads.errors.txt @@ -0,0 +1,23 @@ +tests/cases/compiler/nonMergedDeclarationsAndOverloads.ts(2,5): error TS2300: Duplicate identifier 'm1'. +tests/cases/compiler/nonMergedDeclarationsAndOverloads.ts(4,5): error TS2300: Duplicate identifier 'm1'. +tests/cases/compiler/nonMergedDeclarationsAndOverloads.ts(5,5): error TS2300: Duplicate identifier 'm1'. +tests/cases/compiler/nonMergedDeclarationsAndOverloads.ts(6,5): error TS2300: Duplicate identifier 'm1'. + + +==== tests/cases/compiler/nonMergedDeclarationsAndOverloads.ts (4 errors) ==== + class A { + m1: string; + ~~ +!!! error TS2300: Duplicate identifier 'm1'. + f() {} + m1 (a: string): void; + ~~ +!!! error TS2300: Duplicate identifier 'm1'. + m1 (a: number): void; + ~~ +!!! error TS2300: Duplicate identifier 'm1'. + m1 (a: any): void { + ~~ +!!! error TS2300: Duplicate identifier 'm1'. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/nonMergedDeclarationsAndOverloads.js b/tests/baselines/reference/nonMergedDeclarationsAndOverloads.js new file mode 100644 index 00000000000..3ca6a963515 --- /dev/null +++ b/tests/baselines/reference/nonMergedDeclarationsAndOverloads.js @@ -0,0 +1,19 @@ +//// [nonMergedDeclarationsAndOverloads.ts] +class A { + m1: string; + f() {} + m1 (a: string): void; + m1 (a: number): void; + m1 (a: any): void { + } +} + +//// [nonMergedDeclarationsAndOverloads.js] +var A = (function () { + function A() { + } + A.prototype.f = function () { }; + A.prototype.m1 = function (a) { + }; + return A; +})(); diff --git a/tests/baselines/reference/nonMergedOverloads.errors.txt b/tests/baselines/reference/nonMergedOverloads.errors.txt new file mode 100644 index 00000000000..9a38ebdc3b3 --- /dev/null +++ b/tests/baselines/reference/nonMergedOverloads.errors.txt @@ -0,0 +1,20 @@ +tests/cases/compiler/nonMergedOverloads.ts(1,5): error TS2300: Duplicate identifier 'f'. +tests/cases/compiler/nonMergedOverloads.ts(3,17): error TS1148: Cannot compile modules unless the '--module' flag is provided. +tests/cases/compiler/nonMergedOverloads.ts(3,17): error TS2300: Duplicate identifier 'f'. +tests/cases/compiler/nonMergedOverloads.ts(4,17): error TS2300: Duplicate identifier 'f'. + + +==== tests/cases/compiler/nonMergedOverloads.ts (4 errors) ==== + var f = 10; + ~ +!!! error TS2300: Duplicate identifier 'f'. + + export function f(); + ~ +!!! error TS1148: Cannot compile modules unless the '--module' flag is provided. + ~ +!!! error TS2300: Duplicate identifier 'f'. + export function f() { + ~ +!!! error TS2300: Duplicate identifier 'f'. + } \ No newline at end of file diff --git a/tests/baselines/reference/nonMergedOverloads.js b/tests/baselines/reference/nonMergedOverloads.js new file mode 100644 index 00000000000..2e7f7f67ee6 --- /dev/null +++ b/tests/baselines/reference/nonMergedOverloads.js @@ -0,0 +1,12 @@ +//// [nonMergedOverloads.ts] +var f = 10; + +export function f(); +export function f() { +} + +//// [nonMergedOverloads.js] +var f = 10; +function f() { +} +exports.f = f; diff --git a/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.js b/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.js new file mode 100644 index 00000000000..ec6b5682edd --- /dev/null +++ b/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.js @@ -0,0 +1,10 @@ +//// [sourceMapValidationLambdaSpanningMultipleLines.ts] +((item: string) => + item +) + +//// [sourceMapValidationLambdaSpanningMultipleLines.js] +(function (item) { + return item; +}); +//# sourceMappingURL=sourceMapValidationLambdaSpanningMultipleLines.js.map \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.js.map b/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.js.map new file mode 100644 index 00000000000..c0151106e7c --- /dev/null +++ b/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.js.map @@ -0,0 +1,2 @@ +//// [sourceMapValidationLambdaSpanningMultipleLines.js.map] +{"version":3,"file":"sourceMapValidationLambdaSpanningMultipleLines.js","sourceRoot":"","sources":["sourceMapValidationLambdaSpanningMultipleLines.ts"],"names":[],"mappings":"AAAA,CAAC,UAAC,IAAY;IACV,OAAA,IAAI;AAAJ,CAAI,CACP,CAAA"} \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.sourcemap.txt b/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.sourcemap.txt new file mode 100644 index 00000000000..475aa1debef --- /dev/null +++ b/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.sourcemap.txt @@ -0,0 +1,54 @@ +=================================================================== +JsFile: sourceMapValidationLambdaSpanningMultipleLines.js +mapUrl: sourceMapValidationLambdaSpanningMultipleLines.js.map +sourceRoot: +sources: sourceMapValidationLambdaSpanningMultipleLines.ts +=================================================================== +------------------------------------------------------------------- +emittedFile:tests/cases/compiler/sourceMapValidationLambdaSpanningMultipleLines.js +sourceFile:sourceMapValidationLambdaSpanningMultipleLines.ts +------------------------------------------------------------------- +>>>(function (item) { +1 > +2 >^ +3 > ^^^^^^^^^^ +4 > ^^^^ +5 > ^^-> +1 > +2 >( +3 > ( +4 > item: string +1 >Emitted(1, 1) Source(1, 1) + SourceIndex(0) +2 >Emitted(1, 2) Source(1, 2) + SourceIndex(0) +3 >Emitted(1, 12) Source(1, 3) + SourceIndex(0) +4 >Emitted(1, 16) Source(1, 15) + SourceIndex(0) +--- +>>> return item; +1->^^^^ +2 > ^^^^^^^ +3 > ^^^^ +1->) => + > +2 > +3 > item +1->Emitted(2, 5) Source(2, 5) + SourceIndex(0) +2 >Emitted(2, 12) Source(2, 5) + SourceIndex(0) +3 >Emitted(2, 16) Source(2, 9) + SourceIndex(0) +--- +>>>}); +1 > +2 >^ +3 > ^ +4 > ^ +5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +1 > +2 >item +3 > + > ) +4 > +1 >Emitted(3, 1) Source(2, 5) + SourceIndex(0) +2 >Emitted(3, 2) Source(2, 9) + SourceIndex(0) +3 >Emitted(3, 3) Source(3, 2) + SourceIndex(0) +4 >Emitted(3, 4) Source(3, 2) + SourceIndex(0) +--- +>>>//# sourceMappingURL=sourceMapValidationLambdaSpanningMultipleLines.js.map \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.symbols b/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.symbols new file mode 100644 index 00000000000..c7ff4ca9d9f --- /dev/null +++ b/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/sourceMapValidationLambdaSpanningMultipleLines.ts === +((item: string) => +>item : Symbol(item, Decl(sourceMapValidationLambdaSpanningMultipleLines.ts, 0, 2)) + + item +>item : Symbol(item, Decl(sourceMapValidationLambdaSpanningMultipleLines.ts, 0, 2)) + +) diff --git a/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.types b/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.types new file mode 100644 index 00000000000..d39119cbd91 --- /dev/null +++ b/tests/baselines/reference/sourceMapValidationLambdaSpanningMultipleLines.types @@ -0,0 +1,10 @@ +=== tests/cases/compiler/sourceMapValidationLambdaSpanningMultipleLines.ts === +((item: string) => +>((item: string) => item) : (item: string) => string +>(item: string) => item : (item: string) => string +>item : string + + item +>item : string + +) diff --git a/tests/baselines/reference/typeGuardTypeOfUndefined.js b/tests/baselines/reference/typeGuardTypeOfUndefined.js new file mode 100644 index 00000000000..a24ff2ec0dc --- /dev/null +++ b/tests/baselines/reference/typeGuardTypeOfUndefined.js @@ -0,0 +1,357 @@ +//// [typeGuardTypeOfUndefined.ts] +// undefined type guard adds no new type information +function test1(a: any) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test2(a: any) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test3(a: any) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test4(a: any) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test5(a: boolean | void) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test6(a: boolean | void) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test7(a: boolean | void) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test8(a: boolean | void) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test9(a: boolean | number) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test10(a: boolean | number) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test11(a: boolean | number) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test12(a: boolean | number) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test13(a: boolean | number | void) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test14(a: boolean | number | void) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test15(a: boolean | number | void) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test16(a: boolean | number | void) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} + + +//// [typeGuardTypeOfUndefined.js] +// undefined type guard adds no new type information +function test1(a) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} +function test2(a) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} +function test3(a) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} +function test4(a) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} +function test5(a) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} +function test6(a) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} +function test7(a) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} +function test8(a) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} +function test9(a) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} +function test10(a) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} +function test11(a) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} +function test12(a) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} +function test13(a) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} +function test14(a) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} +function test15(a) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} +function test16(a) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} diff --git a/tests/baselines/reference/typeGuardTypeOfUndefined.symbols b/tests/baselines/reference/typeGuardTypeOfUndefined.symbols new file mode 100644 index 00000000000..d6d36223fe4 --- /dev/null +++ b/tests/baselines/reference/typeGuardTypeOfUndefined.symbols @@ -0,0 +1,330 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardTypeOfUndefined.ts === +// undefined type guard adds no new type information +function test1(a: any) { +>test1 : Symbol(test1, Decl(typeGuardTypeOfUndefined.ts, 0, 0)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 1, 15)) + + if (typeof a !== "undefined") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 1, 15)) + + if (typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 1, 15)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 1, 15)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 1, 15)) + } + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 1, 15)) + } +} + +function test2(a: any) { +>test2 : Symbol(test2, Decl(typeGuardTypeOfUndefined.ts, 13, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 15, 15)) + + if (typeof a === "undefined") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 15, 15)) + + if (typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 15, 15)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 15, 15)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 15, 15)) + } + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 15, 15)) + } +} + +function test3(a: any) { +>test3 : Symbol(test3, Decl(typeGuardTypeOfUndefined.ts, 27, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 29, 15)) + + if (typeof a === "undefined" || typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 29, 15)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 29, 15)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 29, 15)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 29, 15)) + } +} + +function test4(a: any) { +>test4 : Symbol(test4, Decl(typeGuardTypeOfUndefined.ts, 36, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 38, 15)) + + if (typeof a !== "undefined" && typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 38, 15)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 38, 15)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 38, 15)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 38, 15)) + } +} + +function test5(a: boolean | void) { +>test5 : Symbol(test5, Decl(typeGuardTypeOfUndefined.ts, 45, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 47, 15)) + + if (typeof a !== "undefined") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 47, 15)) + + if (typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 47, 15)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 47, 15)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 47, 15)) + } + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 47, 15)) + } +} + +function test6(a: boolean | void) { +>test6 : Symbol(test6, Decl(typeGuardTypeOfUndefined.ts, 59, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 61, 15)) + + if (typeof a === "undefined") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 61, 15)) + + if (typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 61, 15)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 61, 15)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 61, 15)) + } + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 61, 15)) + } +} + +function test7(a: boolean | void) { +>test7 : Symbol(test7, Decl(typeGuardTypeOfUndefined.ts, 73, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 75, 15)) + + if (typeof a === "undefined" || typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 75, 15)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 75, 15)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 75, 15)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 75, 15)) + } +} + +function test8(a: boolean | void) { +>test8 : Symbol(test8, Decl(typeGuardTypeOfUndefined.ts, 82, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 84, 15)) + + if (typeof a !== "undefined" && typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 84, 15)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 84, 15)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 84, 15)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 84, 15)) + } +} + +function test9(a: boolean | number) { +>test9 : Symbol(test9, Decl(typeGuardTypeOfUndefined.ts, 91, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 93, 15)) + + if (typeof a !== "undefined") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 93, 15)) + + if (typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 93, 15)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 93, 15)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 93, 15)) + } + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 93, 15)) + } +} + +function test10(a: boolean | number) { +>test10 : Symbol(test10, Decl(typeGuardTypeOfUndefined.ts, 105, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 107, 16)) + + if (typeof a === "undefined") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 107, 16)) + + if (typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 107, 16)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 107, 16)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 107, 16)) + } + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 107, 16)) + } +} + +function test11(a: boolean | number) { +>test11 : Symbol(test11, Decl(typeGuardTypeOfUndefined.ts, 119, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 121, 16)) + + if (typeof a === "undefined" || typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 121, 16)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 121, 16)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 121, 16)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 121, 16)) + } +} + +function test12(a: boolean | number) { +>test12 : Symbol(test12, Decl(typeGuardTypeOfUndefined.ts, 128, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 130, 16)) + + if (typeof a !== "undefined" && typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 130, 16)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 130, 16)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 130, 16)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 130, 16)) + } +} + +function test13(a: boolean | number | void) { +>test13 : Symbol(test13, Decl(typeGuardTypeOfUndefined.ts, 137, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 139, 16)) + + if (typeof a !== "undefined") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 139, 16)) + + if (typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 139, 16)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 139, 16)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 139, 16)) + } + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 139, 16)) + } +} + +function test14(a: boolean | number | void) { +>test14 : Symbol(test14, Decl(typeGuardTypeOfUndefined.ts, 151, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 153, 16)) + + if (typeof a === "undefined") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 153, 16)) + + if (typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 153, 16)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 153, 16)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 153, 16)) + } + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 153, 16)) + } +} + +function test15(a: boolean | number | void) { +>test15 : Symbol(test15, Decl(typeGuardTypeOfUndefined.ts, 165, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 167, 16)) + + if (typeof a === "undefined" || typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 167, 16)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 167, 16)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 167, 16)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 167, 16)) + } +} + +function test16(a: boolean | number | void) { +>test16 : Symbol(test16, Decl(typeGuardTypeOfUndefined.ts, 174, 1)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 176, 16)) + + if (typeof a !== "undefined" && typeof a === "boolean") { +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 176, 16)) +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 176, 16)) + + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 176, 16)) + } + else { + a; +>a : Symbol(a, Decl(typeGuardTypeOfUndefined.ts, 176, 16)) + } +} + diff --git a/tests/baselines/reference/typeGuardTypeOfUndefined.types b/tests/baselines/reference/typeGuardTypeOfUndefined.types new file mode 100644 index 00000000000..6cf57e1a1dd --- /dev/null +++ b/tests/baselines/reference/typeGuardTypeOfUndefined.types @@ -0,0 +1,434 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardTypeOfUndefined.ts === +// undefined type guard adds no new type information +function test1(a: any) { +>test1 : (a: any) => void +>a : any + + if (typeof a !== "undefined") { +>typeof a !== "undefined" : boolean +>typeof a : string +>a : any +>"undefined" : string + + if (typeof a === "boolean") { +>typeof a === "boolean" : boolean +>typeof a : string +>a : any +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : any + } + } + else { + a; +>a : any + } +} + +function test2(a: any) { +>test2 : (a: any) => void +>a : any + + if (typeof a === "undefined") { +>typeof a === "undefined" : boolean +>typeof a : string +>a : any +>"undefined" : string + + if (typeof a === "boolean") { +>typeof a === "boolean" : boolean +>typeof a : string +>a : any +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : any + } + } + else { + a; +>a : any + } +} + +function test3(a: any) { +>test3 : (a: any) => void +>a : any + + if (typeof a === "undefined" || typeof a === "boolean") { +>typeof a === "undefined" || typeof a === "boolean" : boolean +>typeof a === "undefined" : boolean +>typeof a : string +>a : any +>"undefined" : string +>typeof a === "boolean" : boolean +>typeof a : string +>a : any +>"boolean" : string + + a; +>a : any + } + else { + a; +>a : any + } +} + +function test4(a: any) { +>test4 : (a: any) => void +>a : any + + if (typeof a !== "undefined" && typeof a === "boolean") { +>typeof a !== "undefined" && typeof a === "boolean" : boolean +>typeof a !== "undefined" : boolean +>typeof a : string +>a : any +>"undefined" : string +>typeof a === "boolean" : boolean +>typeof a : string +>a : any +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : any + } +} + +function test5(a: boolean | void) { +>test5 : (a: boolean | void) => void +>a : boolean | void + + if (typeof a !== "undefined") { +>typeof a !== "undefined" : boolean +>typeof a : string +>a : boolean | void +>"undefined" : string + + if (typeof a === "boolean") { +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | void +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : void + } + } + else { + a; +>a : boolean | void + } +} + +function test6(a: boolean | void) { +>test6 : (a: boolean | void) => void +>a : boolean | void + + if (typeof a === "undefined") { +>typeof a === "undefined" : boolean +>typeof a : string +>a : boolean | void +>"undefined" : string + + if (typeof a === "boolean") { +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | void +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : void + } + } + else { + a; +>a : boolean | void + } +} + +function test7(a: boolean | void) { +>test7 : (a: boolean | void) => void +>a : boolean | void + + if (typeof a === "undefined" || typeof a === "boolean") { +>typeof a === "undefined" || typeof a === "boolean" : boolean +>typeof a === "undefined" : boolean +>typeof a : string +>a : boolean | void +>"undefined" : string +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | void +>"boolean" : string + + a; +>a : boolean | void + } + else { + a; +>a : void + } +} + +function test8(a: boolean | void) { +>test8 : (a: boolean | void) => void +>a : boolean | void + + if (typeof a !== "undefined" && typeof a === "boolean") { +>typeof a !== "undefined" && typeof a === "boolean" : boolean +>typeof a !== "undefined" : boolean +>typeof a : string +>a : boolean | void +>"undefined" : string +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | void +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : boolean | void + } +} + +function test9(a: boolean | number) { +>test9 : (a: boolean | number) => void +>a : boolean | number + + if (typeof a !== "undefined") { +>typeof a !== "undefined" : boolean +>typeof a : string +>a : boolean | number +>"undefined" : string + + if (typeof a === "boolean") { +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | number +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : number + } + } + else { + a; +>a : boolean | number + } +} + +function test10(a: boolean | number) { +>test10 : (a: boolean | number) => void +>a : boolean | number + + if (typeof a === "undefined") { +>typeof a === "undefined" : boolean +>typeof a : string +>a : boolean | number +>"undefined" : string + + if (typeof a === "boolean") { +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | number +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : number + } + } + else { + a; +>a : boolean | number + } +} + +function test11(a: boolean | number) { +>test11 : (a: boolean | number) => void +>a : boolean | number + + if (typeof a === "undefined" || typeof a === "boolean") { +>typeof a === "undefined" || typeof a === "boolean" : boolean +>typeof a === "undefined" : boolean +>typeof a : string +>a : boolean | number +>"undefined" : string +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | number +>"boolean" : string + + a; +>a : boolean | number + } + else { + a; +>a : number + } +} + +function test12(a: boolean | number) { +>test12 : (a: boolean | number) => void +>a : boolean | number + + if (typeof a !== "undefined" && typeof a === "boolean") { +>typeof a !== "undefined" && typeof a === "boolean" : boolean +>typeof a !== "undefined" : boolean +>typeof a : string +>a : boolean | number +>"undefined" : string +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | number +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : boolean | number + } +} + +function test13(a: boolean | number | void) { +>test13 : (a: boolean | number | void) => void +>a : boolean | number | void + + if (typeof a !== "undefined") { +>typeof a !== "undefined" : boolean +>typeof a : string +>a : boolean | number | void +>"undefined" : string + + if (typeof a === "boolean") { +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | number | void +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : number | void + } + } + else { + a; +>a : boolean | number | void + } +} + +function test14(a: boolean | number | void) { +>test14 : (a: boolean | number | void) => void +>a : boolean | number | void + + if (typeof a === "undefined") { +>typeof a === "undefined" : boolean +>typeof a : string +>a : boolean | number | void +>"undefined" : string + + if (typeof a === "boolean") { +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | number | void +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : number | void + } + } + else { + a; +>a : boolean | number | void + } +} + +function test15(a: boolean | number | void) { +>test15 : (a: boolean | number | void) => void +>a : boolean | number | void + + if (typeof a === "undefined" || typeof a === "boolean") { +>typeof a === "undefined" || typeof a === "boolean" : boolean +>typeof a === "undefined" : boolean +>typeof a : string +>a : boolean | number | void +>"undefined" : string +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | number | void +>"boolean" : string + + a; +>a : boolean | number | void + } + else { + a; +>a : number | void + } +} + +function test16(a: boolean | number | void) { +>test16 : (a: boolean | number | void) => void +>a : boolean | number | void + + if (typeof a !== "undefined" && typeof a === "boolean") { +>typeof a !== "undefined" && typeof a === "boolean" : boolean +>typeof a !== "undefined" : boolean +>typeof a : string +>a : boolean | number | void +>"undefined" : string +>typeof a === "boolean" : boolean +>typeof a : string +>a : boolean | number | void +>"boolean" : string + + a; +>a : boolean + } + else { + a; +>a : boolean | number | void + } +} + diff --git a/tests/cases/compiler/ambientClassDeclarationWithExtends.ts b/tests/cases/compiler/ambientClassDeclarationWithExtends.ts index 0c5d8d156bf..ca26f1b2a44 100644 --- a/tests/cases/compiler/ambientClassDeclarationWithExtends.ts +++ b/tests/cases/compiler/ambientClassDeclarationWithExtends.ts @@ -1,2 +1,23 @@ +// @Filename: ambientClassDeclarationExtends_singleFile.ts declare class A { } declare class B extends A { } + +declare class C { + public foo; +} +namespace D { var x; } +declare class D extends C { } + +var d: C = new D(); + +// @Filename: ambientClassDeclarationExtends_file1.ts + +declare class E { + public bar; +} +namespace F { var y; } + +// @Filename: ambientClassDeclarationExtends_file2.ts + +declare class F extends E { } +var f: E = new F(); diff --git a/tests/cases/compiler/mixedStaticAndInstanceClassMembers.ts b/tests/cases/compiler/mixedStaticAndInstanceClassMembers.ts new file mode 100644 index 00000000000..6395813b658 --- /dev/null +++ b/tests/cases/compiler/mixedStaticAndInstanceClassMembers.ts @@ -0,0 +1,15 @@ +class A { + f() {} + static m1 (a: string): void; + m1 (a: number): void; + m1 (a: any): void { + } +} + +class B { + f() {} + m1 (a: string): void; + static m1 (a: number): void; + m1 (a: any): void { + } +} \ No newline at end of file diff --git a/tests/cases/compiler/nonMergedDeclarationsAndOverloads.ts b/tests/cases/compiler/nonMergedDeclarationsAndOverloads.ts new file mode 100644 index 00000000000..6ec4c6076f2 --- /dev/null +++ b/tests/cases/compiler/nonMergedDeclarationsAndOverloads.ts @@ -0,0 +1,8 @@ +class A { + m1: string; + f() {} + m1 (a: string): void; + m1 (a: number): void; + m1 (a: any): void { + } +} \ No newline at end of file diff --git a/tests/cases/compiler/nonMergedOverloads.ts b/tests/cases/compiler/nonMergedOverloads.ts new file mode 100644 index 00000000000..582cd72e1f4 --- /dev/null +++ b/tests/cases/compiler/nonMergedOverloads.ts @@ -0,0 +1,5 @@ +var f = 10; + +export function f(); +export function f() { +} \ No newline at end of file diff --git a/tests/cases/compiler/sourceMapValidationLambdaSpanningMultipleLines.ts b/tests/cases/compiler/sourceMapValidationLambdaSpanningMultipleLines.ts new file mode 100644 index 00000000000..57ba843a69c --- /dev/null +++ b/tests/cases/compiler/sourceMapValidationLambdaSpanningMultipleLines.ts @@ -0,0 +1,4 @@ +// @sourcemap: true +((item: string) => + item +) \ No newline at end of file diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardTypeOfUndefined.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardTypeOfUndefined.ts new file mode 100644 index 00000000000..766c5ed8ca2 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardTypeOfUndefined.ts @@ -0,0 +1,184 @@ +// undefined type guard adds no new type information +function test1(a: any) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test2(a: any) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test3(a: any) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test4(a: any) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test5(a: boolean | void) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test6(a: boolean | void) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test7(a: boolean | void) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test8(a: boolean | void) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test9(a: boolean | number) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test10(a: boolean | number) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test11(a: boolean | number) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test12(a: boolean | number) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test13(a: boolean | number | void) { + if (typeof a !== "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test14(a: boolean | number | void) { + if (typeof a === "undefined") { + if (typeof a === "boolean") { + a; + } + else { + a; + } + } + else { + a; + } +} + +function test15(a: boolean | number | void) { + if (typeof a === "undefined" || typeof a === "boolean") { + a; + } + else { + a; + } +} + +function test16(a: boolean | number | void) { + if (typeof a !== "undefined" && typeof a === "boolean") { + a; + } + else { + a; + } +} diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index cb16112ba15..336e017280f 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -169,10 +169,10 @@ module FourSlashInterface { // Opens a file, given either its index as it // appears in the test source, or its filename // as specified in the test metadata - public file(index: number); - public file(name: string); - public file(indexOrName: any) { - FourSlash.currentTestState.openFile(indexOrName); + public file(index: number, content?: string); + public file(name: string, content?: string); + public file(indexOrName: any, content?: string) { + FourSlash.currentTestState.openFile(indexOrName, content); } } diff --git a/tests/cases/fourslash/server/openFile.ts b/tests/cases/fourslash/server/openFile.ts new file mode 100644 index 00000000000..320e52c9f5e --- /dev/null +++ b/tests/cases/fourslash/server/openFile.ts @@ -0,0 +1,16 @@ +/// + +// @Filename: test1.ts +////t. + +// @Filename: test.ts +////var t = '10'; + +// @Filename: tsconfig.json +////{ "files": ["test.ts", "test1.ts"] } + +var overridingContent = "var t = 10; t."; +goTo.file("test.ts", overridingContent); +goTo.file("test1.ts"); +goTo.eof(); +verify.completionListContains("toExponential"); diff --git a/tests/webTestServer.ts b/tests/webTestServer.ts index 6bd15359e3f..dab552e2619 100644 --- a/tests/webTestServer.ts +++ b/tests/webTestServer.ts @@ -269,6 +269,9 @@ if ((browser && browser === 'chrome')) { case "win64": defaultChromePath = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"; break; + case "darwin": + defaultChromePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"; + break; case "linux": defaultChromePath = "/opt/google/chrome/chrome" break;