diff --git a/Gulpfile.ts b/Gulpfile.ts index d856254296e..aef7cc4c6dd 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -39,25 +39,25 @@ Error.stackTraceLimit = 1000; const cmdLineOptions = minimist(process.argv.slice(2), { boolean: ["debug", "inspect", "light", "colors", "lint", "soft"], - string: ["browser", "tests", "host", "reporter", "stackTraceLimit"], + string: ["browser", "tests", "host", "reporter", "stackTraceLimit", "timeout"], alias: { b: "browser", - d: "debug", - t: "tests", - test: "tests", + d: "debug", "debug-brk": "debug", + i: "inspect", "inspect-brk": "inspect", + t: "tests", test: "tests", r: "reporter", - color: "colors", - f: "files", - file: "files", + c: "colors", color: "colors", + f: "files", file: "files", w: "workers", }, default: { soft: false, colors: process.env.colors || process.env.color || true, - debug: process.env.debug || process.env.d, - inspect: process.env.inspect, + debug: process.env.debug || process.env["debug-brk"] || process.env.d, + inspect: process.env.inspect || process.env["inspect-brk"] || process.env.i, host: process.env.TYPESCRIPT_HOST || process.env.host || "node", browser: process.env.browser || process.env.b || "IE", + timeout: process.env.timeout || 40000, tests: process.env.test || process.env.tests || process.env.t, light: process.env.light || false, reporter: process.env.reporter || process.env.r, @@ -594,11 +594,11 @@ function restoreSavedNodeEnv() { process.env.NODE_ENV = savedNodeEnv; } -let testTimeout = 40000; function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: (e?: any) => void) { const lintFlag = cmdLineOptions["lint"]; cleanTestDirs((err) => { if (err) { console.error(err); failWithStatus(err, 1); } + let testTimeout = cmdLineOptions["timeout"]; const debug = cmdLineOptions["debug"]; const inspect = cmdLineOptions["inspect"]; const tests = cmdLineOptions["tests"]; @@ -637,12 +637,6 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: // default timeout is 2sec which really should be enough, but maybe we just need a small amount longer if (!runInParallel) { const args = []; - if (inspect) { - args.push("--inspect"); - } - if (inspect || debug) { - args.push("--debug-brk"); - } args.push("-R", reporter); if (tests) { args.push("-g", `"${tests}"`); @@ -653,7 +647,15 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: else { args.push("--no-colors"); } - args.push("-t", testTimeout); + if (inspect) { + args.unshift("--inspect-brk"); + } + else if (debug) { + args.unshift("--debug-brk"); + } + else { + args.push("-t", testTimeout); + } args.push(run); setNodeEnvToDevelopment(); exec(mocha, args, lintThenFinish, function(e, status) { @@ -838,6 +840,7 @@ gulp.task("runtests-browser", "Runs the tests using the built run.js file like ' }); gulp.task("generate-code-coverage", "Generates code coverage data via istanbul", ["tests"], (done) => { + const testTimeout = cmdLineOptions["timeout"]; exec("istanbul", ["cover", "node_modules/mocha/bin/_mocha", "--", "-R", "min", "-t", testTimeout.toString(), run], done, done); }); diff --git a/Jakefile.js b/Jakefile.js index 900859f033a..3de055b498e 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -25,6 +25,8 @@ var LKGDirectory = "lib/"; var copyright = "CopyrightNotice.txt"; var thirdParty = "ThirdPartyNoticeText.txt"; +var defaultTestTimeout = 40000; + // add node_modules to path so we don't need global modules, prefer the modules by adding them first var nodeModulesPathPrefix = path.resolve("./node_modules/.bin/") + path.delimiter; if (process.env.path !== undefined) { @@ -74,6 +76,10 @@ function measure(marker) { console.log("travis_time:end:" + marker.id + ":start=" + toNs(marker.stamp) + ",finish=" + toNs(total) + ",duration=" + toNs(diff) + "\r"); } +function removeConstModifierFromEnumDeclarations(text) { + return text.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4'); +} + var compilerSources = filesFromConfig("./src/compiler/tsconfig.json"); var servicesSources = filesFromConfig("./src/services/tsconfig.json"); var cancellationTokenSources = filesFromConfig(path.join(serverDirectory, "cancellationToken/tsconfig.json")); @@ -551,7 +557,7 @@ compileFile(servicesFile, servicesSources, [builtLocalDirectory, copyright].conc // Stanalone/web definition file using global 'ts' namespace jake.cpR(standaloneDefinitionsFile, nodeDefinitionsFile, { silent: true }); var definitionFileContents = fs.readFileSync(nodeDefinitionsFile).toString(); - definitionFileContents = definitionFileContents.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4'); + definitionFileContents = removeConstModifierFromEnumDeclarations(definitionFileContents) fs.writeFileSync(standaloneDefinitionsFile, definitionFileContents); // Official node package definition file, pointed to by 'typings' in package.json @@ -611,6 +617,7 @@ compileFile( fs.readFileSync(tsserverLibraryDefinitionFile).toString() + "\r\nexport = ts;" + "\r\nexport as namespace ts;"; + tsserverLibraryDefinitionFileContents = removeConstModifierFromEnumDeclarations(tsserverLibraryDefinitionFileContents); fs.writeFileSync(tsserverLibraryDefinitionFile, tsserverLibraryDefinitionFileContents); }); @@ -800,8 +807,8 @@ function runConsoleTests(defaultReporter, runInParallel) { cleanTestDirs(); } - var debug = process.env.debug || process.env.d; - var inspect = process.env.inspect; + var debug = process.env.debug || process.env["debug-brk"] || process.env.d; + var inspect = process.env.inspect || process.env["inspect-brk"] || process.env.i; var testTimeout = process.env.timeout || defaultTestTimeout; var tests = process.env.test || process.env.tests || process.env.t; var light = process.env.light || false; @@ -842,12 +849,6 @@ function runConsoleTests(defaultReporter, runInParallel) { if (!runInParallel) { var startTime = mark(); var args = []; - if (inspect) { - args.push("--inspect"); - } - if (inspect || debug) { - args.push("--debug-brk"); - } args.push("-R", reporter); if (tests) { args.push("-g", `"${tests}"`); @@ -861,7 +862,15 @@ function runConsoleTests(defaultReporter, runInParallel) { if (bail) { args.push("--bail"); } - args.push("-t", testTimeout); + if (inspect) { + args.unshift("--inspect-brk"); + } + else if (debug) { + args.unshift("--debug-brk"); + } + else { + args.push("-t", testTimeout); + } args.push(run); var cmd = "mocha " + args.join(" "); @@ -926,7 +935,6 @@ function runConsoleTests(defaultReporter, runInParallel) { } } -var defaultTestTimeout = 22000; desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true."); task("runtests-parallel", ["build-rules", "tests", builtLocalDirectory], function () { runConsoleTests('min', /*runInParallel*/ true); @@ -939,6 +947,7 @@ task("runtests", ["build-rules", "tests", builtLocalDirectory], function() { desc("Generates code coverage data via instanbul"); task("generate-code-coverage", ["tests", builtLocalDirectory], function () { + var testTimeout = process.env.timeout || defaultTestTimeout; var cmd = 'istanbul cover node_modules/mocha/bin/_mocha -- -R min -t ' + testTimeout + ' ' + run; console.log(cmd); exec(cmd); diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 22209e2e41e..80ab042ba6d 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1521,7 +1521,7 @@ namespace ts { // All the children of these container types are never visible through another // symbol (i.e. through another symbol's 'exports' or 'members'). Instead, // they're only accessed 'lexically' (i.e. from code that exists underneath - // their container in the tree. To accomplish this, we simply add their declared + // their container in the tree). To accomplish this, we simply add their declared // symbol to the 'locals' of the container. These symbols can then be found as // the type checker walks up the containers, checking them for matching names. return declareSymbol(container.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes); @@ -2053,7 +2053,10 @@ namespace ts { case SyntaxKind.TypePredicate: return checkTypePredicate(node as TypePredicateNode); case SyntaxKind.TypeParameter: - return declareSymbolAndAddToSymbolTable(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes); + if (node.parent.kind !== ts.SyntaxKind.JSDocTemplateTag || isInJavaScriptFile(node)) { + return declareSymbolAndAddToSymbolTable(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes); + } + return; case SyntaxKind.Parameter: return bindParameter(node); case SyntaxKind.VariableDeclaration: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cdfd935a794..879b73a20f7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4200,16 +4200,6 @@ namespace ts { // Return the inferred type for a variable, parameter, or property declaration function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, includeOptionality: boolean): Type { - if (declaration.flags & NodeFlags.JavaScriptFile) { - // If this is a variable in a JavaScript file, then use the JSDoc type (if it has - // one as its type), otherwise fallback to the below standard TS codepaths to - // try to figure it out. - const type = getTypeForDeclarationFromJSDocComment(declaration); - if (type && type !== unknownType) { - return type; - } - } - // A variable declared in a for..in statement is of type string, or of type keyof T when the // right hand expression is of a type parameter type. if (declaration.parent.parent.kind === SyntaxKind.ForInStatement) { @@ -4231,8 +4221,9 @@ namespace ts { } // Use type from type annotation if one is present - if (declaration.type) { - const declaredType = getTypeFromTypeNode(declaration.type); + const typeNode = getEffectiveTypeAnnotationNode(declaration); + if (typeNode) { + const declaredType = getTypeFromTypeNode(typeNode); return addOptionality(declaredType, /*optional*/ declaration.questionToken && includeOptionality); } @@ -4523,10 +4514,11 @@ namespace ts { function getAnnotatedAccessorType(accessor: AccessorDeclaration): Type { if (accessor) { if (accessor.kind === SyntaxKind.GetAccessor) { - return accessor.type && getTypeFromTypeNode(accessor.type); + const getterTypeAnnotation = getEffectiveReturnTypeNode(accessor); + return getterTypeAnnotation && getTypeFromTypeNode(getterTypeAnnotation); } else { - const setterTypeAnnotation = getSetAccessorTypeAnnotationNode(accessor); + const setterTypeAnnotation = getEffectiveSetAccessorTypeAnnotationNode(accessor); return setterTypeAnnotation && getTypeFromTypeNode(setterTypeAnnotation); } } @@ -4679,7 +4671,7 @@ namespace ts { function reportCircularityError(symbol: Symbol) { // Check if variable has type annotation that circularly references the variable itself - if ((symbol.valueDeclaration).type) { + if (getEffectiveTypeAnnotationNode(symbol.valueDeclaration)) { error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); return unknownType; @@ -5265,14 +5257,18 @@ namespace ts { // A variable-like declaration is considered independent (free of this references) if it has a type annotation // that specifies an independent type, or if it has no type annotation and no initializer (and thus of type any). function isIndependentVariableLikeDeclaration(node: VariableLikeDeclaration): boolean { - return node.type && isIndependentType(node.type) || !node.type && !node.initializer; + const typeNode = getEffectiveTypeAnnotationNode(node); + return typeNode ? isIndependentType(typeNode) : !node.initializer; } // A function-like declaration is considered independent (free of this references) if it has a return type // annotation that is considered independent and if each parameter is considered independent. function isIndependentFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { - if (node.kind !== SyntaxKind.Constructor && (!node.type || !isIndependentType(node.type))) { - return false; + if (node.kind !== SyntaxKind.Constructor) { + const typeNode = getEffectiveReturnTypeNode(node); + if (!typeNode || !isIndependentType(typeNode)) { + return false; + } } for (const parameter of node.parameters) { if (!isIndependentVariableLikeDeclaration(parameter)) { @@ -6424,15 +6420,10 @@ namespace ts { else if (classType) { return classType; } - else if (declaration.type) { - return getTypeFromTypeNode(declaration.type); - } - if (declaration.flags & NodeFlags.JavaScriptFile) { - const type = getReturnTypeFromJSDocComment(declaration); - if (type && type !== unknownType) { - return type; - } + const typeNode = getEffectiveReturnTypeNode(declaration); + if (typeNode) { + return getTypeFromTypeNode(typeNode); } // TypeScript 1.0 spec (April 2014): @@ -8333,7 +8324,7 @@ namespace ts { return false; } // Functions with any parameters that lack type annotations are context sensitive. - if (forEach(node.parameters, p => !p.type)) { + if (forEach(node.parameters, p => !getEffectiveTypeAnnotationNode(p))) { return true; } // For arrow functions we now know we're not context sensitive. @@ -8976,7 +8967,9 @@ namespace ts { reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(prop), typeToString(target)); } else { - errorNode = prop.valueDeclaration; + if (prop.valueDeclaration) { + errorNode = prop.valueDeclaration; + } reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, symbolToString(prop), typeToString(target)); } @@ -12761,8 +12754,15 @@ namespace ts { function getContextualTypeForInitializerExpression(node: Expression): Type { const declaration = node.parent; if (node === declaration.initializer) { - if (declaration.type) { - return getTypeFromTypeNode(declaration.type); + const typeNode = getEffectiveTypeAnnotationNode(declaration); + if (typeNode) { + return getTypeFromTypeNode(typeNode); + } + if (isInJavaScriptFile(declaration)) { + const jsDocType = getTypeForDeclarationFromJSDocComment(declaration); + if (jsDocType) { + return jsDocType; + } } if (declaration.kind === SyntaxKind.Parameter) { const type = getContextuallyTypedParameterType(declaration); @@ -12776,12 +12776,13 @@ namespace ts { if (isBindingPattern(declaration.parent)) { const parentDeclaration = declaration.parent.parent; const name = declaration.propertyName || declaration.name; - if (parentDeclaration.kind !== SyntaxKind.BindingElement && - parentDeclaration.type && - !isBindingPattern(name)) { - const text = getTextOfPropertyName(name); - if (text) { - return getTypeOfPropertyOfType(getTypeFromTypeNode(parentDeclaration.type), text); + if (parentDeclaration.kind !== SyntaxKind.BindingElement) { + const parentTypeNode = getEffectiveTypeAnnotationNode(parentDeclaration); + if (parentTypeNode && !isBindingPattern(name)) { + const text = getTextOfPropertyName(name); + if (text) { + return getTypeOfPropertyOfType(getTypeFromTypeNode(parentTypeNode), text); + } } } } @@ -12835,9 +12836,9 @@ namespace ts { function getContextualReturnType(functionDecl: FunctionLikeDeclaration): Type { // If the containing function has a return type annotation, is a constructor, or is a get accessor whose // corresponding set accessor has a type annotation, return statements in the function are contextually typed - if (functionDecl.type || - functionDecl.kind === SyntaxKind.Constructor || - functionDecl.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(functionDecl.symbol, SyntaxKind.SetAccessor))) { + if (functionDecl.kind === SyntaxKind.Constructor || + getEffectiveReturnTypeNode(functionDecl) || + isGetAccessorWithAnnotatedSetAccessor(functionDecl)) { return getReturnTypeOfSignature(getSignatureFromDeclaration(functionDecl)); } @@ -14234,9 +14235,13 @@ namespace ts { /** * Check if a property with the given name is known anywhere in the given type. In an object type, a property - * is considered known if the object type is empty and the check is for assignability, if the object type has - * index signatures, or if the property is actually declared in the object type. In a union or intersection - * type, a property is considered known if it is known in any constituent type. + * is considered known if + * 1. the object type is empty and the check is for assignability, or + * 2. if the object type has index signatures, or + * 3. if the property is actually declared in the object type + * (this means that 'toString', for example, is not usually a known property). + * 4. In a union or intersection type, + * a property is considered known if it is known in any constituent type. * @param targetType a type to search a given name in * @param name a property name to search * @param isComparingJsxAttributes a boolean flag indicating whether we are searching in JsxAttributesType @@ -14246,7 +14251,7 @@ namespace ts { const resolved = resolveStructuredTypeMembers(targetType); if (resolved.stringIndexInfo || resolved.numberIndexInfo && isNumericLiteralName(name) || - getPropertyOfType(targetType, name) || + getPropertyOfObjectType(targetType, name) || isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) { // For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known. return true; @@ -16374,7 +16379,10 @@ namespace ts { for (let i = 0; i < len; i++) { const declaration = signature.parameters[i].valueDeclaration; if (declaration.type) { - inferTypes((mapper).inferences, getTypeFromTypeNode(declaration.type), getTypeAtPosition(context, i)); + const typeNode = getEffectiveTypeAnnotationNode(declaration); + if (typeNode) { + inferTypes((mapper).inferences, getTypeFromTypeNode(typeNode), getTypeAtPosition(context, i)); + } } } } @@ -16393,14 +16401,14 @@ namespace ts { const len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0); for (let i = 0; i < len; i++) { const parameter = signature.parameters[i]; - if (!(parameter.valueDeclaration).type) { + if (!getEffectiveTypeAnnotationNode(parameter.valueDeclaration)) { const contextualParameterType = getTypeAtPosition(context, i); assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType); } } if (signature.hasRestParameter && isRestParameterIndex(context, signature.parameters.length - 1)) { const parameter = lastOrUndefined(signature.parameters); - if (!(parameter.valueDeclaration).type) { + if (!getEffectiveTypeAnnotationNode(parameter.valueDeclaration)) { const contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters)); assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType); } @@ -16436,15 +16444,6 @@ namespace ts { } } - function getReturnTypeFromJSDocComment(func: SignatureDeclaration | FunctionDeclaration): Type { - const returnTag = getJSDocReturnTag(func); - if (returnTag && returnTag.typeExpression) { - return getTypeFromTypeNode(returnTag.typeExpression.type); - } - - return undefined; - } - function createPromiseType(promisedType: Type): Type { // creates a `Promise` type where `T` is the promisedType argument const globalPromiseType = getGlobalPromiseType(/*reportErrors*/ true); @@ -16670,16 +16669,16 @@ namespace ts { const hasExplicitReturn = func.flags & NodeFlags.HasExplicitReturn; if (returnType && returnType.flags & TypeFlags.Never) { - error(func.type, Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point); + error(getEffectiveReturnTypeNode(func), Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point); } else if (returnType && !hasExplicitReturn) { // minimal check: function has syntactic return type annotation and no explicit return statements in the body // this function does not conform to the specification. // NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present - error(func.type, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value); + error(getEffectiveReturnTypeNode(func), Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value); } else if (returnType && strictNullChecks && !isTypeAssignableTo(undefinedType, returnType)) { - error(func.type, Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined); + error(getEffectiveReturnTypeNode(func), Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined); } else if (compilerOptions.noImplicitReturns) { if (!returnType) { @@ -16694,7 +16693,7 @@ namespace ts { return; } } - error(func.type || func, Diagnostics.Not_all_code_paths_return_a_value); + error(getEffectiveReturnTypeNode(func) || func, Diagnostics.Not_all_code_paths_return_a_value); } } @@ -16735,7 +16734,7 @@ namespace ts { contextualSignature : instantiateSignature(contextualSignature, contextualMapper); assignContextualParameterTypes(signature, instantiatedContextualSignature); } - if (!node.type && !signature.resolvedReturnType) { + if (!getEffectiveReturnTypeNode(node) && !signature.resolvedReturnType) { const returnType = getReturnTypeFromBody(node, checkMode); if (!signature.resolvedReturnType) { signature.resolvedReturnType = returnType; @@ -16760,10 +16759,11 @@ namespace ts { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); const functionFlags = getFunctionFlags(node); - const returnOrPromisedType = node.type && + const returnTypeNode = getEffectiveReturnTypeNode(node); + const returnOrPromisedType = returnTypeNode && ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async ? checkAsyncFunctionReturnType(node) : // Async function - getTypeFromTypeNode(node.type)); // AsyncGenerator function, Generator function, or normal function + getTypeFromTypeNode(returnTypeNode)); // AsyncGenerator function, Generator function, or normal function if ((functionFlags & FunctionFlags.Generator) === 0) { // Async function or normal function // return is not necessary in the body of generators @@ -16771,7 +16771,7 @@ namespace ts { } if (node.body) { - if (!node.type) { + if (!returnTypeNode) { // There are some checks that are only performed in getReturnTypeFromBody, that may produce errors // we need. An example is the noImplicitAny errors resulting from widening the return expression // of a function. Because checking of function expression bodies is deferred, there was never an @@ -17557,8 +17557,9 @@ namespace ts { // There is no point in doing an assignability check if the function // has no explicit return type because the return type is directly computed // from the yield expressions. - if (func.type) { - const signatureElementType = getIteratedTypeOfGenerator(getTypeFromTypeNode(func.type), (functionFlags & FunctionFlags.Async) !== 0) || anyType; + const returnType = getEffectiveReturnTypeNode(func); + if (returnType) { + const signatureElementType = getIteratedTypeOfGenerator(getTypeFromTypeNode(returnType), (functionFlags & FunctionFlags.Async) !== 0) || anyType; if (nodeIsYieldStar) { checkTypeAssignableTo( functionFlags & FunctionFlags.Async @@ -18086,13 +18087,15 @@ namespace ts { forEach(node.parameters, checkParameter); + // TODO(rbuckton): Should we start checking JSDoc types? if (node.type) { checkSourceElement(node.type); } if (produceDiagnostics) { checkCollisionWithArgumentsInGeneratedCode(node); - if (noImplicitAny && !node.type) { + const returnTypeNode = getEffectiveReturnTypeNode(node); + if (noImplicitAny && !returnTypeNode) { switch (node.kind) { case SyntaxKind.ConstructSignature: error(node, Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); @@ -18103,12 +18106,12 @@ namespace ts { } } - if (node.type) { + if (returnTypeNode) { const functionFlags = getFunctionFlags(node); if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Generator)) === FunctionFlags.Generator) { - const returnType = getTypeFromTypeNode(node.type); + const returnType = getTypeFromTypeNode(returnTypeNode); if (returnType === voidType) { - error(node.type, Diagnostics.A_generator_cannot_have_a_void_type_annotation); + error(returnTypeNode, Diagnostics.A_generator_cannot_have_a_void_type_annotation); } else { const generatorElementType = getIteratedTypeOfGenerator(returnType, (functionFlags & FunctionFlags.Async) !== 0) || anyType; @@ -18122,7 +18125,7 @@ namespace ts { // interface BadGenerator extends Iterable, Iterator { } // function* g(): BadGenerator { } // Iterable and Iterator have different types! // - checkTypeAssignableTo(iterableIteratorInstantiation, returnType, node.type); + checkTypeAssignableTo(iterableIteratorInstantiation, returnType, returnTypeNode); } } else if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { @@ -19134,7 +19137,8 @@ namespace ts { // then(...): Promise; // } // - const returnType = getTypeFromTypeNode(node.type); + const returnTypeNode = getEffectiveReturnTypeNode(node); + const returnType = getTypeFromTypeNode(returnTypeNode); if (languageVersion >= ScriptTarget.ES2015) { if (returnType === unknownType) { @@ -19144,21 +19148,21 @@ namespace ts { if (globalPromiseType !== emptyGenericType && !isReferenceToType(returnType, globalPromiseType)) { // The promise type was not a valid type reference to the global promise type, so we // report an error and return the unknown type. - error(node.type, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type); + error(returnTypeNode, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type); return unknownType; } } else { // Always mark the type node as referenced if it points to a value - markTypeNodeAsReferenced(node.type); + markTypeNodeAsReferenced(returnTypeNode); if (returnType === unknownType) { return unknownType; } - const promiseConstructorName = getEntityNameFromTypeNode(node.type); + const promiseConstructorName = getEntityNameFromTypeNode(returnTypeNode); if (promiseConstructorName === undefined) { - error(node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, typeToString(returnType)); + error(returnTypeNode, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, typeToString(returnType)); return unknownType; } @@ -19166,10 +19170,10 @@ namespace ts { const promiseConstructorType = promiseConstructorSymbol ? getTypeOfSymbol(promiseConstructorSymbol) : unknownType; if (promiseConstructorType === unknownType) { if (promiseConstructorName.kind === SyntaxKind.Identifier && promiseConstructorName.text === "Promise" && getTargetType(returnType) === getGlobalPromiseType(/*reportErrors*/ false)) { - error(node.type, Diagnostics.An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option); + error(returnTypeNode, Diagnostics.An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option); } else { - error(node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, entityNameToString(promiseConstructorName)); + error(returnTypeNode, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, entityNameToString(promiseConstructorName)); } return unknownType; } @@ -19178,11 +19182,11 @@ namespace ts { if (globalPromiseConstructorLikeType === emptyObjectType) { // If we couldn't resolve the global PromiseConstructorLike type we cannot verify // compatibility with __awaiter. - error(node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, entityNameToString(promiseConstructorName)); + error(returnTypeNode, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, entityNameToString(promiseConstructorName)); return unknownType; } - if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, node.type, + if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, returnTypeNode, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value)) { return unknownType; } @@ -19327,7 +19331,8 @@ namespace ts { } function getParameterTypeNodeForDecoratorCheck(node: ParameterDeclaration): TypeNode { - return node.dotDotDotToken ? getRestParameterElementType(node.type) : node.type; + const typeNode = getEffectiveTypeAnnotationNode(node); + return isRestParameter(node) ? getRestParameterElementType(typeNode) : typeNode; } /** Check the decorators of a node */ @@ -19373,14 +19378,15 @@ namespace ts { markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); } - markDecoratorMedataDataTypeNodeAsReferenced((node).type); + markDecoratorMedataDataTypeNodeAsReferenced(getEffectiveReturnTypeNode(node)); break; case SyntaxKind.PropertyDeclaration: - markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(node)); + markDecoratorMedataDataTypeNodeAsReferenced(getEffectiveTypeAnnotationNode(node)); break; + case SyntaxKind.Parameter: - markDecoratorMedataDataTypeNodeAsReferenced((node).type); + markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(node)); break; } } @@ -19445,14 +19451,15 @@ namespace ts { checkSourceElement(node.body); + const returnTypeNode = getEffectiveReturnTypeNode(node); if ((functionFlags & FunctionFlags.Generator) === 0) { // Async function or normal function - const returnOrPromisedType = node.type && (functionFlags & FunctionFlags.Async + const returnOrPromisedType = returnTypeNode && (functionFlags & FunctionFlags.Async ? checkAsyncFunctionReturnType(node) // Async function - : getTypeFromTypeNode(node.type)); // normal function + : getTypeFromTypeNode(returnTypeNode)); // normal function checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnOrPromisedType); } - if (produceDiagnostics && !node.type) { + if (produceDiagnostics && !returnTypeNode) { // Report an implicit any error if there is no body, no explicit return type, and node is not a private method // in an ambient context if (noImplicitAny && nodeIsMissing(node.body) && !isPrivateWithinAmbient(node)) { @@ -20582,7 +20589,8 @@ namespace ts { } function isGetAccessorWithAnnotatedSetAccessor(node: FunctionLikeDeclaration) { - return !!(node.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(node.symbol, SyntaxKind.SetAccessor))); + return node.kind === SyntaxKind.GetAccessor + && getEffectiveSetAccessorTypeAnnotationNode(getDeclarationOfKind(node.symbol, SyntaxKind.SetAccessor)) !== undefined; } function isUnwrappedReturnTypeVoidOrAny(func: FunctionLikeDeclaration, returnType: Type): boolean { @@ -20626,7 +20634,7 @@ namespace ts { error(node, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); } } - else if (func.type || isGetAccessorWithAnnotatedSetAccessor(func)) { + else if (getEffectiveReturnTypeNode(func) || isGetAccessorWithAnnotatedSetAccessor(func)) { if (functionFlags & FunctionFlags.Async) { // Async function const promisedType = getPromisedTypeOfPromise(returnType); const awaitedType = checkAwaitedType(exprType, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); @@ -21764,7 +21772,10 @@ namespace ts { } // Don't allow to re-export something with no value side when `--isolatedModules` is set. - if (node.kind === SyntaxKind.ExportSpecifier && compilerOptions.isolatedModules && !(target.flags & SymbolFlags.Value)) { + if (compilerOptions.isolatedModules + && node.kind === SyntaxKind.ExportSpecifier + && !(target.flags & SymbolFlags.Value) + && !isInAmbientContext(node)) { error(node, Diagnostics.Cannot_re_export_a_type_when_the_isolatedModules_flag_is_provided); } } @@ -22526,10 +22537,16 @@ namespace ts { } if (entityName.parent!.kind === SyntaxKind.JSDocParameterTag) { - const parameter = ts.getParameterFromJSDoc(entityName.parent as JSDocParameterTag); + const parameter = getParameterFromJSDoc(entityName.parent as JSDocParameterTag); return parameter && parameter.symbol; } + if (entityName.parent.kind === SyntaxKind.TypeParameter && entityName.parent.parent.kind === SyntaxKind.JSDocTemplateTag) { + Debug.assert(!isInJavaScriptFile(entityName)); // Otherwise `isDeclarationName` would have been true. + const typeParameter = getTypeParameterFromJsDoc(entityName.parent as TypeParameterDeclaration & { parent: JSDocTemplateTag }); + return typeParameter && typeParameter.symbol; + } + if (isPartOfExpression(entityName)) { if (nodeIsMissing(entityName)) { // Missing entity name. @@ -24796,7 +24813,6 @@ namespace ts { // falls through default: return isDeclarationName(name); - } } } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 987157843b6..007620ad510 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -596,7 +596,7 @@ namespace ts { currentIdentifiers = node.identifiers; isCurrentFileExternalModule = isExternalModule(node); enclosingDeclaration = node; - emitDetachedComments(currentText, currentLineMap, writer, writeCommentRange, node, newLine, /*removeComents*/ true); + emitDetachedComments(currentText, currentLineMap, writer, writeCommentRange, node, newLine, /*removeComments*/ true); emitLines(node.statements); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 8002709f3f6..5884248396e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -15,7 +15,7 @@ namespace ts { else if (kind === SyntaxKind.Identifier) { return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, pos, end); } - else if (kind < SyntaxKind.FirstNode) { + else if (!isNodeKind(kind)) { return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, pos, end); } else { @@ -481,7 +481,11 @@ namespace ts { // becoming detached from any SourceFile). It is recommended that this SourceFile not // be used once 'update' is called on it. export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile { - return IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); + const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); + // Because new source file node is created, it may not have the flag PossiblyContainDynamicImport. This is the case if there is no new edit to add dynamic import. + // We will manually port the flag to the new source file. + newSourceFile.flags |= (sourceFile.flags & NodeFlags.PossiblyContainsDynamicImport); + return newSourceFile; } /* @internal */ @@ -1099,7 +1103,7 @@ namespace ts { pos = scanner.getStartPos(); } - return kind >= SyntaxKind.FirstNode ? new NodeConstructor(kind, pos, pos) : + return isNodeKind(kind) ? new NodeConstructor(kind, pos, pos) : kind === SyntaxKind.Identifier ? new IdentifierConstructor(kind, pos, pos) : new TokenConstructor(kind, pos, pos); } @@ -3701,7 +3705,7 @@ namespace ts { // For example: // var foo3 = require("subfolder // import * as foo1 from "module-from-node -> we want this import to be a statement rather than import call expression - sourceFile.flags |= NodeFlags.PossiblyContainDynamicImport; + sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport; expression = parseTokenNode(); } else { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 92c50e6ddff..3ca9d03466e 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1379,7 +1379,7 @@ namespace ts { for (const node of file.statements) { collectModuleReferences(node, /*inAmbientModule*/ false); - if ((file.flags & NodeFlags.PossiblyContainDynamicImport) || isJavaScriptFile) { + if ((file.flags & NodeFlags.PossiblyContainsDynamicImport) || isJavaScriptFile) { collectDynamicImportOrRequireCalls(node); } } diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 1abebe937e6..cd14f3b2801 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -35,6 +35,10 @@ namespace ts { getDirectories(path: string): string[]; readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[]; getModifiedTime?(path: string): Date; + /** + * This should be cryptographically secure. + * A good implementation is node.js' `crypto.createHash`. (https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm) + */ createHash?(data: string): string; getMemoryUsage?(): number; exit(exitCode?: number): void; diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index f0c827d8396..bfd3360e885 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -239,7 +239,7 @@ namespace ts { function hoistVariableDeclaration(name: Identifier): void { Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); - const decl = createVariableDeclaration(name); + const decl = setEmitFlags(createVariableDeclaration(name), EmitFlags.NoNestedSourceMaps); if (!lexicalEnvironmentVariableDeclarations) { lexicalEnvironmentVariableDeclarations = [decl]; } diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index 9aadd6bc686..d0049e72f0b 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -640,10 +640,13 @@ namespace ts { return undefined; } - return createStatement( - inlineExpressions( - map(variables, transformInitializedVariable) - ) + return setSourceMapRange( + createStatement( + inlineExpressions( + map(variables, transformInitializedVariable) + ) + ), + node ); } } @@ -1281,9 +1284,12 @@ namespace ts { } function transformInitializedVariable(node: VariableDeclaration) { - return createAssignment( - getSynthesizedClone(node.name), - visitNode(node.initializer, visitor, isExpression) + return setSourceMapRange( + createAssignment( + setSourceMapRange(getSynthesizedClone(node.name), node.name), + visitNode(node.initializer, visitor, isExpression) + ), + node ); } diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index bf0c7dbf7b9..6141f52f5f4 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -514,14 +514,14 @@ namespace ts { function visitImportCallExpression(node: ImportCall): Expression { switch (compilerOptions.module) { - case ModuleKind.CommonJS: - return transformImportCallExpressionCommonJS(node); case ModuleKind.AMD: return transformImportCallExpressionAMD(node); case ModuleKind.UMD: return transformImportCallExpressionUMD(node); + case ModuleKind.CommonJS: + default: + return transformImportCallExpressionCommonJS(node); } - Debug.fail("All supported module kind in this transformation step should have been handled"); } function transformImportCallExpressionUMD(node: ImportCall): Expression { diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 834c7326e22..637cfd0f165 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -662,6 +662,10 @@ namespace ts { } } +if (ts.Debug.isDebugging) { + ts.Debug.enableDebugInfo(); +} + if (ts.sys.tryEnableSourceMapsForHost && /^development$/i.test(ts.sys.getEnvironmentVariable("NODE_ENV"))) { ts.sys.tryEnableSourceMapsForHost(); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8833fbb9d08..28e135606d6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -451,13 +451,16 @@ namespace ts { ThisNodeOrAnySubNodesHasError = 1 << 17, // If this node or any of its children had an error HasAggregatedChildData = 1 << 18, // If we've computed data from children and cached it in this node - // This flag will be set to true when the parse encounter dynamic import so that post-parsing process of module resolution - // will not walk the tree if the flag is not set. However, this flag is just a approximation because once it is set, the flag never get reset. - // (hence it is named "possiblyContainDynamicImport"). - // During editing, if dynamic import is remove, incremental parsing will *NOT* update this flag. This will then causes walking of the tree during module resolution. - // However, the removal operation should not occur often and in the case of the removal, it is likely that users will add back the import anyway. - // The advantage of this approach is its simplicity. For the case of batch compilation, we garuntee that users won't have to pay the price of walking the tree if dynamic import isn't used. - PossiblyContainDynamicImport = 1 << 19, + // This flag will be set when the parser encounters a dynamic import expression so that module resolution + // will not have to walk the tree if the flag is not set. However, this flag is just a approximation because + // once it is set, the flag never gets cleared (hence why it's named "PossiblyContainsDynamicImport"). + // During editing, if dynamic import is removed, incremental parsing will *NOT* update this flag. This means that the tree will always be traversed + // during module resolution. However, the removal operation should not occur often and in the case of the + // removal, it is likely that users will add the import anyway. + // The advantage of this approach is its simplicity. For the case of batch compilation, + // we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used. + /* @internal */ + PossiblyContainsDynamicImport = 1 << 19, BlockScoped = Let | Const, @@ -1794,7 +1797,7 @@ namespace ts { block: Block; } - export type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration; + export type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag; export interface ClassLikeDeclaration extends NamedDeclaration { name?: Identifier; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 77f1e43c9cb..cee2e3626ad 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1546,6 +1546,12 @@ namespace ts { p.name.kind === SyntaxKind.Identifier && p.name.text === name); } + export function getTypeParameterFromJsDoc(node: TypeParameterDeclaration & { parent: JSDocTemplateTag }): TypeParameterDeclaration | undefined { + const name = node.name.text; + const { typeParameters } = (node.parent.parent.parent as ts.SignatureDeclaration | ts.InterfaceDeclaration | ts.ClassDeclaration); + return find(typeParameters, p => p.name.text === name); + } + export function getJSDocType(node: Node): JSDocType { let tag: JSDocTypeTag | JSDocParameterTag = getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag; if (!tag && node.kind === SyntaxKind.Parameter) { @@ -1570,6 +1576,11 @@ namespace ts { return getFirstJSDocTag(node, SyntaxKind.JSDocReturnTag) as JSDocReturnTag; } + export function getJSDocReturnType(node: Node): JSDocType { + const returnTag = getJSDocReturnTag(node); + return returnTag && returnTag.typeExpression && returnTag.typeExpression.type; + } + export function getJSDocTemplateTag(node: Node): JSDocTemplateTag { return getFirstJSDocTag(node, SyntaxKind.JSDocTemplateTag) as JSDocTemplateTag; } @@ -2615,14 +2626,19 @@ namespace ts { }); } - /** Get the type annotaion for the value parameter. */ - export function getSetAccessorTypeAnnotationNode(accessor: SetAccessorDeclaration): TypeNode { + function getSetAccessorValueParameter(accessor: SetAccessorDeclaration): ParameterDeclaration | undefined { if (accessor && accessor.parameters.length > 0) { const hasThis = accessor.parameters.length === 2 && parameterIsThisKeyword(accessor.parameters[0]); - return accessor.parameters[hasThis ? 1 : 0].type; + return accessor.parameters[hasThis ? 1 : 0]; } } + /** Get the type annotation for the value parameter. */ + export function getSetAccessorTypeAnnotationNode(accessor: SetAccessorDeclaration): TypeNode { + const parameter = getSetAccessorValueParameter(accessor); + return parameter && parameter.type; + } + export function getThisParameter(signature: SignatureDeclaration): ParameterDeclaration | undefined { if (signature.parameters.length) { const thisParameter = signature.parameters[0]; @@ -2701,6 +2717,41 @@ namespace ts { }; } + /** + * Gets the effective type annotation of a variable, parameter, or property. If the node was + * parsed in a JavaScript file, gets the type annotation from JSDoc. + */ + export function getEffectiveTypeAnnotationNode(node: VariableLikeDeclaration): TypeNode { + if (node.type) { + return node.type; + } + if (node.flags & NodeFlags.JavaScriptFile) { + return getJSDocType(node); + } + } + + /** + * Gets the effective return type annotation of a signature. If the node was parsed in a + * JavaScript file, gets the return type annotation from JSDoc. + */ + export function getEffectiveReturnTypeNode(node: SignatureDeclaration): TypeNode { + if (node.type) { + return node.type; + } + if (node.flags & NodeFlags.JavaScriptFile) { + return getJSDocReturnType(node); + } + } + + /** + * Gets the effective type annotation of the value parameter of a set accessor. If the node + * was parsed in a JavaScript file, gets the type annotation from JSDoc. + */ + export function getEffectiveSetAccessorTypeAnnotationNode(node: SetAccessorDeclaration): TypeNode { + const parameter = getSetAccessorValueParameter(node); + return parameter && getEffectiveTypeAnnotationNode(parameter); + } + export function emitNewLineBeforeLeadingComments(lineMap: number[], writer: EmitTextWriter, node: TextRange, leadingComments: CommentRange[]) { emitNewLineBeforeLeadingCommentsOfPosition(lineMap, writer, node.pos, leadingComments); } @@ -4670,6 +4721,16 @@ namespace ts { // All node tests in the following list should *not* reference parent pointers so that // they may be used with transformations. namespace ts { + /* @internal */ + export function isNode(node: Node) { + return isNodeKind(node.kind); + } + + /* @internal */ + export function isNodeKind(kind: SyntaxKind) { + return kind >= SyntaxKind.FirstNode; + } + /** * True if node is of some token syntax kind. * For example, this is true for an IfKeyword but not for an IfStatement. @@ -5219,6 +5280,10 @@ namespace ts { /* @internal */ export function isDeclaration(node: Node): node is NamedDeclaration { + if (node.kind === SyntaxKind.TypeParameter) { + return node.parent.kind !== SyntaxKind.JSDocTemplateTag || isInJavaScriptFile(node); + } + return isDeclarationKind(node.kind); } @@ -5308,6 +5373,11 @@ namespace ts { return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode; } + /** True if node is of a kind that may contain comment text. */ + export function isJSDocCommentContainingNode(node: Node): boolean { + return node.kind === SyntaxKind.JSDocComment || isJSDocTag(node); + } + // TODO: determine what this does before making it public. /* @internal */ export function isJSDocTag(node: Node): boolean { diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index fc3b9c784cc..c4023c0a3bd 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -1517,35 +1517,7 @@ namespace ts { } export namespace Debug { - if (isDebugging) { - // Add additional properties in debug mode to assist with debugging. - Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, { - "__debugFlags": { get(this: Symbol) { return formatSymbolFlags(this.flags); } } - }); - - Object.defineProperties(objectAllocator.getTypeConstructor().prototype, { - "__debugFlags": { get(this: Type) { return formatTypeFlags(this.flags); } }, - "__debugObjectFlags": { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((this).objectFlags) : ""; } }, - "__debugTypeToString": { value(this: Type) { return this.checker.typeToString(this); } }, - }); - - for (const ctor of [objectAllocator.getNodeConstructor(), objectAllocator.getIdentifierConstructor(), objectAllocator.getTokenConstructor(), objectAllocator.getSourceFileConstructor()]) { - if (!ctor.prototype.hasOwnProperty("__debugKind")) { - Object.defineProperties(ctor.prototype, { - "__debugKind": { get(this: Node) { return formatSyntaxKind(this.kind); } }, - "__debugModifierFlags": { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } }, - "__debugTransformFlags": { get(this: Node) { return formatTransformFlags(this.transformFlags); } }, - "__debugEmitFlags": { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } }, - "__debugGetText": { value(this: Node, includeTrivia?: boolean) { - if (nodeIsSynthesized(this)) return ""; - const parseNode = getParseTreeNode(this); - const sourceFile = parseNode && getSourceFileOfNode(parseNode); - return sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : ""; - } } - }); - } - } - } + let isDebugInfoEnabled = false; export const failBadSyntaxKind = shouldAssert(AssertionLevel.Normal) ? (node: Node, message?: string): void => fail( @@ -1592,5 +1564,51 @@ namespace ts { () => `Node ${formatSyntaxKind(node.kind)} was unexpected'.`, assertMissingNode) : noop; + + /** + * Injects debug information into frequently used types. + */ + export function enableDebugInfo() { + if (isDebugInfoEnabled) return; + + // Add additional properties in debug mode to assist with debugging. + Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, { + "__debugFlags": { get(this: Symbol) { return formatSymbolFlags(this.flags); } } + }); + + Object.defineProperties(objectAllocator.getTypeConstructor().prototype, { + "__debugFlags": { get(this: Type) { return formatTypeFlags(this.flags); } }, + "__debugObjectFlags": { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((this).objectFlags) : ""; } }, + "__debugTypeToString": { value(this: Type) { return this.checker.typeToString(this); } }, + }); + + const nodeConstructors = [ + objectAllocator.getNodeConstructor(), + objectAllocator.getIdentifierConstructor(), + objectAllocator.getTokenConstructor(), + objectAllocator.getSourceFileConstructor() + ]; + + for (const ctor of nodeConstructors) { + if (!ctor.prototype.hasOwnProperty("__debugKind")) { + Object.defineProperties(ctor.prototype, { + "__debugKind": { get(this: Node) { return formatSyntaxKind(this.kind); } }, + "__debugModifierFlags": { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } }, + "__debugTransformFlags": { get(this: Node) { return formatTransformFlags(this.transformFlags); } }, + "__debugEmitFlags": { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } }, + "__debugGetText": { + value(this: Node, includeTrivia?: boolean) { + if (nodeIsSynthesized(this)) return ""; + const parseNode = getParseTreeNode(this); + const sourceFile = parseNode && getSourceFileOfNode(parseNode); + return sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : ""; + } + } + }); + } + } + + isDebugInfoEnabled = true; + } } } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 132db1e53eb..774c43556ca 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -731,7 +731,7 @@ namespace Harness.LanguageService { } createHash(s: string) { - return s; + return mockHash(s); } require(_initialDir: string, _moduleName: string): ts.server.RequireResult { @@ -856,4 +856,8 @@ namespace Harness.LanguageService { getClassifier(): ts.Classifier { throw new Error("getClassifier is not available using the server interface."); } getPreProcessedFileInfo(): ts.PreProcessedFileInfo { throw new Error("getPreProcessedFileInfo is not available using the server interface."); } } + + export function mockHash(s: string): string { + return `hash-${s}`; + } } diff --git a/src/harness/runner.ts b/src/harness/runner.ts index 3ad6269e52f..4653e440f11 100644 --- a/src/harness/runner.ts +++ b/src/harness/runner.ts @@ -222,6 +222,10 @@ if (taskConfigsFolder) { } } else { + if (ts.Debug.isDebugging) { + ts.Debug.enableDebugInfo(); + } + runTests(runners); } if (!runUnitTests) { diff --git a/src/harness/unittests/cachingInServerLSHost.ts b/src/harness/unittests/cachingInServerLSHost.ts index 1b87fc848b5..9bb264b2637 100644 --- a/src/harness/unittests/cachingInServerLSHost.ts +++ b/src/harness/unittests/cachingInServerLSHost.ts @@ -47,7 +47,7 @@ namespace ts { clearTimeout, setImmediate: typeof setImmediate !== "undefined" ? setImmediate : action => setTimeout(action, 0), clearImmediate: typeof clearImmediate !== "undefined" ? clearImmediate : clearTimeout, - createHash: s => s + createHash: Harness.LanguageService.mockHash, }; } diff --git a/src/harness/unittests/session.ts b/src/harness/unittests/session.ts index efc769efeca..067cd351ec7 100644 --- a/src/harness/unittests/session.ts +++ b/src/harness/unittests/session.ts @@ -25,7 +25,7 @@ namespace ts.server { clearTimeout: noop, setImmediate: () => 0, clearImmediate: noop, - createHash: s => s + createHash: Harness.LanguageService.mockHash, }; const mockLogger: Logger = { diff --git a/src/harness/unittests/telemetry.ts b/src/harness/unittests/telemetry.ts index f250c732c0b..02be254c6f9 100644 --- a/src/harness/unittests/telemetry.ts +++ b/src/harness/unittests/telemetry.ts @@ -9,6 +9,7 @@ namespace ts.projectSystem { et.service.openClientFile(file.path); assert.equal(et.getEvents().length, 0); }); + it("only sends an event once", () => { const file = makeFile("/a.ts"); const tsconfig = makeFile("/tsconfig.json", {}); @@ -46,12 +47,13 @@ namespace ts.projectSystem { const et = new EventTracker([file1]); const compilerOptions: ts.CompilerOptions = { strict: true }; - const projectFileName = "foo.csproj"; + const projectFileName = "/hunter2/foo.csproj"; open(); // TODO: Apparently compilerOptions is mutated, so have to repeat it here! et.assertProjectInfoTelemetryEvent({ + projectId: Harness.LanguageService.mockHash("/hunter2/foo.csproj"), compilerOptions: { strict: true }, compileOnSave: true, // These properties can't be present for an external project, so they are undefined instead of false. @@ -195,6 +197,7 @@ namespace ts.projectSystem { const et = new EventTracker([jsconfig, file]); et.service.openClientFile(file.path); et.assertProjectInfoTelemetryEvent({ + projectId: Harness.LanguageService.mockHash("/jsconfig.json"), fileStats: fileStats({ js: 1 }), compilerOptions: autoJsCompilerOptions, typeAcquisition: { @@ -214,6 +217,7 @@ namespace ts.projectSystem { et.service.openClientFile(file.path); et.getEvent(server.ProjectLanguageServiceStateEvent, /*mayBeMore*/ true); et.assertProjectInfoTelemetryEvent({ + projectId: Harness.LanguageService.mockHash("/jsconfig.json"), fileStats: fileStats({ js: 1 }), compilerOptions: autoJsCompilerOptions, configFileName: "jsconfig.json", @@ -248,7 +252,26 @@ namespace ts.projectSystem { } assertProjectInfoTelemetryEvent(partial: Partial): void { - assert.deepEqual(this.getEvent(ts.server.ProjectInfoTelemetryEvent), makePayload(partial)); + assert.deepEqual(this.getEvent(ts.server.ProjectInfoTelemetryEvent), { + projectId: Harness.LanguageService.mockHash("/tsconfig.json"), + fileStats: fileStats({ ts: 1 }), + compilerOptions: {}, + extends: false, + files: false, + include: false, + exclude: false, + compileOnSave: false, + typeAcquisition: { + enable: false, + exclude: false, + include: false, + }, + configFileName: "tsconfig.json", + projectType: "configured", + languageServiceEnabled: true, + version: ts.version, + ...partial, + }); } getEvent(eventName: T["eventName"], mayBeMore = false): T["data"] { @@ -260,28 +283,6 @@ namespace ts.projectSystem { } } - function makePayload(partial: Partial): server.ProjectInfoTelemetryEventData { - return { - fileStats: fileStats({ ts: 1 }), - compilerOptions: {}, - extends: false, - files: false, - include: false, - exclude: false, - compileOnSave: false, - typeAcquisition: { - enable: false, - exclude: false, - include: false, - }, - configFileName: "tsconfig.json", - projectType: "configured", - languageServiceEnabled: true, - version: ts.version, - ...partial - }; - } - function makeFile(path: string, content: {} = ""): projectSystem.FileOrFolder { return { path, content: typeof content === "string" ? "" : JSON.stringify(content) }; } diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 7a19aa9167f..7c4a3068226 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -472,7 +472,7 @@ namespace ts.projectSystem { } createHash(s: string): string { - return s; + return Harness.LanguageService.mockHash(s); } triggerDirectoryWatcherCallback(directoryName: string, fileName: string): void { diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 7c0e0a0fb92..dd58935119b 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -37,6 +37,8 @@ namespace ts.server { } export interface ProjectInfoTelemetryEventData { + /** Cryptographically secure hash of project file location. */ + readonly projectId: string; /** Count of file extensions seen in the project. */ readonly fileStats: FileStats; /** @@ -1049,6 +1051,7 @@ namespace ts.server { if (!this.eventHandler) return; const data: ProjectInfoTelemetryEventData = { + projectId: this.host.createHash(projectKey), fileStats: countEachFileTypes(project.getScriptInfos()), compilerOptions: convertCompilerOptionsForTelemetry(project.getCompilerOptions()), typeAcquisition: convertTypeAcquisition(project.getTypeAcquisition()), diff --git a/src/server/server.ts b/src/server/server.ts index fa90e8df88d..5f2b7054755 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -35,6 +35,7 @@ namespace ts.server { } = require("os"); function getGlobalTypingsCacheLocation() { + const versionMajorMinor = ts.version.match(/\d+\.\d+/)[0]; switch (process.platform) { case "win32": { const basePath = process.env.LOCALAPPDATA || @@ -43,7 +44,7 @@ namespace ts.server { process.env.USERPROFILE || (process.env.HOMEDRIVE && process.env.HOMEPATH && normalizeSlashes(process.env.HOMEDRIVE + process.env.HOMEPATH)) || os.tmpdir(); - return combinePaths(normalizeSlashes(basePath), "Microsoft/TypeScript"); + return combinePaths(combinePaths(normalizeSlashes(basePath), "Microsoft/TypeScript"), versionMajorMinor); } case "openbsd": case "freebsd": @@ -51,7 +52,7 @@ namespace ts.server { case "linux": case "android": { const cacheLocation = getNonWindowsCacheLocation(process.platform === "darwin"); - return combinePaths(cacheLocation, "typescript"); + return combinePaths(combinePaths(cacheLocation, "typescript"), versionMajorMinor); } default: Debug.fail(`unsupported platform '${process.platform}'`); diff --git a/src/services/classifier.ts b/src/services/classifier.ts index ca8cf52a09b..ff33059630d 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -724,8 +724,8 @@ namespace ts { pushCommentRange(pos, tag.pos - pos); } - pushClassification(tag.atToken.pos, tag.atToken.end - tag.atToken.pos, ClassificationType.punctuation); - pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName); + pushClassification(tag.atToken.pos, tag.atToken.end - tag.atToken.pos, ClassificationType.punctuation); // "@" + pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName); // e.g. "param" pos = tag.tagName.end; @@ -814,7 +814,7 @@ namespace ts { * False will mean that node is not classified and traverse routine should recurse into node contents. */ function tryClassifyNode(node: Node): boolean { - if (isJSDocNode(node)) { + if (isJSDoc(node)) { return true; } diff --git a/src/services/completions.ts b/src/services/completions.ts index 99560ffb4d8..4a6b6170b78 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -445,7 +445,7 @@ namespace ts.Completions { } start = timestamp(); - const previousToken = findPrecedingToken(position, sourceFile); + const previousToken = findPrecedingToken(position, sourceFile, /*startNode*/ undefined, /*includeJsDoc*/ true); log("getCompletionData: Get previous token 1: " + (timestamp() - start)); // The decision to provide completion depends on the contextToken, which is determined through the previousToken. @@ -456,7 +456,7 @@ namespace ts.Completions { // Skip this partial identifier and adjust the contextToken to the token that precedes it. if (contextToken && position <= contextToken.end && isWord(contextToken.kind)) { const start = timestamp(); - contextToken = findPrecedingToken(contextToken.getFullStart(), sourceFile); + contextToken = findPrecedingToken(contextToken.getFullStart(), sourceFile, /*startNode*/ undefined, /*includeJsDoc*/ true); log("getCompletionData: Get previous token 2: " + (timestamp() - start)); } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 67a967ec8b9..56bd506887b 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -784,8 +784,8 @@ namespace ts.FindAllReferences.Core { return; } - const fullStart = state.options.findInComments || container.jsDoc !== undefined || forEach(search.symbol.declarations, d => d.kind === ts.SyntaxKind.JSDocTypedefTag); - for (const position of getPossibleSymbolReferencePositions(sourceFile, search.text, container, fullStart)) { + // Need to search in the full start of the node in case there is a reference inside JSDoc. + for (const position of getPossibleSymbolReferencePositions(sourceFile, search.text, container, /*fullStart*/ true)) { getReferencesAtLocation(sourceFile, position, search, state); } } diff --git a/src/services/preProcess.ts b/src/services/preProcess.ts index 0f0702066e1..7efc174c423 100644 --- a/src/services/preProcess.ts +++ b/src/services/preProcess.ts @@ -95,9 +95,16 @@ namespace ts { function tryConsumeImport(): boolean { let token = scanner.getToken(); if (token === SyntaxKind.ImportKeyword) { - token = nextToken(); - if (token === SyntaxKind.StringLiteral) { + if (token === SyntaxKind.OpenParenToken) { + token = nextToken(); + if (token === SyntaxKind.StringLiteral) { + // import("mod"); + recordModuleName(); + return true; + } + } + else if (token === SyntaxKind.StringLiteral) { // import "mod"; recordModuleName(); return true; @@ -297,7 +304,8 @@ namespace ts { // import * as NS from "mod" // import d, {a, b as B} from "mod" // import i = require("mod"); - // + // import("mod"); + // export * from "mod" // export {a as b} from "mod" // export import i = require("mod") diff --git a/src/services/services.ts b/src/services/services.ts index 22fa67dd1c5..2f835d7de64 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -37,7 +37,7 @@ namespace ts { let ruleProvider: formatting.RulesProvider; function createNode(kind: TKind, pos: number, end: number, parent?: Node): NodeObject | TokenObject | IdentifierObject { - const node = kind >= SyntaxKind.FirstNode ? new NodeObject(kind, pos, end) : + const node = isNodeKind(kind) ? new NodeObject(kind, pos, end) : kind === SyntaxKind.Identifier ? new IdentifierObject(SyntaxKind.Identifier, pos, end) : new TokenObject(kind, pos, end); node.parent = parent; @@ -103,10 +103,10 @@ namespace ts { return sourceFile.text.substring(this.getStart(sourceFile), this.getEnd()); } - private addSyntheticNodes(nodes: Node[], pos: number, end: number, useJSDocScanner?: boolean): number { + private addSyntheticNodes(nodes: Node[], pos: number, end: number): number { scanner.setTextPos(pos); while (pos < end) { - const token = useJSDocScanner ? scanner.scanJSDocToken() : scanner.scan(); + const token = scanner.scan(); Debug.assert(token !== SyntaxKind.EndOfFileToken); // Else it would infinitely loop const textPos = scanner.getTextPos(); if (textPos <= end) { @@ -136,54 +136,50 @@ namespace ts { } private createChildren(sourceFile?: SourceFileLike) { - if (this.kind === SyntaxKind.JSDocComment || isJSDocTag(this)) { + if (!isNodeKind(this.kind)) { + this._children = emptyArray; + return; + } + + if (isJSDocCommentContainingNode(this)) { /** Don't add trivia for "tokens" since this is in a comment. */ const children: Node[] = []; this.forEachChild(child => { children.push(child); }); this._children = children; + return; } - else if (this.kind >= SyntaxKind.FirstNode) { - const children: Node[] = []; - scanner.setText((sourceFile || this.getSourceFile()).text); - let pos = this.pos; - const useJSDocScanner = isJSDocNode(this); - const processNode = (node: Node) => { - const isJSDocTagNode = isJSDocNode(node); - if (!isJSDocTagNode && pos < node.pos) { - pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner); - } - children.push(node); - if (!isJSDocTagNode) { - pos = node.end; - } - }; - const processNodes = (nodes: NodeArray) => { - if (pos < nodes.pos) { - pos = this.addSyntheticNodes(children, pos, nodes.pos, useJSDocScanner); - } - children.push(this.createSyntaxList(nodes)); - pos = nodes.end; - }; - // jsDocComments need to be the first children - if (this.jsDoc) { - for (const jsDocComment of this.jsDoc) { - processNode(jsDocComment); - } + + const children: Node[] = []; + scanner.setText((sourceFile || this.getSourceFile()).text); + let pos = this.pos; + const processNode = (node: Node) => { + pos = this.addSyntheticNodes(children, pos, node.pos); + children.push(node); + pos = node.end; + }; + const processNodes = (nodes: NodeArray) => { + if (pos < nodes.pos) { + pos = this.addSyntheticNodes(children, pos, nodes.pos); } - // For syntactic classifications, all trivia are classcified together, including jsdoc comments. - // For that to work, the jsdoc comments should still be the leading trivia of the first child. - // Restoring the scanner position ensures that. - pos = this.pos; - forEachChild(this, processNode, processNodes); - if (pos < this.end) { - this.addSyntheticNodes(children, pos, this.end); + children.push(this.createSyntaxList(nodes)); + pos = nodes.end; + }; + // jsDocComments need to be the first children + if (this.jsDoc) { + for (const jsDocComment of this.jsDoc) { + processNode(jsDocComment); } - scanner.setText(undefined); - this._children = children; } - else { - this._children = emptyArray; + // For syntactic classifications, all trivia are classcified together, including jsdoc comments. + // For that to work, the jsdoc comments should still be the leading trivia of the first child. + // Restoring the scanner position ensures that. + pos = this.pos; + forEachChild(this, processNode, processNodes); + if (pos < this.end) { + this.addSyntheticNodes(children, pos, this.end); } + scanner.setText(undefined); + this._children = children; } public getChildCount(sourceFile?: SourceFile): number { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index ab958099c11..1eb315dcbb1 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -94,6 +94,10 @@ namespace ts { else if (isNamespaceReference(node)) { return SemanticMeaning.Namespace; } + else if (isTypeParameter(node.parent)) { + Debug.assert(isJSDocTemplateTag(node.parent.parent)); // Else would be handled by isDeclarationName + return SemanticMeaning.Type; + } else { return SemanticMeaning.Value; } @@ -710,7 +714,7 @@ namespace ts { } } - export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node): Node { + export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node, includeJsDoc?: boolean): Node { return find(startNode || sourceFile); function findRightmostToken(n: Node): Node { @@ -741,7 +745,7 @@ namespace ts { // NOTE: JsxText is a weird kind of node that can contain only whitespaces (since they are not counted as trivia). // if this is the case - then we should assume that token in question is located in previous child. if (position < child.end && (nodeHasTokens(child) || child.kind === SyntaxKind.JsxText)) { - const start = child.getStart(sourceFile); + const start = (includeJsDoc && child.jsDoc ? child.jsDoc[0] : child).getStart(sourceFile); const lookInPreviousChild = (start >= position) || // cursor in the leading trivia (child.kind === SyntaxKind.JsxText && start === child.end); // whitespace only JsxText @@ -758,7 +762,7 @@ namespace ts { } } - Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile); + Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || isJSDocCommentContainingNode(n)); // Here we know that none of child token nodes embrace the position, // the only known case is when position is at the end of the file. diff --git a/tests/baselines/reference/checkJsdocReturnTag2.errors.txt b/tests/baselines/reference/checkJsdocReturnTag2.errors.txt new file mode 100644 index 00000000000..23a450c83ca --- /dev/null +++ b/tests/baselines/reference/checkJsdocReturnTag2.errors.txt @@ -0,0 +1,25 @@ +tests/cases/conformance/jsdoc/returns.js(6,5): error TS2322: Type '5' is not assignable to type 'string'. +tests/cases/conformance/jsdoc/returns.js(13,5): error TS2322: Type 'true | 5' is not assignable to type 'string | number'. + Type 'true' is not assignable to type 'string | number'. + + +==== tests/cases/conformance/jsdoc/returns.js (2 errors) ==== + // @ts-check + /** + * @returns {string} This comment is not currently exposed + */ + function f() { + return 5; + ~~~~~~~~~ +!!! error TS2322: Type '5' is not assignable to type 'string'. + } + + /** + * @returns {string | number} This comment is not currently exposed + */ + function f1() { + return 5 || true; + ~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type 'true | 5' is not assignable to type 'string | number'. +!!! error TS2322: Type 'true' is not assignable to type 'string | number'. + } \ No newline at end of file diff --git a/tests/baselines/reference/checkJsdocTypeTag1.types b/tests/baselines/reference/checkJsdocTypeTag1.types index 9368640edcb..898cf58806a 100644 --- a/tests/baselines/reference/checkJsdocTypeTag1.types +++ b/tests/baselines/reference/checkJsdocTypeTag1.types @@ -61,10 +61,10 @@ x(1); /** @type {function (number)} */ const x1 = (a) => a + 1; >x1 : (arg0: number) => any ->(a) => a + 1 : (a: any) => any ->a : any ->a + 1 : any ->a : any +>(a) => a + 1 : (a: number) => number +>a : number +>a + 1 : number +>a : number >1 : 1 x1(0); @@ -75,10 +75,10 @@ x1(0); /** @type {function (number): number} */ const x2 = (a) => a + 1; >x2 : (arg0: number) => number ->(a) => a + 1 : (a: any) => any ->a : any ->a + 1 : any ->a : any +>(a) => a + 1 : (a: number) => number +>a : number +>a + 1 : number +>a : number >1 : 1 x2(0); diff --git a/tests/baselines/reference/checkJsdocTypeTag2.errors.txt b/tests/baselines/reference/checkJsdocTypeTag2.errors.txt index ca02c578a36..3590c10e278 100644 --- a/tests/baselines/reference/checkJsdocTypeTag2.errors.txt +++ b/tests/baselines/reference/checkJsdocTypeTag2.errors.txt @@ -1,9 +1,10 @@ tests/cases/conformance/jsdoc/0.js(3,5): error TS2322: Type 'true' is not assignable to type 'string'. tests/cases/conformance/jsdoc/0.js(6,5): error TS2322: Type '"hello"' is not assignable to type 'number'. tests/cases/conformance/jsdoc/0.js(10,4): error TS2345: Argument of type '"string"' is not assignable to parameter of type 'number'. -tests/cases/conformance/jsdoc/0.js(13,7): error TS2451: Cannot redeclare block-scoped variable 'x2'. tests/cases/conformance/jsdoc/0.js(17,1): error TS2322: Type 'number' is not assignable to type 'string'. -tests/cases/conformance/jsdoc/0.js(20,7): error TS2451: Cannot redeclare block-scoped variable 'x2'. +tests/cases/conformance/jsdoc/0.js(20,21): error TS2339: Property 'concat' does not exist on type 'number'. +tests/cases/conformance/jsdoc/0.js(24,7): error TS2322: Type '(a: number) => number' is not assignable to type '(arg0: number) => string'. + Type 'number' is not assignable to type 'string'. ==== tests/cases/conformance/jsdoc/0.js (6 errors) ==== @@ -26,8 +27,6 @@ tests/cases/conformance/jsdoc/0.js(20,7): error TS2451: Cannot redeclare block-s /** @type {function (number): number} */ const x2 = (a) => a + 1; - ~~ -!!! error TS2451: Cannot redeclare block-scoped variable 'x2'. /** @type {string} */ var a; @@ -36,7 +35,14 @@ tests/cases/conformance/jsdoc/0.js(20,7): error TS2451: Cannot redeclare block-s !!! error TS2322: Type 'number' is not assignable to type 'string'. /** @type {function (number): number} */ - const x2 = (a) => a.concat("hi"); + const x3 = (a) => a.concat("hi"); + ~~~~~~ +!!! error TS2339: Property 'concat' does not exist on type 'number'. + x3(0); + + /** @type {function (number): string} */ + const x4 = (a) => a + 1; ~~ -!!! error TS2451: Cannot redeclare block-scoped variable 'x2'. - x2(0); \ No newline at end of file +!!! error TS2322: Type '(a: number) => number' is not assignable to type '(arg0: number) => string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + x4(0); \ No newline at end of file diff --git a/tests/baselines/reference/checkJsdocTypeTag2.js b/tests/baselines/reference/checkJsdocTypeTag2.js index 23b436e2031..0e550d3ba33 100644 --- a/tests/baselines/reference/checkJsdocTypeTag2.js +++ b/tests/baselines/reference/checkJsdocTypeTag2.js @@ -18,8 +18,12 @@ var a; a = x2(0); /** @type {function (number): number} */ -const x2 = (a) => a.concat("hi"); -x2(0); +const x3 = (a) => a.concat("hi"); +x3(0); + +/** @type {function (number): string} */ +const x4 = (a) => a + 1; +x4(0); //// [0.js] // @ts-check @@ -36,5 +40,8 @@ var x2 = function (a) { return a + 1; }; var a; a = x2(0); /** @type {function (number): number} */ -var x2 = function (a) { return a.concat("hi"); }; -x2(0); +var x3 = function (a) { return a.concat("hi"); }; +x3(0); +/** @type {function (number): string} */ +var x4 = function (a) { return a + 1; }; +x4(0); diff --git a/tests/baselines/reference/contextualTypeFromJSDoc.symbols b/tests/baselines/reference/contextualTypeFromJSDoc.symbols new file mode 100644 index 00000000000..5ebe1e01ca7 --- /dev/null +++ b/tests/baselines/reference/contextualTypeFromJSDoc.symbols @@ -0,0 +1,48 @@ +=== tests/cases/conformance/types/contextualTypes/jsdoc/index.js === +/** @type {Array<[string, {x?:number, y?:number}]>} */ +const arr = [ +>arr : Symbol(arr, Decl(index.js, 1, 5)) + + ['a', { x: 1 }], +>x : Symbol(x, Decl(index.js, 2, 11)) + + ['b', { y: 2 }] +>y : Symbol(y, Decl(index.js, 3, 11)) + +]; + +/** @return {Array<[string, {x?:number, y?:number}]>} */ +function f() { +>f : Symbol(f, Decl(index.js, 4, 2)) + + return [ + ['a', { x: 1 }], +>x : Symbol(x, Decl(index.js, 9, 15)) + + ['b', { y: 2 }] +>y : Symbol(y, Decl(index.js, 10, 15)) + + ]; +} + +class C { +>C : Symbol(C, Decl(index.js, 12, 1)) + + /** @param {Array<[string, {x?:number, y?:number}]>} value */ + set x(value) { } +>x : Symbol(C.x, Decl(index.js, 14, 9), Decl(index.js, 16, 20)) +>value : Symbol(value, Decl(index.js, 16, 10)) + + get x() { +>x : Symbol(C.x, Decl(index.js, 14, 9), Decl(index.js, 16, 20)) + + return [ + ['a', { x: 1 }], +>x : Symbol(x, Decl(index.js, 19, 19)) + + ['b', { y: 2 }] +>y : Symbol(y, Decl(index.js, 20, 19)) + + ]; + } +} diff --git a/tests/baselines/reference/contextualTypeFromJSDoc.types b/tests/baselines/reference/contextualTypeFromJSDoc.types new file mode 100644 index 00000000000..f1121935d38 --- /dev/null +++ b/tests/baselines/reference/contextualTypeFromJSDoc.types @@ -0,0 +1,77 @@ +=== tests/cases/conformance/types/contextualTypes/jsdoc/index.js === +/** @type {Array<[string, {x?:number, y?:number}]>} */ +const arr = [ +>arr : [string, { x?: number; y?: number; }][] +>[ ['a', { x: 1 }], ['b', { y: 2 }]] : ([string, { x: number; }] | [string, { y: number; }])[] + + ['a', { x: 1 }], +>['a', { x: 1 }] : [string, { x: number; }] +>'a' : "a" +>{ x: 1 } : { x: number; } +>x : number +>1 : 1 + + ['b', { y: 2 }] +>['b', { y: 2 }] : [string, { y: number; }] +>'b' : "b" +>{ y: 2 } : { y: number; } +>y : number +>2 : 2 + +]; + +/** @return {Array<[string, {x?:number, y?:number}]>} */ +function f() { +>f : () => [string, { x?: number; y?: number; }][] + + return [ +>[ ['a', { x: 1 }], ['b', { y: 2 }] ] : ([string, { x: number; }] | [string, { y: number; }])[] + + ['a', { x: 1 }], +>['a', { x: 1 }] : [string, { x: number; }] +>'a' : "a" +>{ x: 1 } : { x: number; } +>x : number +>1 : 1 + + ['b', { y: 2 }] +>['b', { y: 2 }] : [string, { y: number; }] +>'b' : "b" +>{ y: 2 } : { y: number; } +>y : number +>2 : 2 + + ]; +} + +class C { +>C : C + + /** @param {Array<[string, {x?:number, y?:number}]>} value */ + set x(value) { } +>x : [string, { x?: number; y?: number; }][] +>value : [string, { x?: number; y?: number; }][] + + get x() { +>x : [string, { x?: number; y?: number; }][] + + return [ +>[ ['a', { x: 1 }], ['b', { y: 2 }] ] : ([string, { x: number; }] | [string, { y: number; }])[] + + ['a', { x: 1 }], +>['a', { x: 1 }] : [string, { x: number; }] +>'a' : "a" +>{ x: 1 } : { x: number; } +>x : number +>1 : 1 + + ['b', { y: 2 }] +>['b', { y: 2 }] : [string, { y: number; }] +>'b' : "b" +>{ y: 2 } : { y: number; } +>y : number +>2 : 2 + + ]; + } +} diff --git a/tests/baselines/reference/excessPropertyCheckWithSpread.errors.txt b/tests/baselines/reference/excessPropertyCheckWithSpread.errors.txt new file mode 100644 index 00000000000..422d7fc280c --- /dev/null +++ b/tests/baselines/reference/excessPropertyCheckWithSpread.errors.txt @@ -0,0 +1,30 @@ +tests/cases/compiler/excessPropertyCheckWithSpread.ts(6,3): error TS2345: Argument of type '{ n: number; a: number; }' is not assignable to parameter of type '{ a: any; }'. + Object literal may only specify known properties, and 'n' does not exist in type '{ a: any; }'. +tests/cases/compiler/excessPropertyCheckWithSpread.ts(16,3): error TS2345: Argument of type '{ opt: string | number; a: number; }' is not assignable to parameter of type '{ a: any; }'. + Object literal may only specify known properties, and 'opt' does not exist in type '{ a: any; }'. + + +==== tests/cases/compiler/excessPropertyCheckWithSpread.ts (2 errors) ==== + declare function f({ a: number }): void + interface I { + readonly n: number; + } + declare let i: I; + f({ a: 1, ...i }); + ~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '{ n: number; a: number; }' is not assignable to parameter of type '{ a: any; }'. +!!! error TS2345: Object literal may only specify known properties, and 'n' does not exist in type '{ a: any; }'. + + interface R { + opt?: number + } + interface L { + opt: string + } + declare let l: L; + declare let r: R; + f({ a: 1, ...l, ...r }); + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '{ opt: string | number; a: number; }' is not assignable to parameter of type '{ a: any; }'. +!!! error TS2345: Object literal may only specify known properties, and 'opt' does not exist in type '{ a: any; }'. + \ No newline at end of file diff --git a/tests/baselines/reference/excessPropertyCheckWithSpread.js b/tests/baselines/reference/excessPropertyCheckWithSpread.js new file mode 100644 index 00000000000..d8dac07a3fb --- /dev/null +++ b/tests/baselines/reference/excessPropertyCheckWithSpread.js @@ -0,0 +1,30 @@ +//// [excessPropertyCheckWithSpread.ts] +declare function f({ a: number }): void +interface I { + readonly n: number; +} +declare let i: I; +f({ a: 1, ...i }); + +interface R { + opt?: number +} +interface L { + opt: string +} +declare let l: L; +declare let r: R; +f({ a: 1, ...l, ...r }); + + +//// [excessPropertyCheckWithSpread.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +f(__assign({ a: 1 }, i)); +f(__assign({ a: 1 }, l, r)); diff --git a/tests/baselines/reference/generatorTypeCheck63.errors.txt b/tests/baselines/reference/generatorTypeCheck63.errors.txt index ed2ed36a438..c08635e8b73 100644 --- a/tests/baselines/reference/generatorTypeCheck63.errors.txt +++ b/tests/baselines/reference/generatorTypeCheck63.errors.txt @@ -1,11 +1,12 @@ -tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(24,14): error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. - Type 'IterableIterator' is not assignable to type 'IterableIterator'. - Type 'State | 1' is not assignable to type 'State'. - Type '1' is not assignable to type 'State'. +tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(24,61): error TS2345: Argument of type '(state: State) => IterableIterator' is not assignable to parameter of type '(a: StrategicState) => IterableIterator'. + Type 'IterableIterator' is not assignable to type 'IterableIterator'. + Type 'State | 1' is not assignable to type 'StrategicState'. + Type '1' has no properties in common with type 'StrategicState'. tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(29,70): error TS7025: Generator implicitly has type 'IterableIterator' because it does not yield any values. Consider supplying a return type. tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(32,42): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly. Type argument candidate 'State' is not a valid type argument because it is not a supertype of candidate '1'. -tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(36,14): error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. +tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(36,62): error TS2345: Argument of type '(state: State) => IterableIterator' is not assignable to parameter of type '(a: StrategicState) => IterableIterator'. + Type 'IterableIterator' is not assignable to type 'IterableIterator'. ==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts (4 errors) ==== @@ -33,11 +34,11 @@ tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(36,14): err } export const Nothing: Strategy = strategy("Nothing", function* (state: State) { - ~~~~~~~ -!!! error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. -!!! error TS2322: Type 'IterableIterator' is not assignable to type 'IterableIterator'. -!!! error TS2322: Type 'State | 1' is not assignable to type 'State'. -!!! error TS2322: Type '1' is not assignable to type 'State'. + ~~~~~~~~ +!!! error TS2345: Argument of type '(state: State) => IterableIterator' is not assignable to parameter of type '(a: StrategicState) => IterableIterator'. +!!! error TS2345: Type 'IterableIterator' is not assignable to type 'IterableIterator'. +!!! error TS2345: Type 'State | 1' is not assignable to type 'StrategicState'. +!!! error TS2345: Type '1' has no properties in common with type 'StrategicState'. yield 1; return state; }); @@ -55,8 +56,9 @@ tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(36,14): err }); export const Nothing3: Strategy = strategy("Nothing", function* (state: State) { - ~~~~~~~~ -!!! error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. + ~~~~~~~~ +!!! error TS2345: Argument of type '(state: State) => IterableIterator' is not assignable to parameter of type '(a: StrategicState) => IterableIterator'. +!!! error TS2345: Type 'IterableIterator' is not assignable to type 'IterableIterator'. yield state; return 1; }); \ No newline at end of file diff --git a/tests/baselines/reference/importCallExpressionNoModuleKindSpecified.errors.txt b/tests/baselines/reference/importCallExpressionNoModuleKindSpecified.errors.txt new file mode 100644 index 00000000000..cf665dda049 --- /dev/null +++ b/tests/baselines/reference/importCallExpressionNoModuleKindSpecified.errors.txt @@ -0,0 +1,37 @@ +error TS2468: Cannot find global value 'Promise'. +tests/cases/conformance/dynamicImport/2.ts(3,24): error TS2712: A dynamic import call in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. +tests/cases/conformance/dynamicImport/2.ts(7,12): error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. +tests/cases/conformance/dynamicImport/2.ts(9,29): error TS2712: A dynamic import call in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. + + +!!! error TS2468: Cannot find global value 'Promise'. +==== tests/cases/conformance/dynamicImport/0.ts (0 errors) ==== + export class B { + print() { return "I am B"} + } + + export function foo() { return "foo" } + +==== tests/cases/conformance/dynamicImport/1.ts (0 errors) ==== + export function backup() { return "backup"; } + +==== tests/cases/conformance/dynamicImport/2.ts (3 errors) ==== + declare var console: any; + class C { + private myModule = import("./0"); + ~~~~~~~~~~~~~ +!!! error TS2712: A dynamic import call in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. + method() { + this.myModule.then(Zero => { + console.log(Zero.foo()); + }, async err => { + ~~~~~~~~~~~~~~ +!!! error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. + console.log(err); + let one = await import("./1"); + ~~~~~~~~~~~~~ +!!! error TS2712: A dynamic import call in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. + console.log(one.backup()); + }); + } + } \ No newline at end of file diff --git a/tests/baselines/reference/importCallExpressionNoModuleKindSpecified.js b/tests/baselines/reference/importCallExpressionNoModuleKindSpecified.js new file mode 100644 index 00000000000..487d4e03a6c --- /dev/null +++ b/tests/baselines/reference/importCallExpressionNoModuleKindSpecified.js @@ -0,0 +1,105 @@ +//// [tests/cases/conformance/dynamicImport/importCallExpressionNoModuleKindSpecified.ts] //// + +//// [0.ts] +export class B { + print() { return "I am B"} +} + +export function foo() { return "foo" } + +//// [1.ts] +export function backup() { return "backup"; } + +//// [2.ts] +declare var console: any; +class C { + private myModule = import("./0"); + method() { + this.myModule.then(Zero => { + console.log(Zero.foo()); + }, async err => { + console.log(err); + let one = await import("./1"); + console.log(one.backup()); + }); + } +} + +//// [0.js] +"use strict"; +exports.__esModule = true; +var B = (function () { + function B() { + } + B.prototype.print = function () { return "I am B"; }; + return B; +}()); +exports.B = B; +function foo() { return "foo"; } +exports.foo = foo; +//// [1.js] +"use strict"; +exports.__esModule = true; +function backup() { return "backup"; } +exports.backup = backup; +//// [2.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var C = (function () { + function C() { + this.myModule = Promise.resolve().then(function () { return require("./0"); }); + } + C.prototype.method = function () { + var _this = this; + this.myModule.then(function (Zero) { + console.log(Zero.foo()); + }, function (err) { return __awaiter(_this, void 0, void 0, function () { + var one; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + console.log(err); + return [4 /*yield*/, Promise.resolve().then(function () { return require("./1"); })]; + case 1: + one = _a.sent(); + console.log(one.backup()); + return [2 /*return*/]; + } + }); + }); }); + }; + return C; +}()); diff --git a/tests/baselines/reference/isolatedModulesReExportType.errors.txt b/tests/baselines/reference/isolatedModulesReExportType.errors.txt index 10c07cde084..dc035a84c2f 100644 --- a/tests/baselines/reference/isolatedModulesReExportType.errors.txt +++ b/tests/baselines/reference/isolatedModulesReExportType.errors.txt @@ -35,4 +35,14 @@ declare type T = number; export = T; +==== /node_modules/foo/bar.d.ts (0 errors) ==== + export type T = number; + +==== /node_modules/foo/index.d.ts (0 errors) ==== + export { T } from "./bar"; // In a declaration file, so not an error. + +==== /node_modules/baz/index.d.ts (0 errors) ==== + declare module "baz" { + export { T } from "foo"; // Also allowed. + } \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesReExportType.js b/tests/baselines/reference/isolatedModulesReExportType.js index 545e5a81a8a..5924dd249e7 100644 --- a/tests/baselines/reference/isolatedModulesReExportType.js +++ b/tests/baselines/reference/isolatedModulesReExportType.js @@ -9,7 +9,17 @@ export class C {} //// [exportEqualsT.ts] declare type T = number; export = T; - + +//// [bar.d.ts] +export type T = number; + +//// [index.d.ts] +export { T } from "./bar"; // In a declaration file, so not an error. + +//// [index.d.ts] +declare module "baz" { + export { T } from "foo"; // Also allowed. +} //// [user.ts] // Error, can't re-export something that's only a type. diff --git a/tests/baselines/reference/jsdocInTypeScript.errors.txt b/tests/baselines/reference/jsdocInTypeScript.errors.txt index 621aa4677b4..9aa0e377010 100644 --- a/tests/baselines/reference/jsdocInTypeScript.errors.txt +++ b/tests/baselines/reference/jsdocInTypeScript.errors.txt @@ -43,7 +43,16 @@ tests/cases/compiler/jsdocInTypeScript.ts(30,3): error TS2339: Property 'x' does // @type has no effect either. /** @type {{ x?: number }} */ const z = {}; - z.x = 1; + z.x = 1; // Error ~ !!! error TS2339: Property 'x' does not exist on type '{}'. + + // @template tag should not interfere with constraint or default. + /** @template T */ + interface I {} + + /** @template T */ + function tem(t: T): I { return {}; } + + let i: I; // Should succeed thanks to type parameter default \ No newline at end of file diff --git a/tests/baselines/reference/jsdocInTypeScript.js b/tests/baselines/reference/jsdocInTypeScript.js index 29782e92592..961c11bb00b 100644 --- a/tests/baselines/reference/jsdocInTypeScript.js +++ b/tests/baselines/reference/jsdocInTypeScript.js @@ -28,7 +28,16 @@ f(1); f(true).length; // @type has no effect either. /** @type {{ x?: number }} */ const z = {}; -z.x = 1; +z.x = 1; // Error + +// @template tag should not interfere with constraint or default. +/** @template T */ +interface I {} + +/** @template T */ +function tem(t: T): I { return {}; } + +let i: I; // Should succeed thanks to type parameter default //// [jsdocInTypeScript.js] @@ -50,4 +59,7 @@ f(true).length; // @type has no effect either. /** @type {{ x?: number }} */ var z = {}; -z.x = 1; +z.x = 1; // Error +/** @template T */ +function tem(t) { return {}; } +var i; // Should succeed thanks to type parameter default diff --git a/tests/baselines/reference/objectLiteralFunctionArgContextualTyping2.errors.txt b/tests/baselines/reference/objectLiteralFunctionArgContextualTyping2.errors.txt index b967b227809..0117d2c0c8c 100644 --- a/tests/baselines/reference/objectLiteralFunctionArgContextualTyping2.errors.txt +++ b/tests/baselines/reference/objectLiteralFunctionArgContextualTyping2.errors.txt @@ -4,12 +4,12 @@ tests/cases/compiler/objectLiteralFunctionArgContextualTyping2.ts(9,4): error TS Property 'doStuff' is missing in type '{ value: string; }'. tests/cases/compiler/objectLiteralFunctionArgContextualTyping2.ts(10,17): error TS2345: Argument of type '{ value: string; what: number; }' is not assignable to parameter of type 'I2'. Object literal may only specify known properties, and 'what' does not exist in type 'I2'. -tests/cases/compiler/objectLiteralFunctionArgContextualTyping2.ts(11,4): error TS2345: Argument of type '{ toString: (s: any) => any; }' is not assignable to parameter of type 'I2'. - Property 'value' is missing in type '{ toString: (s: any) => any; }'. -tests/cases/compiler/objectLiteralFunctionArgContextualTyping2.ts(12,4): error TS2345: Argument of type '{ toString: (s: string) => string; }' is not assignable to parameter of type 'I2'. - Property 'value' is missing in type '{ toString: (s: string) => string; }'. -tests/cases/compiler/objectLiteralFunctionArgContextualTyping2.ts(13,4): error TS2345: Argument of type '{ value: string; toString: (s: any) => any; }' is not assignable to parameter of type 'I2'. - Property 'doStuff' is missing in type '{ value: string; toString: (s: any) => any; }'. +tests/cases/compiler/objectLiteralFunctionArgContextualTyping2.ts(11,6): error TS2345: Argument of type '{ toString: (s: any) => any; }' is not assignable to parameter of type 'I2'. + Object literal may only specify known properties, and 'toString' does not exist in type 'I2'. +tests/cases/compiler/objectLiteralFunctionArgContextualTyping2.ts(12,6): error TS2345: Argument of type '{ toString: (s: string) => string; }' is not assignable to parameter of type 'I2'. + Object literal may only specify known properties, and 'toString' does not exist in type 'I2'. +tests/cases/compiler/objectLiteralFunctionArgContextualTyping2.ts(13,17): error TS2345: Argument of type '{ value: string; toString: (s: any) => any; }' is not assignable to parameter of type 'I2'. + Object literal may only specify known properties, and 'toString' does not exist in type 'I2'. ==== tests/cases/compiler/objectLiteralFunctionArgContextualTyping2.ts (6 errors) ==== @@ -33,14 +33,14 @@ tests/cases/compiler/objectLiteralFunctionArgContextualTyping2.ts(13,4): error T !!! error TS2345: Argument of type '{ value: string; what: number; }' is not assignable to parameter of type 'I2'. !!! error TS2345: Object literal may only specify known properties, and 'what' does not exist in type 'I2'. f2({ toString: (s) => s }) - ~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~ !!! error TS2345: Argument of type '{ toString: (s: any) => any; }' is not assignable to parameter of type 'I2'. -!!! error TS2345: Property 'value' is missing in type '{ toString: (s: any) => any; }'. +!!! error TS2345: Object literal may only specify known properties, and 'toString' does not exist in type 'I2'. f2({ toString: (s: string) => s }) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2345: Argument of type '{ toString: (s: string) => string; }' is not assignable to parameter of type 'I2'. -!!! error TS2345: Property 'value' is missing in type '{ toString: (s: string) => string; }'. +!!! error TS2345: Object literal may only specify known properties, and 'toString' does not exist in type 'I2'. f2({ value: '', toString: (s) => s.uhhh }) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2345: Argument of type '{ value: string; toString: (s: any) => any; }' is not assignable to parameter of type 'I2'. -!!! error TS2345: Property 'doStuff' is missing in type '{ value: string; toString: (s: any) => any; }'. \ No newline at end of file +!!! error TS2345: Object literal may only specify known properties, and 'toString' does not exist in type 'I2'. \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.js b/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.js new file mode 100644 index 00000000000..24a27fb919a --- /dev/null +++ b/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.js @@ -0,0 +1,14 @@ +//// [sourceMapValidationVarInDownLevelGenerator.ts] +function * f() { + var x = 1, y; +} + +//// [sourceMapValidationVarInDownLevelGenerator.js] +function f() { + var x, y; + return __generator(this, function (_a) { + x = 1; + return [2 /*return*/]; + }); +} +//# sourceMappingURL=sourceMapValidationVarInDownLevelGenerator.js.map \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.js.map b/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.js.map new file mode 100644 index 00000000000..293f445a6fd --- /dev/null +++ b/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.js.map @@ -0,0 +1,2 @@ +//// [sourceMapValidationVarInDownLevelGenerator.js.map] +{"version":3,"file":"sourceMapValidationVarInDownLevelGenerator.js","sourceRoot":"","sources":["sourceMapValidationVarInDownLevelGenerator.ts"],"names":[],"mappings":"AAAA;;;QACQ,CAAC,GAAG,CAAC,CAAI;;;CAChB"} \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.sourcemap.txt b/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.sourcemap.txt new file mode 100644 index 00000000000..8fe7af32307 --- /dev/null +++ b/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.sourcemap.txt @@ -0,0 +1,47 @@ +=================================================================== +JsFile: sourceMapValidationVarInDownLevelGenerator.js +mapUrl: sourceMapValidationVarInDownLevelGenerator.js.map +sourceRoot: +sources: sourceMapValidationVarInDownLevelGenerator.ts +=================================================================== +------------------------------------------------------------------- +emittedFile:tests/cases/compiler/sourceMapValidationVarInDownLevelGenerator.js +sourceFile:sourceMapValidationVarInDownLevelGenerator.ts +------------------------------------------------------------------- +>>>function f() { +1 > +2 >^^^^^^^^^^^^^^-> +1 > +1 >Emitted(1, 1) Source(1, 1) + SourceIndex(0) +--- +>>> var x, y; +>>> return __generator(this, function (_a) { +>>> x = 1; +1->^^^^^^^^ +2 > ^ +3 > ^^^ +4 > ^ +5 > ^ +6 > ^^^^^^^^^^^^^^^^^-> +1->function * f() { + > var +2 > x +3 > = +4 > 1 +5 > , y; +1->Emitted(4, 9) Source(2, 9) + SourceIndex(0) +2 >Emitted(4, 10) Source(2, 10) + SourceIndex(0) +3 >Emitted(4, 13) Source(2, 13) + SourceIndex(0) +4 >Emitted(4, 14) Source(2, 14) + SourceIndex(0) +5 >Emitted(4, 15) Source(2, 18) + SourceIndex(0) +--- +>>> return [2 /*return*/]; +>>> }); +>>>} +1->^ +2 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +1-> + >} +1->Emitted(7, 2) Source(3, 2) + SourceIndex(0) +--- +>>>//# sourceMappingURL=sourceMapValidationVarInDownLevelGenerator.js.map \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.symbols b/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.symbols new file mode 100644 index 00000000000..99c9c4d714a --- /dev/null +++ b/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/sourceMapValidationVarInDownLevelGenerator.ts === +function * f() { +>f : Symbol(f, Decl(sourceMapValidationVarInDownLevelGenerator.ts, 0, 0)) + + var x = 1, y; +>x : Symbol(x, Decl(sourceMapValidationVarInDownLevelGenerator.ts, 1, 7)) +>y : Symbol(y, Decl(sourceMapValidationVarInDownLevelGenerator.ts, 1, 14)) +} diff --git a/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.types b/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.types new file mode 100644 index 00000000000..cac2f03d8e4 --- /dev/null +++ b/tests/baselines/reference/sourceMapValidationVarInDownLevelGenerator.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/sourceMapValidationVarInDownLevelGenerator.ts === +function * f() { +>f : () => IterableIterator + + var x = 1, y; +>x : number +>1 : 1 +>y : any +} diff --git a/tests/baselines/reference/tsxSpreadAttributesResolution1.js b/tests/baselines/reference/tsxSpreadAttributesResolution1.js index f8c3cfbb594..7d83e9bd390 100644 --- a/tests/baselines/reference/tsxSpreadAttributesResolution1.js +++ b/tests/baselines/reference/tsxSpreadAttributesResolution1.js @@ -7,11 +7,12 @@ class Poisoned extends React.Component<{}, {}> { } } -const obj: Object = {}; +const obj = {}; // OK let p = ; -let y = ; +let y = ; + //// [file.jsx] "use strict"; diff --git a/tests/baselines/reference/tsxSpreadAttributesResolution1.symbols b/tests/baselines/reference/tsxSpreadAttributesResolution1.symbols index 82a4e5cc822..9b3f535f309 100644 --- a/tests/baselines/reference/tsxSpreadAttributesResolution1.symbols +++ b/tests/baselines/reference/tsxSpreadAttributesResolution1.symbols @@ -17,9 +17,8 @@ class Poisoned extends React.Component<{}, {}> { } } -const obj: Object = {}; +const obj = {}; >obj : Symbol(obj, Decl(file.tsx, 8, 5)) ->Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) // OK let p = ; diff --git a/tests/baselines/reference/tsxSpreadAttributesResolution1.types b/tests/baselines/reference/tsxSpreadAttributesResolution1.types index f8f1cb8d15a..26f83c74001 100644 --- a/tests/baselines/reference/tsxSpreadAttributesResolution1.types +++ b/tests/baselines/reference/tsxSpreadAttributesResolution1.types @@ -18,9 +18,8 @@ class Poisoned extends React.Component<{}, {}> { } } -const obj: Object = {}; ->obj : Object ->Object : Object +const obj = {}; +>obj : {} >{} : {} // OK @@ -28,7 +27,7 @@ let p = ; >p : JSX.Element > : JSX.Element >Poisoned : typeof Poisoned ->obj : Object +>obj : {} let y = ; >y : JSX.Element diff --git a/tests/baselines/reference/weakType.errors.txt b/tests/baselines/reference/weakType.errors.txt index 7064ace5daa..441ef70ac16 100644 --- a/tests/baselines/reference/weakType.errors.txt +++ b/tests/baselines/reference/weakType.errors.txt @@ -1,11 +1,14 @@ -tests/cases/compiler/weakType.ts(31,18): error TS2559: Type '{ error?: number; }' has no properties in common with type 'ChangeOptions'. -tests/cases/compiler/weakType.ts(56,5): error TS2322: Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak & Spoiler'. +tests/cases/compiler/weakType.ts(16,13): error TS2559: Type '12' has no properties in common with type 'Settings'. +tests/cases/compiler/weakType.ts(17,13): error TS2559: Type '"completely wrong"' has no properties in common with type 'Settings'. +tests/cases/compiler/weakType.ts(18,13): error TS2559: Type 'false' has no properties in common with type 'Settings'. +tests/cases/compiler/weakType.ts(35,18): error TS2559: Type '{ error?: number; }' has no properties in common with type 'ChangeOptions'. +tests/cases/compiler/weakType.ts(60,5): error TS2322: Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak & Spoiler'. Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak'. Types of property 'properties' are incompatible. Type '{ wrong: string; }' has no properties in common with type '{ b?: number; }'. -==== tests/cases/compiler/weakType.ts (2 errors) ==== +==== tests/cases/compiler/weakType.ts (5 errors) ==== interface Settings { timeout?: number; onError?(): void; @@ -16,10 +19,20 @@ tests/cases/compiler/weakType.ts(56,5): error TS2322: Type '{ properties: { wron } function doSomething(settings: Settings) { /* ... */ } - // forgot to call `getDefaultSettings` // but it is not caught because we don't check for call signatures doSomething(getDefaultSettings); + // same for arrow expressions: + doSomething(() => { }); + doSomething(12); + ~~ +!!! error TS2559: Type '12' has no properties in common with type 'Settings'. + doSomething('completely wrong'); + ~~~~~~~~~~~~~~~~~~ +!!! error TS2559: Type '"completely wrong"' has no properties in common with type 'Settings'. + doSomething(false); + ~~~~~ +!!! error TS2559: Type 'false' has no properties in common with type 'Settings'. // this is an oddly popular way of defining settings // this example is from services/textChanges.ts diff --git a/tests/baselines/reference/weakType.js b/tests/baselines/reference/weakType.js index 6ed3ff1814d..5637271ccec 100644 --- a/tests/baselines/reference/weakType.js +++ b/tests/baselines/reference/weakType.js @@ -9,10 +9,14 @@ function getDefaultSettings() { } function doSomething(settings: Settings) { /* ... */ } - // forgot to call `getDefaultSettings` // but it is not caught because we don't check for call signatures doSomething(getDefaultSettings); +// same for arrow expressions: +doSomething(() => { }); +doSomething(12); +doSomething('completely wrong'); +doSomething(false); // this is an oddly popular way of defining settings // this example is from services/textChanges.ts @@ -65,6 +69,11 @@ function doSomething(settings) { } // forgot to call `getDefaultSettings` // but it is not caught because we don't check for call signatures doSomething(getDefaultSettings); +// same for arrow expressions: +doSomething(function () { }); +doSomething(12); +doSomething('completely wrong'); +doSomething(false); function del(options, error) { if (options === void 0) { options = {}; } if (error === void 0) { error = {}; } diff --git a/tests/cases/compiler/excessPropertyCheckWithSpread.ts b/tests/cases/compiler/excessPropertyCheckWithSpread.ts new file mode 100644 index 00000000000..11c573b4ce4 --- /dev/null +++ b/tests/cases/compiler/excessPropertyCheckWithSpread.ts @@ -0,0 +1,16 @@ +declare function f({ a: number }): void +interface I { + readonly n: number; +} +declare let i: I; +f({ a: 1, ...i }); + +interface R { + opt?: number +} +interface L { + opt: string +} +declare let l: L; +declare let r: R; +f({ a: 1, ...l, ...r }); diff --git a/tests/cases/compiler/isolatedModulesReExportType.ts b/tests/cases/compiler/isolatedModulesReExportType.ts index d1e05af6c83..6d82fd3f180 100644 --- a/tests/cases/compiler/isolatedModulesReExportType.ts +++ b/tests/cases/compiler/isolatedModulesReExportType.ts @@ -10,6 +10,16 @@ export class C {} declare type T = number; export = T; +// @Filename: /node_modules/foo/bar.d.ts +export type T = number; + +// @Filename: /node_modules/foo/index.d.ts +export { T } from "./bar"; // In a declaration file, so not an error. + +// @Filename: /node_modules/baz/index.d.ts +declare module "baz" { + export { T } from "foo"; // Also allowed. +} // @Filename: /user.ts // Error, can't re-export something that's only a type. diff --git a/tests/cases/compiler/jsdocInTypeScript.ts b/tests/cases/compiler/jsdocInTypeScript.ts index 08cfb6d5af5..b0f052472e0 100644 --- a/tests/cases/compiler/jsdocInTypeScript.ts +++ b/tests/cases/compiler/jsdocInTypeScript.ts @@ -27,4 +27,13 @@ f(1); f(true).length; // @type has no effect either. /** @type {{ x?: number }} */ const z = {}; -z.x = 1; +z.x = 1; // Error + +// @template tag should not interfere with constraint or default. +/** @template T */ +interface I {} + +/** @template T */ +function tem(t: T): I { return {}; } + +let i: I; // Should succeed thanks to type parameter default diff --git a/tests/cases/compiler/sourceMapValidationVarInDownLevelGenerator.ts b/tests/cases/compiler/sourceMapValidationVarInDownLevelGenerator.ts new file mode 100644 index 00000000000..1a1bbd5a806 --- /dev/null +++ b/tests/cases/compiler/sourceMapValidationVarInDownLevelGenerator.ts @@ -0,0 +1,7 @@ +// @sourcemap: true +// @downlevelIteration: true +// @noEmitHelpers: true +// @lib: es2015 +function * f() { + var x = 1, y; +} \ No newline at end of file diff --git a/tests/cases/compiler/weakType.ts b/tests/cases/compiler/weakType.ts index f04f36c9c2f..ffe51205e53 100644 --- a/tests/cases/compiler/weakType.ts +++ b/tests/cases/compiler/weakType.ts @@ -8,10 +8,14 @@ function getDefaultSettings() { } function doSomething(settings: Settings) { /* ... */ } - // forgot to call `getDefaultSettings` // but it is not caught because we don't check for call signatures doSomething(getDefaultSettings); +// same for arrow expressions: +doSomething(() => { }); +doSomething(12); +doSomething('completely wrong'); +doSomething(false); // this is an oddly popular way of defining settings // this example is from services/textChanges.ts diff --git a/tests/cases/conformance/dynamicImport/importCallExpressionNoModuleKindSpecified.ts b/tests/cases/conformance/dynamicImport/importCallExpressionNoModuleKindSpecified.ts new file mode 100644 index 00000000000..2d2f54e00b1 --- /dev/null +++ b/tests/cases/conformance/dynamicImport/importCallExpressionNoModuleKindSpecified.ts @@ -0,0 +1,24 @@ +// @filename: 0.ts +export class B { + print() { return "I am B"} +} + +export function foo() { return "foo" } + +// @filename: 1.ts +export function backup() { return "backup"; } + +// @filename: 2.ts +declare var console: any; +class C { + private myModule = import("./0"); + method() { + this.myModule.then(Zero => { + console.log(Zero.foo()); + }, async err => { + console.log(err); + let one = await import("./1"); + console.log(one.backup()); + }); + } +} \ No newline at end of file diff --git a/tests/cases/conformance/jsdoc/checkJsdocTypeTag2.ts b/tests/cases/conformance/jsdoc/checkJsdocTypeTag2.ts index a7dffdb90a7..14c6fffd6d6 100644 --- a/tests/cases/conformance/jsdoc/checkJsdocTypeTag2.ts +++ b/tests/cases/conformance/jsdoc/checkJsdocTypeTag2.ts @@ -21,5 +21,9 @@ var a; a = x2(0); /** @type {function (number): number} */ -const x2 = (a) => a.concat("hi"); -x2(0); \ No newline at end of file +const x3 = (a) => a.concat("hi"); +x3(0); + +/** @type {function (number): string} */ +const x4 = (a) => a + 1; +x4(0); \ No newline at end of file diff --git a/tests/cases/conformance/jsx/tsxSpreadAttributesResolution1.tsx b/tests/cases/conformance/jsx/tsxSpreadAttributesResolution1.tsx index 6d5225df2d9..a14a7ffe59c 100644 --- a/tests/cases/conformance/jsx/tsxSpreadAttributesResolution1.tsx +++ b/tests/cases/conformance/jsx/tsxSpreadAttributesResolution1.tsx @@ -11,8 +11,8 @@ class Poisoned extends React.Component<{}, {}> { } } -const obj: Object = {}; +const obj = {}; // OK let p = ; -let y = ; \ No newline at end of file +let y = ; diff --git a/tests/cases/conformance/types/contextualTypes/jsdoc/contextualTypeFromJSDoc.ts b/tests/cases/conformance/types/contextualTypes/jsdoc/contextualTypeFromJSDoc.ts new file mode 100644 index 00000000000..c9d7cc54d58 --- /dev/null +++ b/tests/cases/conformance/types/contextualTypes/jsdoc/contextualTypeFromJSDoc.ts @@ -0,0 +1,30 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @filename: index.js +// @target: esnext + +/** @type {Array<[string, {x?:number, y?:number}]>} */ +const arr = [ + ['a', { x: 1 }], + ['b', { y: 2 }] +]; + +/** @return {Array<[string, {x?:number, y?:number}]>} */ +function f() { + return [ + ['a', { x: 1 }], + ['b', { y: 2 }] + ]; +} + +class C { + /** @param {Array<[string, {x?:number, y?:number}]>} value */ + set x(value) { } + get x() { + return [ + ['a', { x: 1 }], + ['b', { y: 2 }] + ]; + } +} \ No newline at end of file diff --git a/tests/cases/fourslash/completionInJsDocQualifiedNames.ts b/tests/cases/fourslash/completionInJsDocQualifiedNames.ts new file mode 100644 index 00000000000..507f6b49fe3 --- /dev/null +++ b/tests/cases/fourslash/completionInJsDocQualifiedNames.ts @@ -0,0 +1,15 @@ +/// + +// @allowJs: true + +// @Filename: /node_modules/foo/index.d.ts +/////** tee */ +////export type T = number; + +// @Filename: /a.js +////import * as Foo from "foo"; +/////** @type {Foo./**/} */ +////const x = 0; + +goTo.marker(); +verify.completionListContains("T", "type T = number", "tee ", "type"); diff --git a/tests/cases/fourslash/findAllRefsJsDocTemplateTag_class.ts b/tests/cases/fourslash/findAllRefsJsDocTemplateTag_class.ts new file mode 100644 index 00000000000..3c1930eb37b --- /dev/null +++ b/tests/cases/fourslash/findAllRefsJsDocTemplateTag_class.ts @@ -0,0 +1,6 @@ +/// + +/////** @template [|T|] */ +////class C<[|{| "isWriteAccess": true, "isDefinition": true |}T|]> {} + +verify.singleReferenceGroup("(type parameter) T in C"); diff --git a/tests/cases/fourslash/findAllRefsJsDocTemplateTag_class_js.ts b/tests/cases/fourslash/findAllRefsJsDocTemplateTag_class_js.ts new file mode 100644 index 00000000000..6577cfce15d --- /dev/null +++ b/tests/cases/fourslash/findAllRefsJsDocTemplateTag_class_js.ts @@ -0,0 +1,17 @@ +/// + +// @allowJs: true +// @Filename: /a.js + +// TODO: https://github.com/Microsoft/TypeScript/issues/16411 +// Both uses of T should be referenced. + +/////** @template [|{| "isWriteAccess": true, "isDefinition": true |}T|] */ +////class C { +//// constructor() { +//// /** @type {T} */ +//// this.x = null; +//// } +////} + +verify.singleReferenceGroup("(type parameter) T in C"); diff --git a/tests/cases/fourslash/findAllRefsJsDocTemplateTag_function.ts b/tests/cases/fourslash/findAllRefsJsDocTemplateTag_function.ts new file mode 100644 index 00000000000..394c7cf5e5e --- /dev/null +++ b/tests/cases/fourslash/findAllRefsJsDocTemplateTag_function.ts @@ -0,0 +1,6 @@ +/// + +/////** @template [|{| "isWriteAccess": false, "isDefinition": false |}T|] */ +////function f<[|{| "isWriteAccess": true, "isDefinition": true |}T|]>() {} + +verify.singleReferenceGroup("(type parameter) T in f(): void"); diff --git a/tests/cases/fourslash/findAllRefsJsDocTemplateTag_function_js.ts b/tests/cases/fourslash/findAllRefsJsDocTemplateTag_function_js.ts new file mode 100644 index 00000000000..0eb20cc32d6 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsJsDocTemplateTag_function_js.ts @@ -0,0 +1,12 @@ +/// + +// @allowJs: true +// @Filename: /a.js + +/////** +//// * @template [|{| "isWriteAccess": true, "isDefinition": true |}T|] +//// * @return {[|T|]} +//// */ +////function f() {} + +verify.singleReferenceGroup("(type parameter) T"); // TODO:GH#??? should be "(type parameter) T in f(): void" diff --git a/tests/cases/fourslash/incrementalParsingDynamicImport1.ts b/tests/cases/fourslash/incrementalParsingDynamicImport1.ts new file mode 100644 index 00000000000..0f15dcb3b1b --- /dev/null +++ b/tests/cases/fourslash/incrementalParsingDynamicImport1.ts @@ -0,0 +1,17 @@ +/// + +// @lib: es6 + +// @Filename: ./foo.ts +//// export function bar() { return 1; } + +//// var x1 = import("./foo"); +//// x1.then(foo => { +//// var s: string = foo.bar(); +//// }) +//// /*1*/ + +verify.numberOfErrorsInCurrentFile(1); +goTo.marker("1"); +edit.insert(" "); +verify.numberOfErrorsInCurrentFile(1); \ No newline at end of file