diff --git a/.mailmap b/.mailmap index 2be2abbdfd2..4f27b3087b8 100644 --- a/.mailmap +++ b/.mailmap @@ -340,4 +340,5 @@ Paul Koerbitz EcoleKeine # Ecole Keine Khải rhysd # @rhysd -Zen <843968788@qq.com> Zzzen <843968788@qq.com> # @Zzzen \ No newline at end of file +Zen <843968788@qq.com> Zzzen <843968788@qq.com> # @Zzzen +bluelovers # @bluelovers \ No newline at end of file diff --git a/AUTHORS.md b/AUTHORS.md index 8ffe4b73c29..0c31c45e2ed 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -52,6 +52,7 @@ TypeScript is authored by: * Bill Ticehurst * Blaine Bublitz * Blake Embrey +* @bluelovers * @bootstraponline * Bowden Kelly * Bowden Kenny diff --git a/lib/lib.es2015.core.d.ts b/lib/lib.es2015.core.d.ts index 7c43b36c424..16105331f1f 100644 --- a/lib/lib.es2015.core.d.ts +++ b/lib/lib.es2015.core.d.ts @@ -222,29 +222,29 @@ interface NumberConstructor { * Returns true if passed value is finite. * Unlike the global isFinite, Number.isFinite doesn't forcibly convert the parameter to a * number. Only finite values of the type number, result in true. - * @param number A numeric value. + * @param value The value you want to test. */ - isFinite(number: number): boolean; + isFinite(value: any): boolean; /** * Returns true if the value passed is an integer, false otherwise. - * @param number A numeric value. + * @param value The value you want to test. */ - isInteger(number: number): boolean; + isInteger(value: any): boolean; /** * Returns a Boolean value that indicates whether a value is the reserved value NaN (not a * number). Unlike the global isNaN(), Number.isNaN() doesn't forcefully convert the parameter * to a number. Only values of the type number, that are also NaN, result in true. - * @param number A numeric value. + * @param value The value you want to test. */ - isNaN(number: number): boolean; + isNaN(number: any): boolean; /** * Returns true if the value passed is a safe integer. - * @param number A numeric value. + * @param value The value you want to test */ - isSafeInteger(number: number): boolean; + isSafeInteger(value: any): boolean; /** * The value of the largest integer n such that n and n + 1 are both exactly representable as diff --git a/scripts/tslint/rules/nextLineRule.ts b/scripts/tslint/rules/nextLineRule.ts index fa03746afc6..9de80793c62 100644 --- a/scripts/tslint/rules/nextLineRule.ts +++ b/scripts/tslint/rules/nextLineRule.ts @@ -52,8 +52,8 @@ function walk(ctx: Lint.WalkContext, checkCatch: boolean, checkElse: boole return; } - const tryClosingBrace = tryBlock.getLastToken(sourceFile); - const catchKeyword = catchClause.getFirstToken(sourceFile); + const tryClosingBrace = tryBlock.getLastToken(sourceFile)!; + const catchKeyword = catchClause.getFirstToken(sourceFile)!; const tryClosingBraceLoc = sourceFile.getLineAndCharacterOfPosition(tryClosingBrace.getEnd()); const catchKeywordLoc = sourceFile.getLineAndCharacterOfPosition(catchKeyword.getStart(sourceFile)); if (tryClosingBraceLoc.line === catchKeywordLoc.line) { diff --git a/scripts/tslint/rules/noInOperatorRule.ts b/scripts/tslint/rules/noInOperatorRule.ts index 448cf90cacd..95f052ccaa6 100644 --- a/scripts/tslint/rules/noInOperatorRule.ts +++ b/scripts/tslint/rules/noInOperatorRule.ts @@ -12,7 +12,7 @@ export class Rule extends Lint.Rules.AbstractRule { function walk(ctx: Lint.WalkContext): void { ts.forEachChild(ctx.sourceFile, recur); function recur(node: ts.Node): void { - if (node.kind === ts.SyntaxKind.InKeyword && node.parent!.kind === ts.SyntaxKind.BinaryExpression) { + if (node.kind === ts.SyntaxKind.InKeyword && node.parent.kind === ts.SyntaxKind.BinaryExpression) { ctx.addFailureAtNode(node, Rule.FAILURE_STRING); } } diff --git a/scripts/tslint/rules/noIncrementDecrementRule.ts b/scripts/tslint/rules/noIncrementDecrementRule.ts index ff2d81b1962..007d25919e1 100644 --- a/scripts/tslint/rules/noIncrementDecrementRule.ts +++ b/scripts/tslint/rules/noIncrementDecrementRule.ts @@ -28,7 +28,7 @@ function walk(ctx: Lint.WalkContext): void { } function check(node: ts.UnaryExpression): void { - if (!isAllowedLocation(node.parent!)) { + if (!isAllowedLocation(node.parent)) { ctx.addFailureAtNode(node, Rule.POSTFIX_FAILURE_STRING); } } @@ -47,7 +47,7 @@ function isAllowedLocation(node: ts.Node): boolean { // Can be in a comma operator in a for statement (`for (let a = 0, b = 10; a < b; a++, b--)`) case ts.SyntaxKind.BinaryExpression: return (node as ts.BinaryExpression).operatorToken.kind === ts.SyntaxKind.CommaToken && - node.parent!.kind === ts.SyntaxKind.ForStatement; + node.parent.kind === ts.SyntaxKind.ForStatement; default: return false; diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 7dd4ed1a39a..5b48a69fa04 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3712,6 +3712,10 @@ namespace ts { break; case SyntaxKind.ReturnStatement: + // Return statements may require an `await` in ESNext. + transformFlags |= TransformFlags.ContainsHoistedDeclarationOrCompletion | TransformFlags.AssertESNext; + break; + case SyntaxKind.ContinueStatement: case SyntaxKind.BreakStatement: transformFlags |= TransformFlags.ContainsHoistedDeclarationOrCompletion; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 237553141f6..7dd798a935d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -99,7 +99,7 @@ namespace ts { getGlobalDiagnostics, getTypeOfSymbolAtLocation: (symbol, location) => { location = getParseTreeNode(location); - return location ? getTypeOfSymbolAtLocation(symbol, location) : unknownType; + return location ? getTypeOfSymbolAtLocation(symbol, location) : errorType; }, getSymbolsOfParameterPropertyDeclaration: (parameterIn, parameterName) => { const parameter = getParseTreeNode(parameterIn, isParameter); @@ -117,7 +117,7 @@ namespace ts { getWidenedType, getTypeFromTypeNode: nodeIn => { const node = getParseTreeNode(nodeIn, isTypeNode); - return node ? getTypeFromTypeNode(node) : unknownType; + return node ? getTypeFromTypeNode(node) : errorType; }, getParameterType: getTypeAtPosition, getReturnTypeOfSignature, @@ -152,7 +152,7 @@ namespace ts { }, getTypeAtLocation: node => { node = getParseTreeNode(node); - return node ? getTypeOfNode(node) : unknownType; + return node ? getTypeOfNode(node) : errorType; }, getPropertySymbolOfDestructuringAssignment: locationIn => { const location = getParseTreeNode(locationIn, isIdentifier); @@ -353,7 +353,8 @@ namespace ts { const anyType = createIntrinsicType(TypeFlags.Any, "any"); const autoType = createIntrinsicType(TypeFlags.Any, "any"); const wildcardType = createIntrinsicType(TypeFlags.Any, "any"); - const unknownType = createIntrinsicType(TypeFlags.Any, "unknown"); + const errorType = createIntrinsicType(TypeFlags.Any, "error"); + const unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined"); const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined"); const nullType = createIntrinsicType(TypeFlags.Null, "null"); @@ -398,7 +399,7 @@ namespace ts { const noTypePredicate = createIdentifierTypePredicate("<>", 0, anyType); const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); - const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); + const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, errorType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); const resolvingSignaturesArray = [resolvingSignature]; @@ -1290,7 +1291,7 @@ namespace ts { isInExternalModule = true; // falls through case SyntaxKind.ModuleDeclaration: - const moduleExports = getSymbolOfNode(location as ModuleDeclaration).exports!; + const moduleExports = getSymbolOfNode(location as SourceFile | ModuleDeclaration).exports!; if (location.kind === SyntaxKind.SourceFile || isAmbientModule(location)) { // It's an external module. First see if the module has an export default and if the local @@ -1322,8 +1323,14 @@ namespace ts { } } + // ES6 exports are also visible locally (except for 'default'), but commonjs exports are not (except typedefs) if (name !== InternalSymbolName.Default && (result = lookup(moduleExports, name, meaning & SymbolFlags.ModuleMember))) { - break loop; + if (isSourceFile(location) && location.commonJsModuleIndicator && !result.declarations.some(isJSDocTypeAlias)) { + result = undefined; + } + else { + break loop; + } } break; case SyntaxKind.EnumDeclaration: @@ -2526,6 +2533,46 @@ namespace ts { return getMergedSymbol(symbol.parent && getLateBoundSymbol(symbol.parent)); } + /** + * Attempts to find the symbol corresponding to the container a symbol is in - usually this + * is just its' `.parent`, but for locals, this value is `undefined` + */ + function getContainerOfSymbol(symbol: Symbol): Symbol | undefined { + const container = getParentOfSymbol(symbol); + if (container) { + return container; + } + const candidate = forEach(symbol.declarations, d => !isAmbientModule(d) && d.parent && hasNonGlobalAugmentationExternalModuleSymbol(d.parent) ? getSymbolOfNode(d.parent) : undefined); + if (!candidate) { + return undefined; + } + const alias = getAliasForSymbolInContainer(candidate, symbol); + return alias ? candidate : undefined; + } + + function getAliasForSymbolInContainer(container: Symbol, symbol: Symbol) { + if (container === getParentOfSymbol(symbol)) { + // fast path, `symbol` is either already the alias or isn't aliased + return symbol; + } + const exports = getExportsOfSymbol(container); + const quick = exports.get(symbol.escapedName); + if (quick && symbolRefersToTarget(quick)) { + return quick; + } + return forEachEntry(exports, exported => { + if (symbolRefersToTarget(exported)) { + return exported; + } + }); + + function symbolRefersToTarget(s: Symbol) { + if (s === symbol || resolveSymbol(s) === symbol || resolveSymbol(s) === resolveSymbol(symbol)) { + return s; + } + } + } + function getExportSymbolOfValueSymbolIfExported(symbol: Symbol): Symbol; function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined; function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined { @@ -2831,7 +2878,7 @@ namespace ts { // But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible // It is accessible if the parent m is accessible because then m.c can be accessed through qualification meaningToLook = getQualifiedLeftMeaning(meaning); - symbol = getParentOfSymbol(symbol); + symbol = getContainerOfSymbol(symbol); } // This could be a symbol that is not exported in the external module @@ -3099,6 +3146,9 @@ namespace ts { if (type.flags & TypeFlags.Any) { return createKeywordTypeNode(SyntaxKind.AnyKeyword); } + if (type.flags & TypeFlags.Unknown) { + return createKeywordTypeNode(SyntaxKind.UnknownKeyword); + } if (type.flags & TypeFlags.String) { return createKeywordTypeNode(SyntaxKind.StringKeyword); } @@ -3719,12 +3769,12 @@ namespace ts { needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) { // Go up and add our parent. - const parent = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol); + const parent = getContainerOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol); if (parent) { const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false); if (parentChain) { parentSymbol = parent; - accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [symbol]); + accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]); } } } @@ -4377,8 +4427,8 @@ namespace ts { const pattern = declaration.parent; let parentType = getTypeForBindingElementParent(pattern.parent); // If parent has the unknown (error) type, then so does this binding element - if (parentType === unknownType) { - return unknownType; + if (parentType === errorType) { + return errorType; } // If no type was specified or inferred for parent, // infer from the initializer of the binding element if one is present. @@ -4393,9 +4443,9 @@ namespace ts { let type: Type | undefined; if (pattern.kind === SyntaxKind.ObjectBindingPattern) { if (declaration.dotDotDotToken) { - if (!isValidSpreadType(parentType)) { + if (parentType.flags & TypeFlags.Unknown || !isValidSpreadType(parentType)) { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); - return unknownType; + return errorType; } const literalMembers: PropertyName[] = []; for (const element of pattern.elements) { @@ -4453,7 +4503,7 @@ namespace ts { getIndexTypeOfType(parentType, IndexKind.String); if (!type) { error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name)); - return unknownType; + return errorType; } } } @@ -4479,7 +4529,7 @@ namespace ts { else { error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName); } - return unknownType; + return errorType; } } } @@ -4631,7 +4681,7 @@ namespace ts { undefined; if (!expression) { - return unknownType; + return errorType; } const special = getSpecialPropertyAssignmentKind(expression); @@ -4657,7 +4707,7 @@ namespace ts { if (!jsDocType) { jsDocType = declarationType; } - else if (jsDocType !== unknownType && declarationType !== unknownType && + else if (jsDocType !== errorType && declarationType !== errorType && !isTypeIdenticalTo(jsDocType, declarationType) && !(symbol.flags & SymbolFlags.JSContainer)) { errorNextVariableOrPropertyDeclarationMustHaveSameType(jsDocType, declaration, declarationType); @@ -4900,7 +4950,7 @@ namespace ts { } // Handle variable, parameter or property if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { - return unknownType; + return errorType; } let type: Type; @@ -4993,7 +5043,7 @@ namespace ts { } if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { - return unknownType; + return errorType; } let type: Type; @@ -5090,7 +5140,7 @@ namespace ts { // up recursively calling getTypeOfAlias, causing a stack overflow. links.type = targetSymbol.flags & SymbolFlags.Value ? getTypeOfSymbol(targetSymbol) - : unknownType; + : errorType; } return links.type; } @@ -5100,11 +5150,11 @@ namespace ts { if (!links.type) { if (symbolInstantiationDepth === 100) { error(symbol.valueDeclaration, Diagnostics.Generic_type_instantiation_is_excessively_deep_and_possibly_infinite); - links.type = unknownType; + links.type = errorType; } else { if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { - return unknownType; + return errorType; } symbolInstantiationDepth++; let type = instantiateType(getTypeOfSymbol(links.target!), links.mapper!); @@ -5123,7 +5173,7 @@ namespace ts { if (getEffectiveTypeAnnotationNode(symbol.valueDeclaration)) { error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); - return unknownType; + return errorType; } // Otherwise variable has initializer that circularly references the variable itself if (noImplicitAny) { @@ -5155,7 +5205,7 @@ namespace ts { if (symbol.flags & SymbolFlags.Alias) { return getTypeOfAlias(symbol); } - return unknownType; + return errorType; } function isReferenceToType(type: Type, target: Type) { @@ -5330,7 +5380,7 @@ namespace ts { return type.resolvedBaseConstructorType = undefinedType; } if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseConstructorType)) { - return unknownType; + return errorType; } const baseConstructorType = checkExpression(baseTypeNode.expression); if (extended && baseTypeNode !== extended) { @@ -5344,11 +5394,11 @@ namespace ts { } if (!popTypeResolution()) { error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, symbolToString(type.symbol)); - return type.resolvedBaseConstructorType = unknownType; + return type.resolvedBaseConstructorType = errorType; } if (!(baseConstructorType.flags & TypeFlags.Any) && baseConstructorType !== nullWideningType && !isConstructorType(baseConstructorType)) { error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, typeToString(baseConstructorType)); - return type.resolvedBaseConstructorType = unknownType; + return type.resolvedBaseConstructorType = errorType; } type.resolvedBaseConstructorType = baseConstructorType; } @@ -5407,7 +5457,7 @@ namespace ts { baseType = getReturnTypeOfSignature(constructors[0]); } - if (baseType === unknownType) { + if (baseType === errorType) { return type.resolvedBaseTypes = emptyArray; } if (!isValidBaseType(baseType)) { @@ -5454,7 +5504,7 @@ namespace ts { if (declaration.kind === SyntaxKind.InterfaceDeclaration && getInterfaceBaseTypeNodes(declaration)) { for (const node of getInterfaceBaseTypeNodes(declaration)!) { const baseType = getTypeFromTypeNode(node); - if (baseType !== unknownType) { + if (baseType !== errorType) { if (isValidBaseType(baseType)) { if (type !== baseType && !hasBaseType(baseType, type)) { if (type.resolvedBaseTypes === emptyArray) { @@ -5542,14 +5592,14 @@ namespace ts { // Note that we use the links object as the target here because the symbol object is used as the unique // identity for resolution of the 'type' property in SymbolLinks. if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) { - return unknownType; + return errorType; } const declaration = find(symbol.declarations, d => isJSDocTypeAlias(d) || d.kind === SyntaxKind.TypeAliasDeclaration); const typeNode = isJSDocTypeAlias(declaration) ? declaration.typeExpression : declaration.type; // If typeNode is missing, we will error in checkJSDocTypedefTag. - let type = typeNode ? getTypeFromTypeNode(typeNode) : unknownType; + let type = typeNode ? getTypeFromTypeNode(typeNode) : errorType; if (popTypeResolution()) { const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); @@ -5562,7 +5612,7 @@ namespace ts { } } else { - type = unknownType; + type = errorType; error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); } links.declaredType = type; @@ -5687,7 +5737,7 @@ namespace ts { } function getDeclaredTypeOfSymbol(symbol: Symbol): Type { - return tryGetDeclaredTypeOfSymbol(symbol) || unknownType; + return tryGetDeclaredTypeOfSymbol(symbol) || errorType; } function tryGetDeclaredTypeOfSymbol(symbol: Symbol): Type | undefined { @@ -5720,6 +5770,7 @@ namespace ts { function isThislessType(node: TypeNode): boolean { switch (node.kind) { case SyntaxKind.AnyKeyword: + case SyntaxKind.UnknownKeyword: case SyntaxKind.StringKeyword: case SyntaxKind.NumberKeyword: case SyntaxKind.BooleanKeyword: @@ -6486,14 +6537,14 @@ namespace ts { function getConstraintTypeFromMappedType(type: MappedType) { return type.constraintType || - (type.constraintType = instantiateType(getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)), type.mapper || identityMapper) || unknownType); + (type.constraintType = instantiateType(getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)), type.mapper || identityMapper) || errorType); } function getTemplateTypeFromMappedType(type: MappedType) { return type.templateType || (type.templateType = type.declaration.type ? instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), type.mapper || identityMapper) : - unknownType); + errorType); } function getConstraintDeclarationForMappedType(type: MappedType) { @@ -6666,7 +6717,7 @@ namespace ts { const objectType = getBaseConstraintOfType(type.objectType) || type.objectType; const indexType = getBaseConstraintOfType(type.indexType) || type.indexType; const constraint = !isGenericObjectType(objectType) && !isGenericIndexType(indexType) ? getIndexedAccessType(objectType, indexType) : undefined; - return constraint && constraint !== unknownType ? constraint : undefined; + return constraint && constraint !== errorType ? constraint : undefined; } function getDefaultConstraintOfConditionalType(type: ConditionalType) { @@ -6824,7 +6875,7 @@ namespace ts { const baseObjectType = getBaseConstraint((t).objectType); const baseIndexType = getBaseConstraint((t).indexType); const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType) : undefined; - return baseIndexedAccess && baseIndexedAccess !== unknownType ? getBaseConstraint(baseIndexedAccess) : undefined; + return baseIndexedAccess && baseIndexedAccess !== errorType ? getBaseConstraint(baseIndexedAccess) : undefined; } if (t.flags & TypeFlags.Conditional) { const constraint = getConstraintOfConditionalType(t); @@ -6918,7 +6969,7 @@ namespace ts { let checkFlags = 0; for (const current of containingType.types) { const type = getApparentType(current); - if (type !== unknownType) { + if (type !== errorType) { const prop = getPropertyOfType(type, name); const modifiers = prop ? getDeclarationModifierFlagsFromSymbol(prop) : 0; if (prop && !(modifiers & excludeModifiers)) { @@ -7456,7 +7507,7 @@ namespace ts { function getReturnTypeOfSignature(signature: Signature): Type { if (!signature.resolvedReturnType) { if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) { - return unknownType; + return errorType; } let type: Type; if (signature.target) { @@ -7759,7 +7810,7 @@ namespace ts { error(node, diag, typeStr, minTypeArgumentCount, typeParameters.length); if (!isJs) { // TODO: Adopt same permissive behavior in TS as in JS to reduce follow-on editing experience failures (requires editing fillMissingTypeArguments) - return unknownType; + return errorType; } } // In a type reference, the outer type parameters of the referenced class or interface are automatically @@ -7768,7 +7819,7 @@ namespace ts { const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJs)); return createTypeReference(type, typeArguments); } - return checkNoTypeArguments(node, symbol) ? type : unknownType; + return checkNoTypeArguments(node, symbol) ? type : errorType; } function getTypeAliasInstantiation(symbol: Symbol, typeArguments: Type[] | undefined): Type { @@ -7802,11 +7853,11 @@ namespace ts { symbolToString(symbol), minTypeArgumentCount, typeParameters.length); - return unknownType; + return errorType; } return getTypeAliasInstantiation(symbol, typeArguments); } - return checkNoTypeArguments(node, symbol) ? type : unknownType; + return checkNoTypeArguments(node, symbol) ? type : errorType; } function getTypeReferenceName(node: TypeReferenceType): EntityNameOrEntityNameExpression | undefined { @@ -7837,7 +7888,7 @@ namespace ts { function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type { const typeArguments = typeArgumentsFromTypeReferenceNode(node); // Do unconditionally so we mark type arguments as referenced. if (symbol === unknownSymbol) { - return unknownType; + return errorType; } const type = getTypeReferenceTypeWorker(node, symbol, typeArguments); @@ -7850,11 +7901,11 @@ namespace ts { if (res) { return checkNoTypeArguments(node, symbol) ? res.flags & TypeFlags.TypeParameter ? getConstrainedTypeVariable(res, node) : res : - unknownType; + errorType; } if (!(symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node))) { - return unknownType; + return errorType; } const jsdocType = getJSDocTypeReference(node, symbol, typeArguments); @@ -8293,7 +8344,7 @@ namespace ts { // easier to reason about their origin. if (!(flags & TypeFlags.Never || flags & TypeFlags.Intersection && isEmptyIntersectionType(type))) { includes |= flags & ~TypeFlags.ConstructionFlags; - if (flags & TypeFlags.Any) { + if (flags & TypeFlags.AnyOrUnknown) { if (type === wildcardType) includes |= TypeFlags.Wildcard; } else if (!strictNullChecks && flags & TypeFlags.Nullable) { @@ -8404,8 +8455,8 @@ namespace ts { } const typeSet: Type[] = []; const includes = addTypesToUnion(typeSet, 0, types); - if (includes & TypeFlags.Any) { - return includes & TypeFlags.Wildcard ? wildcardType : anyType; + if (includes & TypeFlags.AnyOrUnknown) { + return includes & TypeFlags.Any ? includes & TypeFlags.Wildcard ? wildcardType : anyType : unknownType; } switch (unionReduction) { case UnionReduction.Literal: @@ -8508,7 +8559,7 @@ namespace ts { } else { includes |= flags & ~TypeFlags.ConstructionFlags; - if (flags & TypeFlags.Any) { + if (flags & TypeFlags.AnyOrUnknown) { if (type === wildcardType) includes |= TypeFlags.Wildcard; } else if ((strictNullChecks || !(flags & TypeFlags.Nullable)) && !contains(typeSet, type) && @@ -8579,9 +8630,6 @@ namespace ts { // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution // for intersections of types with signatures can be deterministic. function getIntersectionType(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { - if (types.length === 0) { - return emptyObjectType; - } const typeSet: Type[] = []; const includes = addTypesToIntersection(typeSet, 0, types); if (includes & TypeFlags.Never) { @@ -8590,6 +8638,9 @@ namespace ts { if (includes & TypeFlags.Any) { return includes & TypeFlags.Wildcard ? wildcardType : anyType; } + if (!strictNullChecks && includes & TypeFlags.Nullable) { + return includes & TypeFlags.Undefined ? undefinedType : nullType; + } if (includes & TypeFlags.String && includes & TypeFlags.StringLiteral || includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral || includes & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol) { @@ -8598,6 +8649,9 @@ namespace ts { if (includes & TypeFlags.EmptyObject && !(includes & TypeFlags.Object)) { typeSet.push(emptyObjectType); } + if (typeSet.length === 0) { + return unknownType; + } if (typeSet.length === 1) { return typeSet[0]; } @@ -8712,7 +8766,7 @@ namespace ts { case SyntaxKind.UniqueKeyword: links.resolvedType = node.type.kind === SyntaxKind.SymbolKeyword ? getESSymbolLikeTypeForNode(walkUpParenthesizedTypes(node.parent)) - : unknownType; + : errorType; break; } } @@ -8739,7 +8793,7 @@ namespace ts { markPropertyAsReferenced(prop, accessExpression, /*isThisAccess*/ accessExpression.expression.kind === SyntaxKind.ThisKeyword); if (isAssignmentTarget(accessExpression) && (isReferenceToReadonlyEntity(accessExpression, prop) || isReferenceThroughNamespaceImport(accessExpression))) { error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, symbolToString(prop)); - return unknownType; + return errorType; } if (cacheSymbol) { getNodeLinks(accessNode!).resolvedSymbol = prop; @@ -8792,7 +8846,7 @@ namespace ts { error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType)); } } - return unknownType; + return errorType; } function isGenericObjectType(type: Type): boolean { @@ -8893,7 +8947,7 @@ namespace ts { // an expression. This is to preserve backwards compatibility. For example, an element access 'this["foo"]' // has always been resolved eagerly using the constraint type of 'this' at the given location. if (isGenericIndexType(indexType) || !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) && isGenericObjectType(objectType)) { - if (objectType.flags & TypeFlags.Any) { + if (objectType.flags & TypeFlags.AnyOrUnknown) { return objectType; } // Defer the operation by creating an indexed access type. @@ -8912,8 +8966,8 @@ namespace ts { const propTypes: Type[] = []; for (const t of (indexType).types) { const propType = getPropertyTypeForIndexType(apparentObjectType, t, accessNode, /*cacheSymbol*/ false); - if (propType === unknownType) { - return unknownType; + if (propType === errorType) { + return errorType; } propTypes.push(propType); } @@ -8977,6 +9031,9 @@ namespace ts { combinedMapper = combineTypeMappers(mapper, context); } if (!isDeferred) { + if (extendsType.flags & TypeFlags.AnyOrUnknown) { + return instantiateType(root.trueType, mapper); + } // Return union of trueType and falseType for 'any' since it matches anything if (checkType.flags & TypeFlags.Any) { return getUnionType([instantiateType(root.trueType, combinedMapper || mapper), instantiateType(root.falseType, mapper)]); @@ -9099,12 +9156,12 @@ namespace ts { if (node.isTypeOf && node.typeArguments) { // Only the non-typeof form can make use of type arguments error(node, Diagnostics.Type_arguments_cannot_be_used_here); links.resolvedSymbol = unknownSymbol; - return links.resolvedType = unknownType; + return links.resolvedType = errorType; } if (!isLiteralImportTypeNode(node)) { error(node.argument, Diagnostics.String_literal_expected); links.resolvedSymbol = unknownSymbol; - return links.resolvedType = unknownType; + return links.resolvedType = errorType; } const argumentType = getTypeFromTypeNode(node.argument); const targetMeaning = node.isTypeOf ? SymbolFlags.Value : SymbolFlags.Type; @@ -9113,7 +9170,7 @@ namespace ts { const innerModuleSymbol = resolveExternalModule(node, moduleName, Diagnostics.Cannot_find_module_0, node, /*isForAugmentation*/ false); if (!innerModuleSymbol) { links.resolvedSymbol = unknownSymbol; - return links.resolvedType = unknownType; + return links.resolvedType = errorType; } const moduleSymbol = resolveExternalModuleSymbol(innerModuleSymbol, /*dontResolveAlias*/ false); if (!nodeIsMissing(node.qualifier)) { @@ -9125,7 +9182,7 @@ namespace ts { const next = getSymbol(getExportsOfSymbol(getMergedSymbol(resolveSymbol(currentNamespace))), current.escapedText, meaning); if (!next) { error(current, Diagnostics.Namespace_0_has_no_exported_member_1, getFullyQualifiedName(currentNamespace), declarationNameToString(current)); - return links.resolvedType = unknownType; + return links.resolvedType = errorType; } getNodeLinks(current).resolvedSymbol = next; getNodeLinks(current.parent).resolvedSymbol = next; @@ -9140,7 +9197,7 @@ namespace ts { else { error(node, targetMeaning === SymbolFlags.Value ? Diagnostics.Module_0_does_not_refer_to_a_value_but_is_used_as_a_value_here : Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here, moduleName); links.resolvedSymbol = unknownSymbol; - links.resolvedType = unknownType; + links.resolvedType = errorType; } } } @@ -9195,6 +9252,9 @@ namespace ts { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } + if (left.flags & TypeFlags.Unknown || right.flags & TypeFlags.Unknown) { + return unknownType; + } if (left.flags & TypeFlags.Never) { return right; } @@ -9371,7 +9431,7 @@ namespace ts { } } error(node, Diagnostics.A_this_type_is_available_only_in_a_non_static_member_of_a_class_or_interface); - return unknownType; + return errorType; } function getTypeFromThisTypeNode(node: ThisExpression | ThisTypeNode): Type { @@ -9388,6 +9448,8 @@ namespace ts { case SyntaxKind.JSDocAllType: case SyntaxKind.JSDocUnknownType: return anyType; + case SyntaxKind.UnknownKeyword: + return unknownType; case SyntaxKind.StringKeyword: return stringType; case SyntaxKind.NumberKeyword: @@ -9463,7 +9525,7 @@ namespace ts { const symbol = getSymbolAtLocation(node); return (symbol && getDeclaredTypeOfSymbol(symbol))!; // TODO: GH#18217 default: - return unknownType; + return errorType; } } @@ -9756,7 +9818,7 @@ namespace ts { } function isMappableType(type: Type) { - return type.flags & (TypeFlags.Any | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection); + return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection); } function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper): AnonymousType { @@ -9855,7 +9917,7 @@ namespace ts { } function getWildcardInstantiation(type: Type) { - return type.flags & (TypeFlags.Primitive | TypeFlags.Any | TypeFlags.Never) ? type : + return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type : type.wildcardInstantiation || (type.wildcardInstantiation = instantiateType(type, wildcardMapper)); } @@ -10269,7 +10331,7 @@ namespace ts { function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map, errorReporter?: ErrorReporter) { const s = source.flags; const t = target.flags; - if (t & TypeFlags.Any || s & TypeFlags.Never || source === wildcardType) return true; + if (t & TypeFlags.AnyOrUnknown || s & TypeFlags.Never || source === wildcardType) return true; if (t & TypeFlags.Never) return false; if (s & TypeFlags.StringLike && t & TypeFlags.String) return true; if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral && @@ -10592,6 +10654,16 @@ namespace ts { else if (source.symbol && source.flags & TypeFlags.Object && globalObjectType === source) { reportError(Diagnostics.The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead); } + else if (getObjectFlags(source) & ObjectFlags.JsxAttributes && target.flags & TypeFlags.Intersection) { + const targetTypes = (target as IntersectionType).types; + const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, errorNode); + const intrinsicClassAttributes = getJsxType(JsxNames.IntrinsicClassAttributes, errorNode); + if (intrinsicAttributes !== errorType && intrinsicClassAttributes !== errorType && + (contains(targetTypes, intrinsicAttributes) || contains(targetTypes, intrinsicClassAttributes))) { + // do not report top error + return result; + } + } reportRelationError(headMessage, source, target); } return result; @@ -10995,7 +11067,7 @@ namespace ts { } } const constraint = getConstraintForRelation(source); - if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) { + if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.AnyOrUnknown)) { // A type variable with no constraint is not related to the non-primitive object type. if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) { errorInfo = saveErrorInfo; @@ -11438,7 +11510,7 @@ namespace ts { return indexTypesIdenticalTo(source, target, kind); } const targetInfo = getIndexInfoOfType(target, kind); - if (!targetInfo || targetInfo.type.flags & TypeFlags.Any && !sourceIsPrimitive) { + if (!targetInfo || targetInfo.type.flags & TypeFlags.AnyOrUnknown && !sourceIsPrimitive) { // Index signature of type any permits assignment from everything but primitives return Ternary.True; } @@ -13216,17 +13288,17 @@ namespace ts { return getConstraintForLocation(getTypeOfPropertyOfType(type, text), name) || isNumericLiteralName(text) && getIndexTypeOfType(type, IndexKind.Number) || getIndexTypeOfType(type, IndexKind.String) || - unknownType; + errorType; } function getTypeOfDestructuredArrayElement(type: Type, index: number) { return isTupleLikeType(type) && getTypeOfPropertyOfType(type, "" + index as __String) || checkIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) || - unknownType; + errorType; } function getTypeOfDestructuredSpreadExpression(type: Type) { - return createArrayType(checkIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) || unknownType); + return createArrayType(checkIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) || errorType); } function getAssignedTypeOfBinaryExpression(node: BinaryExpression): Type { @@ -13265,7 +13337,7 @@ namespace ts { case SyntaxKind.ForInStatement: return stringType; case SyntaxKind.ForOfStatement: - return checkRightHandSideOfForOf((parent).expression, (parent).awaitModifier) || unknownType; + return checkRightHandSideOfForOf((parent).expression, (parent).awaitModifier) || errorType; case SyntaxKind.BinaryExpression: return getAssignedTypeOfBinaryExpression(parent); case SyntaxKind.DeleteExpression: @@ -13279,7 +13351,7 @@ namespace ts { case SyntaxKind.ShorthandPropertyAssignment: return getAssignedTypeOfShorthandPropertyAssignment(parent); } - return unknownType; + return errorType; } function getInitialTypeOfBindingElement(node: BindingElement): Type { @@ -13309,9 +13381,9 @@ namespace ts { return stringType; } if (node.parent.parent.kind === SyntaxKind.ForOfStatement) { - return checkRightHandSideOfForOf(node.parent.parent.expression, node.parent.parent.awaitModifier) || unknownType; + return checkRightHandSideOfForOf(node.parent.parent.expression, node.parent.parent.awaitModifier) || errorType; } - return unknownType; + return errorType; } function getInitialType(node: VariableDeclaration | BindingElement) { @@ -13568,7 +13640,7 @@ namespace ts { const funcType = checkNonNullExpression(node.expression); if (funcType !== silentNeverType) { const apparentType = getApparentType(funcType); - return apparentType !== unknownType && some(getSignaturesOfType(apparentType, SignatureKind.Call), signatureHasTypePredicate); + return apparentType !== errorType && some(getSignaturesOfType(apparentType, SignatureKind.Call), signatureHasTypePredicate); } } return false; @@ -13585,7 +13657,7 @@ namespace ts { let key: string | undefined; let flowDepth = 0; if (flowAnalysisDisabled) { - return unknownType; + return errorType; } if (!reference.flowNode || !couldBeUninitialized && !(declaredType.flags & TypeFlags.Narrowable)) { return declaredType; @@ -13609,7 +13681,7 @@ namespace ts { // and disable further control flow analysis in the containing function or module body. flowAnalysisDisabled = true; reportFlowControlError(reference); - return unknownType; + return errorType; } flowDepth++; while (true) { @@ -14341,7 +14413,7 @@ namespace ts { function checkIdentifier(node: Identifier): Type { const symbol = getResolvedSymbol(node); if (symbol === unknownSymbol) { - return unknownType; + return errorType; } // As noted in ECMAScript 6 language spec, arrow functions never have an arguments objects. @@ -14419,11 +14491,11 @@ namespace ts { if (!(localOrExportSymbol.flags & SymbolFlags.Variable) && !(isInJavaScriptFile(node) && localOrExportSymbol.flags & SymbolFlags.ValueModule)) { error(node, Diagnostics.Cannot_assign_to_0_because_it_is_not_a_variable, symbolToString(symbol)); - return unknownType; + return errorType; } if (isReadonlySymbol(localOrExportSymbol)) { error(node, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, symbolToString(symbol)); - return unknownType; + return errorType; } } @@ -14467,7 +14539,7 @@ namespace ts { // the entire control flow graph from the variable's declaration (i.e. when the flow container and // declaration container are the same). const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAsignmentTarget || - type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || + type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.AnyOrUnknown) !== 0 || isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || node.parent.kind === SyntaxKind.NonNullExpression || declaration.kind === SyntaxKind.VariableDeclaration && (declaration).exclamationToken || @@ -14740,7 +14812,7 @@ namespace ts { if (isInJavaScriptFile(node)) { const type = getTypeForThisExpressionFromJSDoc(container); - if (type && type !== unknownType) { + if (type && type !== errorType) { return getFlowTypeOfReference(node, type); } } @@ -14798,7 +14870,7 @@ namespace ts { else { error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class); } - return unknownType; + return errorType; } if (!isCallExpression && container.kind === SyntaxKind.Constructor) { @@ -14889,7 +14961,7 @@ namespace ts { if (container.parent.kind === SyntaxKind.ObjectLiteralExpression) { if (languageVersion < ScriptTarget.ES2015) { error(node, Diagnostics.super_is_only_allowed_in_members_of_object_literal_expressions_when_option_target_is_ES2015_or_higher); - return unknownType; + return errorType; } else { // for object literal assume that type of 'super' is 'any' @@ -14901,19 +14973,19 @@ namespace ts { const classLikeDeclaration = container.parent; if (!getClassExtendsHeritageClauseElement(classLikeDeclaration)) { error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class); - return unknownType; + return errorType; } const classType = getDeclaredTypeOfSymbol(getSymbolOfNode(classLikeDeclaration)); const baseClassType = classType && getBaseTypes(classType)[0]; if (!baseClassType) { - return unknownType; + return errorType; } if (container.kind === SyntaxKind.Constructor && isInConstructorArgumentInitializer(node, container)) { // issue custom error message for super property access in constructor arguments (to be aligned with old compiler) error(node, Diagnostics.super_cannot_be_referenced_in_constructor_arguments); - return unknownType; + return errorType; } return nodeCheckFlag === NodeCheckFlags.SuperStatic @@ -15517,7 +15589,7 @@ namespace ts { // var CustomTag: "h1" = "h1"; // Hello World const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, context); - if (intrinsicElementsType !== unknownType) { + if (intrinsicElementsType !== errorType) { const stringLiteralTypeName = (valueType).value; const intrinsicProp = getPropertyOfType(intrinsicElementsType, escapeLeadingUnderscores(stringLiteralTypeName)); if (intrinsicProp) { @@ -15540,7 +15612,7 @@ namespace ts { ctor = false; if (signatures.length === 0) { // We found no signatures at all, which is an error - return unknownType; + return errorType; } } @@ -15564,7 +15636,7 @@ namespace ts { function getJsxPropsTypeFromCallSignature(sig: Signature, context: Node) { let propsType = getTypeOfFirstParameterOfSignatureWithFallback(sig, emptyObjectType); const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context); - if (intrinsicAttribs !== unknownType) { + if (intrinsicAttribs !== errorType) { propsType = intersectTypes(intrinsicAttribs, propsType); } return propsType; @@ -15601,7 +15673,7 @@ namespace ts { // Normal case -- add in IntrinsicClassElements and IntrinsicElements let apparentAttributesType = attributesType; const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes, context); - if (intrinsicClassAttribs !== unknownType) { + if (intrinsicClassAttribs !== errorType) { const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol); const hostClassType = getReturnTypeOfSignature(sig); apparentAttributesType = intersectTypes( @@ -15613,7 +15685,7 @@ namespace ts { } const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context); - if (intrinsicAttribs !== unknownType) { + if (intrinsicAttribs !== errorType) { apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType); } @@ -15991,7 +16063,7 @@ namespace ts { const type = checkExpression(memberDecl.expression); if (!isValidSpreadType(type)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); - return unknownType; + return errorType; } spread = getSpreadType(spread, type, node.symbol, propagatedFlags, /*objectFlags*/ 0); offset = i + 1; @@ -16071,7 +16143,7 @@ namespace ts { } function isValidSpreadType(type: Type): boolean { - return !!(type.flags & (TypeFlags.Any | TypeFlags.NonPrimitive) || + return !!(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.NonPrimitive) || getFalsyFlags(type) & TypeFlags.DefinitelyFalsy && isValidSpreadType(removeDefinitelyFalsyTypes(type)) || type.flags & TypeFlags.Object && !isGenericMappedType(type) || type.flags & TypeFlags.UnionOrIntersection && !forEach((type).types, t => !isValidSpreadType(t))); @@ -16274,11 +16346,11 @@ namespace ts { return createJsxAttributesTypeFromAttributesProperty(node.parent, checkMode); } - function getJsxType(name: __String, location: Node) { + function getJsxType(name: __String, location: Node | undefined) { const namespace = getJsxNamespaceAt(location); const exports = namespace && getExportsOfSymbol(namespace); const typeSymbol = exports && getSymbol(exports, name, SymbolFlags.Type); - return typeSymbol ? getDeclaredTypeOfSymbol(typeSymbol) : unknownType; + return typeSymbol ? getDeclaredTypeOfSymbol(typeSymbol) : errorType; } /** @@ -16291,7 +16363,7 @@ namespace ts { const links = getNodeLinks(node); if (!links.resolvedSymbol) { const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, node); - if (intrinsicElementsType !== unknownType) { + if (intrinsicElementsType !== errorType) { // Property case if (!isIdentifier(node.tagName)) return Debug.fail(); const intrinsicProp = getPropertyOfType(intrinsicElementsType, node.tagName.escapedText); @@ -16372,7 +16444,7 @@ namespace ts { return getSignatureInstantiation(signature, args, isJavascript); } - function getJsxNamespaceAt(location: Node): Symbol { + function getJsxNamespaceAt(location: Node | undefined): Symbol { const namespaceName = getJsxNamespace(location); const resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false); if (resolvedNamespace) { @@ -16468,7 +16540,7 @@ namespace ts { if (callReturnType && isTypeAssignableTo(callReturnType, jsxStatelessElementType)) { // Intersect in JSX.IntrinsicAttributes if it exists const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, openingLikeElement); - if (intrinsicAttributes !== unknownType) { + if (intrinsicAttributes !== errorType) { paramType = intersectTypes(intrinsicAttributes, paramType); } return paramType; @@ -16528,7 +16600,7 @@ namespace ts { } // Intersect in JSX.IntrinsicAttributes if it exists const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, openingLikeElement); - if (intrinsicAttributes !== unknownType) { + if (intrinsicAttributes !== errorType) { result = intersectTypes(intrinsicAttributes, result); } return result; @@ -16615,7 +16687,7 @@ namespace ts { // var CustomTag: "h1" = "h1"; // Hello World const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, openingLikeElement); - if (intrinsicElementsType !== unknownType) { + if (intrinsicElementsType !== errorType) { const stringLiteralTypeName = (elementType).value; const intrinsicProp = getPropertyOfType(intrinsicElementsType, escapeLeadingUnderscores(stringLiteralTypeName)); if (intrinsicProp) { @@ -16635,7 +16707,7 @@ namespace ts { const instantiatedSignatures = getInstantiatedJsxSignatures(openingLikeElement, elementType, /*reportErrors*/ true); if (!length(instantiatedSignatures)) { - return unknownType; + return errorType; } const elemInstanceType = getUnionType(instantiatedSignatures!.map(getReturnTypeOfSignature), UnionReduction.Subtype); @@ -16675,7 +16747,7 @@ namespace ts { return links.resolvedJsxElementAttributesType = getIndexInfoOfSymbol(symbol, IndexKind.String)!.type; } else { - return links.resolvedJsxElementAttributesType = unknownType; + return links.resolvedJsxElementAttributesType = errorType; } } return links.resolvedJsxElementAttributesType; @@ -16734,7 +16806,7 @@ namespace ts { function getJsxElementClassTypeAt(location: Node): Type | undefined { const type = getJsxType(JsxNames.ElementClass, location); - if (type === unknownType) return undefined; + if (type === errorType) return undefined; return type; } @@ -16915,7 +16987,7 @@ namespace ts { return type; } else { - return unknownType; + return errorType; } } @@ -17078,6 +17150,10 @@ namespace ts { undefinedDiagnostic?: DiagnosticMessage, nullOrUndefinedDiagnostic?: DiagnosticMessage ): Type { + if (type.flags & TypeFlags.Unknown) { + error(node, Diagnostics.Object_is_of_type_unknown); + return errorType; + } const kind = (strictNullChecks ? getFalsyFlags(type) : type.flags) & TypeFlags.Nullable; if (kind) { error(node, kind & TypeFlags.Undefined ? kind & TypeFlags.Null ? @@ -17086,7 +17162,7 @@ namespace ts { (nullDiagnostic || Diagnostics.Object_is_possibly_null) ); const t = getNonNullableType(type); - return t.flags & (TypeFlags.Nullable | TypeFlags.Never) ? unknownType : t; + return t.flags & (TypeFlags.Nullable | TypeFlags.Never) ? errorType : t; } return type; } @@ -17121,7 +17197,7 @@ namespace ts { if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) { reportNonexistentProperty(right, leftType.flags & TypeFlags.TypeParameter && (leftType as TypeParameter).isThisType ? apparentType : leftType); } - return unknownType; + return errorType; } if (indexInfo.isReadonly && (isAssignmentTarget(node) || isDeleteTarget(node))) { error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType)); @@ -17136,7 +17212,7 @@ namespace ts { if (assignmentKind) { if (isReferenceToReadonlyEntity(node, prop) || isReferenceThroughNamespaceImport(node)) { error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, idText(right)); - return unknownType; + return errorType; } } propType = getConstraintForLocation(getTypeOfSymbol(prop), node); @@ -17418,7 +17494,7 @@ namespace ts { && (!(property.flags & SymbolFlags.Method) || isValidMethodAccess(property, type)); } function isValidMethodAccess(method: Symbol, actualThisType: Type): boolean { - const propType = getTypeOfFuncClassEnumModule(method); + const propType = getTypeOfPropertyOfType(actualThisType, method.escapedName)!; const signatures = getSignaturesOfType(getNonNullableType(propType), SignatureKind.Call); Debug.assert(signatures.length !== 0); return signatures.some(sig => { @@ -17441,7 +17517,7 @@ namespace ts { propertyName: __String, type: Type): boolean { - if (type === unknownType || isTypeAny(type)) { + if (type === errorType || isTypeAny(type)) { return true; } const prop = getPropertyOfType(type, propertyName); @@ -17516,25 +17592,25 @@ namespace ts { const end = node.end; grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.Expression_expected); } - return unknownType; + return errorType; } const indexType = isForInVariableForNumericPropertyNames(indexExpression) ? numberType : checkExpression(indexExpression); - if (objectType === unknownType || objectType === silentNeverType) { + if (objectType === errorType || objectType === silentNeverType) { return objectType; } if (isConstEnumObjectType(objectType) && indexExpression.kind !== SyntaxKind.StringLiteral) { error(indexExpression, Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal); - return unknownType; + return errorType; } return checkIndexedAccessIndexType(getIndexedAccessType(objectType, indexType, node), node); } function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean { - if (expressionType === unknownType) { + if (expressionType === errorType) { // There is already an error, so no need to report one. return false; } @@ -17682,7 +17758,7 @@ namespace ts { // Even if the call is incomplete, we'll have a missing expression as our last argument, // so we can say the count is just the arg list length argCount = args.length; - typeArguments = undefined; + typeArguments = node.typeArguments; if (node.template.kind === SyntaxKind.TemplateExpression) { // If a tagged template expression lacks a tail literal, the call is incomplete. @@ -18133,7 +18209,7 @@ namespace ts { } Debug.fail("Unsupported decorator target."); - return unknownType; + return errorType; } /** @@ -18155,7 +18231,7 @@ namespace ts { // The second argument to a decorator is its `propertyKey` if (node.kind === SyntaxKind.ClassDeclaration) { Debug.fail("Class decorators should not have a second synthetic argument."); - return unknownType; + return errorType; } if (node.kind === SyntaxKind.Parameter) { @@ -18197,12 +18273,12 @@ namespace ts { default: Debug.fail("Unsupported property name."); - return unknownType; + return errorType; } } Debug.fail("Unsupported decorator target."); - return unknownType; + return errorType; } /** @@ -18217,7 +18293,7 @@ namespace ts { // or its `parameterIndex` for a parameter decorator if (node.kind === SyntaxKind.ClassDeclaration) { Debug.fail("Class decorators should not have a third synthetic argument."); - return unknownType; + return errorType; } if (node.kind === SyntaxKind.Parameter) { @@ -18227,7 +18303,7 @@ namespace ts { if (node.kind === SyntaxKind.PropertyDeclaration) { Debug.fail("Property decorators should not have a third synthetic argument."); - return unknownType; + return errorType; } if (node.kind === SyntaxKind.MethodDeclaration || @@ -18240,7 +18316,7 @@ namespace ts { } Debug.fail("Unsupported decorator target."); - return unknownType; + return errorType; } /** @@ -18258,7 +18334,7 @@ namespace ts { } Debug.fail("Decorators should not have a fourth synthetic argument."); - return unknownType; + return errorType; } /** @@ -18602,7 +18678,7 @@ namespace ts { if (isTypeAny(superType)) { return anySignature; } - if (superType !== unknownType) { + if (superType !== errorType) { // In super call, the candidate signatures are the matching arity signatures of the base constructor function instantiated // with the type arguments specified in the extends clause. const baseTypeNode = getClassExtendsHeritageClauseElement(getContainingClass(node)!); @@ -18626,7 +18702,7 @@ namespace ts { } const apparentType = getApparentType(funcType); - if (apparentType === unknownType) { + if (apparentType === errorType) { // Another error has already been reported return resolveErrorCall(node); } @@ -18644,7 +18720,7 @@ namespace ts { if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, constructSignatures.length)) { // The unknownType indicates that an error already occurred (and was reported). No // need to report another error in this case. - if (funcType !== unknownType && node.typeArguments) { + if (funcType !== errorType && node.typeArguments) { error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); } return resolveUntypedCall(node); @@ -18694,7 +18770,7 @@ namespace ts { // signatures for overload resolution. The result type of the function call becomes // the result type of the operation. expressionType = getApparentType(expressionType); - if (expressionType === unknownType) { + if (expressionType === errorType) { // Another error has already been reported return resolveErrorCall(node); } @@ -18820,7 +18896,7 @@ namespace ts { const tagType = checkExpression(node.tag); const apparentType = getApparentType(tagType); - if (apparentType === unknownType) { + if (apparentType === errorType) { // Another error has already been reported return resolveErrorCall(node); } @@ -18871,7 +18947,7 @@ namespace ts { function resolveDecorator(node: Decorator, candidatesOutArray: Signature[] | undefined): Signature { const funcType = checkExpression(node.expression); const apparentType = getApparentType(funcType); - if (apparentType === unknownType) { + if (apparentType === errorType) { return resolveErrorCall(node); } @@ -19173,7 +19249,7 @@ namespace ts { } function getTypeWithSyntheticDefaultImportType(type: Type, symbol: Symbol, originalSymbol: Symbol): Type { - if (allowSyntheticDefaultImports && type && type !== unknownType) { + if (allowSyntheticDefaultImports && type && type !== errorType) { const synthType = type as SyntheticDefaultModuleType; if (!synthType.syntheticType) { const file = find(originalSymbol.declarations, isSourceFile); @@ -19244,7 +19320,7 @@ namespace ts { checkSourceElement(type); const targetType = getTypeFromTypeNode(type); - if (produceDiagnostics && targetType !== unknownType) { + if (produceDiagnostics && targetType !== errorType) { const widenedType = getWidenedType(exprType); if (!isTypeComparableTo(targetType, widenedType)) { checkTypeComparableTo(exprType, targetType, errNode, Diagnostics.Type_0_cannot_be_converted_to_type_1); @@ -19275,7 +19351,7 @@ namespace ts { const container = getNewTargetContainer(node); if (!container) { error(node, Diagnostics.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, "new.target"); - return unknownType; + return errorType; } else if (container.kind === SyntaxKind.Constructor) { const symbol = getSymbolOfNode(container.parent as ClassLikeDeclaration); @@ -19294,7 +19370,7 @@ namespace ts { const file = getSourceFileOfNode(node); Debug.assert(!!(file.flags & NodeFlags.PossiblyContainsImportMeta), "Containing file is missing import meta node flag."); Debug.assert(!!file.externalModuleIndicator, "Containing file should be a module."); - return node.name.escapedText === "meta" ? getGlobalImportMetaType() : unknownType; + return node.name.escapedText === "meta" ? getGlobalImportMetaType() : errorType; } function getTypeOfParameter(symbol: Symbol) { @@ -19413,7 +19489,7 @@ namespace ts { error(func, isImportCall(func) ? Diagnostics.A_dynamic_import_call_returns_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option : Diagnostics.An_async_function_or_method_must_return_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option); - return unknownType; + return errorType; } else if (!getGlobalPromiseConstructorSymbol(/*reportErrors*/ true)) { error(func, isImportCall(func) ? @@ -19426,7 +19502,7 @@ namespace ts { function getReturnTypeFromBody(func: FunctionLikeDeclaration, checkMode?: CheckMode): Type { if (!func.body) { - return unknownType; + return errorType; } const functionFlags = getFunctionFlags(func); @@ -19624,7 +19700,7 @@ namespace ts { } // Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions. - if (returnType && maybeTypeOfKind(returnType, TypeFlags.Any | TypeFlags.Void)) { + if (returnType && maybeTypeOfKind(returnType, TypeFlags.AnyOrUnknown | TypeFlags.Void)) { return; } @@ -19912,7 +19988,7 @@ namespace ts { } return numberType; } - return unknownType; + return errorType; } function checkPostfixUnaryExpression(node: PostfixUnaryExpression): Type { @@ -19934,7 +20010,7 @@ namespace ts { // Return true if type might be of the given kind. A union or intersection type might be of a given // kind if at least one constituent type is of the given kind. function maybeTypeOfKind(type: Type, kind: TypeFlags): boolean { - if (type.flags & kind || kind & TypeFlags.GenericMappedType && isGenericMappedType(type)) { + if (type.flags & kind & ~TypeFlags.GenericMappedType || kind & TypeFlags.GenericMappedType && isGenericMappedType(type)) { return true; } if (type.flags & TypeFlags.UnionOrIntersection) { @@ -19952,7 +20028,7 @@ namespace ts { if (source.flags & kind) { return true; } - if (strict && source.flags & (TypeFlags.Any | TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null)) { + if (strict && source.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null)) { return false; } return !!(kind & TypeFlags.NumberLike) && isTypeAssignableTo(source, numberType) || @@ -20089,7 +20165,7 @@ namespace ts { // This elementType will be used if the specific property corresponding to this index is not // present (aka the tuple element property). This call also checks that the parentType is in // fact an iterable or array (depending on target language). - const elementType = checkIteratedTypeOrElementType(sourceType, node, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) || unknownType; + const elementType = checkIteratedTypeOrElementType(sourceType, node, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) || errorType; for (let i = 0; i < elements.length; i++) { checkArrayLiteralDestructuringElementAssignment(node, sourceType, i, elementType, checkMode); } @@ -20340,7 +20416,7 @@ namespace ts { else if (isTypeAny(leftType) || isTypeAny(rightType)) { // Otherwise, the result is of type Any. // NOTE: unknown type here denotes error type. Old compiler treated this case as any type so do we. - resultType = leftType === unknownType || rightType === unknownType ? unknownType : anyType; + resultType = leftType === errorType || rightType === errorType ? errorType : anyType; } // Symbols are not allowed at all in arithmetic expressions @@ -20418,7 +20494,7 @@ namespace ts { if (propType.symbol && propType.symbol.flags & SymbolFlags.Class) { const name = prop.escapedName; const symbol = resolveName(prop.valueDeclaration, name, SymbolFlags.Type, undefined, name, /*isUse*/ false); - if (symbol) { + if (symbol && symbol.declarations.some(d => d.kind === SyntaxKind.JSDocTypedefTag)) { grammarErrorOnNode(symbol.declarations[0], Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name)); return grammarErrorOnNode(prop.valueDeclaration, Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name)); } @@ -20888,7 +20964,7 @@ namespace ts { case SyntaxKind.JsxOpeningElement: Debug.fail("Shouldn't ever directly check a JsxOpeningElement"); } - return unknownType; + return errorType; } // DECLARATION AND STATEMENT TYPE CHECKING @@ -21501,7 +21577,7 @@ namespace ts { function getTypeParametersForTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments) { const type = getTypeFromTypeReference(node); - if (type !== unknownType) { + if (type !== errorType) { const symbol = getNodeLinks(node).resolvedSymbol; if (symbol) { return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters || @@ -21517,7 +21593,7 @@ namespace ts { grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments); } const type = getTypeFromTypeReference(node); - if (type !== unknownType) { + if (type !== errorType) { if (node.typeArguments) { // Do type argument local checks only if referenced type is successfully resolved forEach(node.typeArguments, checkSourceElement); @@ -22057,7 +22133,7 @@ namespace ts { * The runtime behavior of the `await` keyword. */ function checkAwaitedType(type: Type, errorNode: Node, diagnosticMessage: DiagnosticMessage): Type { - return getAwaitedType(type, errorNode, diagnosticMessage) || unknownType; + return getAwaitedType(type, errorNode, diagnosticMessage) || errorType; } function getAwaitedType(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage): Type | undefined { @@ -22206,41 +22282,41 @@ namespace ts { const returnType = getTypeFromTypeNode(returnTypeNode); if (languageVersion >= ScriptTarget.ES2015) { - if (returnType === unknownType) { - return unknownType; + if (returnType === errorType) { + return errorType; } const globalPromiseType = getGlobalPromiseType(/*reportErrors*/ true); 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(returnTypeNode, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type); - return unknownType; + return errorType; } } else { // Always mark the type node as referenced if it points to a value markTypeNodeAsReferenced(returnTypeNode); - if (returnType === unknownType) { - return unknownType; + if (returnType === errorType) { + return errorType; } const promiseConstructorName = getEntityNameFromTypeNode(returnTypeNode); if (promiseConstructorName === undefined) { 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; + return errorType; } const promiseConstructorSymbol = resolveEntityName(promiseConstructorName, SymbolFlags.Value, /*ignoreErrors*/ true); - const promiseConstructorType = promiseConstructorSymbol ? getTypeOfSymbol(promiseConstructorSymbol) : unknownType; - if (promiseConstructorType === unknownType) { + const promiseConstructorType = promiseConstructorSymbol ? getTypeOfSymbol(promiseConstructorSymbol) : errorType; + if (promiseConstructorType === errorType) { if (promiseConstructorName.kind === SyntaxKind.Identifier && promiseConstructorName.escapedText === "Promise" && getTargetType(returnType) === getGlobalPromiseType(/*reportErrors*/ false)) { 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(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; + return errorType; } const globalPromiseConstructorLikeType = getGlobalPromiseConstructorLikeType(/*reportErrors*/ true); @@ -22248,12 +22324,12 @@ namespace ts { // If we couldn't resolve the global PromiseConstructorLike type we cannot verify // compatibility with __awaiter. 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; + return errorType; } 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; + return errorType; } // Verify there is no local declaration that could collide with the promise constructor. @@ -22263,7 +22339,7 @@ namespace ts { error(collidingSymbol.valueDeclaration, Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions, idText(rootName), entityNameToString(promiseConstructorName)); - return unknownType; + return errorType; } } @@ -23260,7 +23336,7 @@ namespace ts { // initializer is consistent with type associated with the node const declarationType = convertAutoToAny(getWidenedTypeForVariableLikeDeclaration(node)); - if (type !== unknownType && declarationType !== unknownType && + if (type !== errorType && declarationType !== errorType && !isTypeIdenticalTo(type, declarationType) && !(symbol.flags & SymbolFlags.JSContainer)) { errorNextVariableOrPropertyDeclarationMustHaveSameType(type, node, declarationType); @@ -23428,7 +23504,7 @@ namespace ts { // iteratedType may be undefined. In this case, we still want to check the structure of // varExpr, in particular making sure it's a valid LeftHandSideExpression. But we'd like // to short circuit the type relation checking as much as possible, so we pass the unknownType. - checkDestructuringAssignment(varExpr, iteratedType || unknownType); + checkDestructuringAssignment(varExpr, iteratedType || errorType); } else { const leftType = checkExpression(varExpr); @@ -23849,7 +23925,7 @@ namespace ts { const unwrappedReturnType = (getFunctionFlags(func) & FunctionFlags.AsyncGenerator) === FunctionFlags.Async ? getPromisedTypeOfPromise(returnType) // Async function : returnType; // AsyncGenerator function, Generator function, or normal function - return !!unwrappedReturnType && maybeTypeOfKind(unwrappedReturnType, TypeFlags.Void | TypeFlags.Any); + return !!unwrappedReturnType && maybeTypeOfKind(unwrappedReturnType, TypeFlags.Void | TypeFlags.AnyOrUnknown); } function checkReturnStatement(node: ReturnStatement) { @@ -24143,6 +24219,7 @@ namespace ts { // The predefined type keywords are reserved and cannot be used as names of user defined types. switch (name.escapedText) { case "any": + case "unknown": case "number": case "boolean": case "string": @@ -24361,7 +24438,7 @@ namespace ts { checkTypeReferenceNode(typeRefNode); if (produceDiagnostics) { const t = getTypeFromTypeNode(typeRefNode); - if (t !== unknownType) { + if (t !== errorType) { if (isValidBaseType(t)) { const genericDiag = t.symbol && t.symbol.flags & SymbolFlags.Class ? Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass : @@ -24576,7 +24653,7 @@ namespace ts { const propName = (member).name; if (isIdentifier(propName)) { const type = getTypeOfSymbol(getSymbolOfNode(member)); - if (!(type.flags & TypeFlags.Any || getFalsyFlags(type) & TypeFlags.Undefined)) { + if (!(type.flags & TypeFlags.AnyOrUnknown || getFalsyFlags(type) & TypeFlags.Undefined)) { if (!constructor || !isPropertyInitializedInConstructor(propName, type, constructor)) { error(member.name, Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor, declarationNameToString(propName)); } @@ -26224,7 +26301,7 @@ namespace ts { function getTypeOfNode(node: Node): Type | undefined { if (node.flags & NodeFlags.InWithStatement) { // We cannot answer semantic questions within a with block, do not proceed any further - return unknownType; + return errorType; } if (isPartOfTypeNode(node)) { @@ -26282,11 +26359,11 @@ namespace ts { const symbol = getSymbolAtLocation(node); if (symbol) { const declaredType = getDeclaredTypeOfSymbol(symbol); - return declaredType !== unknownType ? declaredType : getTypeOfSymbol(symbol); + return declaredType !== errorType ? declaredType : getTypeOfSymbol(symbol); } } - return unknownType; + return errorType; } // Gets the type of object literal or array literal of destructuring assignment. @@ -26302,27 +26379,27 @@ namespace ts { // } if (expr.parent.kind === SyntaxKind.ForOfStatement) { const iteratedType = checkRightHandSideOfForOf((expr.parent).expression, (expr.parent).awaitModifier); - return checkDestructuringAssignment(expr, iteratedType || unknownType); + return checkDestructuringAssignment(expr, iteratedType || errorType); } // If this is from "for" initializer // for ({a } = elems[0];.....) { } if (expr.parent.kind === SyntaxKind.BinaryExpression) { const iteratedType = getTypeOfExpression((expr.parent).right); - return checkDestructuringAssignment(expr, iteratedType || unknownType); + return checkDestructuringAssignment(expr, iteratedType || errorType); } // If this is from nested object binding pattern // for ({ skills: { primary, secondary } } = multiRobot, i = 0; i < 1; i++) { if (expr.parent.kind === SyntaxKind.PropertyAssignment) { const typeOfParentObjectLiteral = getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(expr.parent.parent); - return checkObjectLiteralDestructuringPropertyAssignment(typeOfParentObjectLiteral || unknownType, expr.parent)!; // TODO: GH#18217 + return checkObjectLiteralDestructuringPropertyAssignment(typeOfParentObjectLiteral || errorType, expr.parent)!; // TODO: GH#18217 } // Array literal assignment - array destructuring pattern Debug.assert(expr.parent.kind === SyntaxKind.ArrayLiteralExpression); // [{ property1: p1, property2 }] = elems; const typeOfArrayLiteral = getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(expr.parent); - const elementType = checkIteratedTypeOrElementType(typeOfArrayLiteral || unknownType, expr.parent, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) || unknownType; + const elementType = checkIteratedTypeOrElementType(typeOfArrayLiteral || errorType, expr.parent, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) || errorType; return checkArrayLiteralDestructuringElementAssignment(expr.parent, typeOfArrayLiteral, - (expr.parent).elements.indexOf(expr), elementType || unknownType)!; // TODO: GH#18217 + (expr.parent).elements.indexOf(expr), elementType || errorType)!; // TODO: GH#18217 } // Gets the property symbol corresponding to the property in destructuring assignment @@ -26745,10 +26822,10 @@ namespace ts { return TypeReferenceSerializationKind.Unknown; } const type = getDeclaredTypeOfSymbol(typeSymbol); - if (type === unknownType) { + if (type === errorType) { return TypeReferenceSerializationKind.Unknown; } - else if (type.flags & TypeFlags.Any) { + else if (type.flags & TypeFlags.AnyOrUnknown) { return TypeReferenceSerializationKind.ObjectType; } else if (isTypeAssignableToKind(type, TypeFlags.Void | TypeFlags.Nullable | TypeFlags.Never)) { @@ -26789,7 +26866,7 @@ namespace ts { const symbol = getSymbolOfNode(declaration); let type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature)) ? getWidenedLiteralType(getTypeOfSymbol(symbol)) - : unknownType; + : errorType; if (type.flags & TypeFlags.UniqueESSymbol && type.symbol === symbol) { flags |= NodeBuilderFlags.AllowUniqueESSymbolType; @@ -27100,7 +27177,7 @@ namespace ts { getSymbolLinks(undefinedSymbol).type = undefinedWideningType; getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments" as __String, /*arity*/ 0, /*reportErrors*/ true); - getSymbolLinks(unknownSymbol).type = unknownType; + getSymbolLinks(unknownSymbol).type = errorType; // Initialize special types globalArrayType = getGlobalType("Array" as __String, /*arity*/ 1, /*reportErrors*/ true); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index f0bb5e5ed7d..259c1ee4ea5 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2024,6 +2024,10 @@ "category": "Error", "code": 2570 }, + "Object is of type 'unknown'.": { + "category": "Error", + "code": 2571 + }, "JSX element attributes type '{0}' may not be a union type.": { "category": "Error", "code": 2600 @@ -4289,5 +4293,13 @@ "Convert '{0}' to mapped object type": { "category": "Message", "code": 95055 + }, + "Convert namespace import to named imports": { + "category": "Message", + "code": 95056 + }, + "Convert named imports to namespace import": { + "category": "Message", + "code": 95057 } } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 03a89343045..ea5a2a33937 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2850,6 +2850,7 @@ namespace ts { function parseNonArrayType(): TypeNode { switch (token()) { case SyntaxKind.AnyKeyword: + case SyntaxKind.UnknownKeyword: case SyntaxKind.StringKeyword: case SyntaxKind.NumberKeyword: case SyntaxKind.SymbolKeyword: @@ -2907,6 +2908,7 @@ namespace ts { function isStartOfType(inStartOfParameter?: boolean): boolean { switch (token()) { case SyntaxKind.AnyKeyword: + case SyntaxKind.UnknownKeyword: case SyntaxKind.StringKeyword: case SyntaxKind.NumberKeyword: case SyntaxKind.BooleanKeyword: diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 8b48aa5c041..b4c428d5e5a 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -60,15 +60,12 @@ namespace ts { watcher: FileWatcher; /** ref count keeping this directory watch alive */ refCount: number; - /** map of refcount for the subDirectory */ - subDirectoryMap?: Map; } interface DirectoryOfFailedLookupWatch { dir: string; dirPath: Path; ignore?: true; - subDirectory?: Path; } export const maxNumberOfFilesToIterateForInvalidation = 256; @@ -403,20 +400,21 @@ namespace ts { } // Use some ancestor of the root directory - let subDirectory: Path | undefined; + let subDirectoryPath: Path | undefined, subDirectory: string | undefined; if (rootPath !== undefined) { while (!isInDirectoryPath(dirPath, rootPath)) { const parentPath = getDirectoryPath(dirPath); if (parentPath === dirPath) { break; } - subDirectory = dirPath.slice(parentPath.length + directorySeparator.length) as Path; + subDirectoryPath = dirPath; + subDirectory = dir; dirPath = parentPath; dir = getDirectoryPath(dir); } } - return filterFSRootDirectoriesToWatch({ dir, dirPath, subDirectory }, dirPath); + return filterFSRootDirectoriesToWatch({ dir: subDirectory || dir, dirPath: subDirectoryPath || dirPath }, dirPath); } function isPathWithDefaultFailedLookupExtension(path: Path) { @@ -439,7 +437,7 @@ namespace ts { let setAtRoot = false; for (const failedLookupLocation of failedLookupLocations) { const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation); - const { dir, dirPath, ignore , subDirectory } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); + const { dir, dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); if (!ignore) { // If the failed lookup location path is not one of the supported extensions, // store it in the custom path @@ -451,7 +449,7 @@ namespace ts { setAtRoot = true; } else { - setDirectoryWatcher(dir, dirPath, subDirectory); + setDirectoryWatcher(dir, dirPath); } } } @@ -461,20 +459,13 @@ namespace ts { } } - function setDirectoryWatcher(dir: string, dirPath: Path, subDirectory?: Path) { - let dirWatcher = directoryWatchesOfFailedLookups.get(dirPath); + function setDirectoryWatcher(dir: string, dirPath: Path) { + const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath); if (dirWatcher) { dirWatcher.refCount++; } else { - dirWatcher = { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 }; - directoryWatchesOfFailedLookups.set(dirPath, dirWatcher); - } - - if (subDirectory) { - const subDirectoryMap = dirWatcher.subDirectoryMap || (dirWatcher.subDirectoryMap = createMap()); - const existing = subDirectoryMap.get(subDirectory) || 0; - subDirectoryMap.set(subDirectory, existing + 1); + directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 }); } } @@ -492,7 +483,7 @@ namespace ts { let removeAtRoot = false; for (const failedLookupLocation of failedLookupLocations) { const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation); - const { dirPath, ignore, subDirectory } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); + const { dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); if (!ignore) { const refCount = customFailedLookupPaths.get(failedLookupLocationPath); if (refCount) { @@ -509,7 +500,7 @@ namespace ts { removeAtRoot = true; } else { - removeDirectoryWatcher(dirPath, subDirectory); + removeDirectoryWatcher(dirPath); } } } @@ -518,30 +509,12 @@ namespace ts { } } - function removeDirectoryWatcher(dirPath: string, subDirectory?: Path) { + function removeDirectoryWatcher(dirPath: string) { const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath)!; - if (subDirectory) { - const existing = dirWatcher.subDirectoryMap!.get(subDirectory)!; - if (existing === 1) { - dirWatcher.subDirectoryMap!.delete(subDirectory); - } - else { - dirWatcher.subDirectoryMap!.set(subDirectory, existing - 1); - } - } // Do not close the watcher yet since it might be needed by other failed lookup locations. dirWatcher.refCount--; } - function inWatchedSubdirectory(dirPath: Path, fileOrDirectoryPath: Path) { - const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath); - if (!dirWatcher || !dirWatcher.subDirectoryMap) return false; - return forEachKey(dirWatcher.subDirectoryMap, subDirectory => { - const fullSubDirectory = `${dirPath}/${subDirectory}` as Path; - return fullSubDirectory === fileOrDirectoryPath || isInDirectoryPath(fullSubDirectory, fileOrDirectoryPath); - }); - } - function createDirectoryWatcher(directory: string, dirPath: Path) { return resolutionHost.watchDirectoryOfFailedLookupLocation(directory, fileOrDirectory => { const fileOrDirectoryPath = resolutionHost.toPath(fileOrDirectory); @@ -550,13 +523,8 @@ namespace ts { cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath); } - // If the files are added to project root or node_modules directory, always run through the invalidation process - // Otherwise run through invalidation only if adding to the immediate directory - if (!allFilesHaveInvalidatedResolution && - (dirPath === rootPath || isNodeModulesDirectory(dirPath) || getDirectoryPath(fileOrDirectoryPath) === dirPath || inWatchedSubdirectory(dirPath, fileOrDirectoryPath))) { - if (invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath)) { - resolutionHost.onInvalidatedResolution(); - } + if (!allFilesHaveInvalidatedResolution && invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath)) { + resolutionHost.onInvalidatedResolution(); } }, WatchDirectoryFlags.Recursive); } diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 41b65c67864..af74d69ceef 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -124,6 +124,7 @@ namespace ts { "typeof": SyntaxKind.TypeOfKeyword, "undefined": SyntaxKind.UndefinedKeyword, "unique": SyntaxKind.UniqueKeyword, + "unknown": SyntaxKind.UnknownKeyword, "var": SyntaxKind.VarKeyword, "void": SyntaxKind.VoidKeyword, "while": SyntaxKind.WhileKeyword, diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index a0ab03a9731..49453139947 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -63,6 +63,8 @@ namespace ts { return visitAwaitExpression(node as AwaitExpression); case SyntaxKind.YieldExpression: return visitYieldExpression(node as YieldExpression); + case SyntaxKind.ReturnStatement: + return visitReturnStatement(node as ReturnStatement); case SyntaxKind.LabeledStatement: return visitLabeledStatement(node as LabeledStatement); case SyntaxKind.ObjectLiteralExpression: @@ -161,6 +163,16 @@ namespace ts { return visitEachChild(node, visitor, context); } + function visitReturnStatement(node: ReturnStatement) { + if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) { + return updateReturn(node, createDownlevelAwait( + node.expression ? visitNode(node.expression, visitor, isExpression) : createVoidZero() + )); + } + + return visitEachChild(node, visitor, context); + } + function visitLabeledStatement(node: LabeledStatement) { if (enclosingFunctionFlags & FunctionFlags.Async) { const statement = unwrapInnermostStatementOfLabel(node); @@ -416,7 +428,7 @@ namespace ts { createLogicalNot(getDone) ), /*incrementor*/ undefined, - /*statement*/ convertForOfStatementHead(node, createDownlevelAwait(getValue)) + /*statement*/ convertForOfStatementHead(node, getValue) ), /*location*/ node ), diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index 4752f4e4574..a5e10c4b65d 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -3252,8 +3252,8 @@ namespace ts { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 5ae6bcb8b32..cc244d92204 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -384,6 +384,7 @@ namespace ts { case SyntaxKind.TypePredicate: case SyntaxKind.TypeParameter: case SyntaxKind.AnyKeyword: + case SyntaxKind.UnknownKeyword: case SyntaxKind.BooleanKeyword: case SyntaxKind.StringKeyword: case SyntaxKind.NumberKeyword: @@ -1907,6 +1908,7 @@ namespace ts { case SyntaxKind.MappedType: case SyntaxKind.TypeLiteral: case SyntaxKind.AnyKeyword: + case SyntaxKind.UnknownKeyword: case SyntaxKind.ThisType: break; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a3cdb32df07..b13f4aea613 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -241,6 +241,7 @@ namespace ts { TypeKeyword, UndefinedKeyword, UniqueKeyword, + UnknownKeyword, FromKeyword, GlobalKeyword, OfKeyword, // LastKeyword and LastToken and LastContextualKeyword @@ -1068,6 +1069,7 @@ namespace ts { export interface KeywordTypeNode extends TypeNode { kind: SyntaxKind.AnyKeyword + | SyntaxKind.UnknownKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.BooleanKeyword @@ -3665,42 +3667,43 @@ namespace ts { export const enum TypeFlags { Any = 1 << 0, - String = 1 << 1, - Number = 1 << 2, - Boolean = 1 << 3, - Enum = 1 << 4, - StringLiteral = 1 << 5, - NumberLiteral = 1 << 6, - BooleanLiteral = 1 << 7, - EnumLiteral = 1 << 8, // Always combined with StringLiteral, NumberLiteral, or Union - ESSymbol = 1 << 9, // Type of symbol primitive introduced in ES6 - UniqueESSymbol = 1 << 10, // unique symbol - Void = 1 << 11, - Undefined = 1 << 12, - Null = 1 << 13, - Never = 1 << 14, // Never type - TypeParameter = 1 << 15, // Type parameter - Object = 1 << 16, // Object type - Union = 1 << 17, // Union (T | U) - Intersection = 1 << 18, // Intersection (T & U) - Index = 1 << 19, // keyof T - IndexedAccess = 1 << 20, // T[K] - Conditional = 1 << 21, // T extends U ? X : Y - Substitution = 1 << 22, // Type parameter substitution + Unknown = 1 << 1, + String = 1 << 2, + Number = 1 << 3, + Boolean = 1 << 4, + Enum = 1 << 5, + StringLiteral = 1 << 6, + NumberLiteral = 1 << 7, + BooleanLiteral = 1 << 8, + EnumLiteral = 1 << 9, // Always combined with StringLiteral, NumberLiteral, or Union + ESSymbol = 1 << 10, // Type of symbol primitive introduced in ES6 + UniqueESSymbol = 1 << 11, // unique symbol + Void = 1 << 12, + Undefined = 1 << 13, + Null = 1 << 14, + Never = 1 << 15, // Never type + TypeParameter = 1 << 16, // Type parameter + Object = 1 << 17, // Object type + Union = 1 << 18, // Union (T | U) + Intersection = 1 << 19, // Intersection (T & U) + Index = 1 << 20, // keyof T + IndexedAccess = 1 << 21, // T[K] + Conditional = 1 << 22, // T extends U ? X : Y + Substitution = 1 << 23, // Type parameter substitution + NonPrimitive = 1 << 24, // intrinsic object type /* @internal */ - FreshLiteral = 1 << 23, // Fresh literal or unique type + FreshLiteral = 1 << 25, // Fresh literal or unique type /* @internal */ - ContainsWideningType = 1 << 24, // Type is or contains undefined or null widening type + UnionOfUnitTypes = 1 << 26, // Type is union of unit types /* @internal */ - ContainsObjectLiteral = 1 << 25, // Type is or contains object literal type + ContainsWideningType = 1 << 27, // Type is or contains undefined or null widening type /* @internal */ - ContainsAnyFunctionType = 1 << 26, // Type is or contains the anyFunctionType - NonPrimitive = 1 << 27, // intrinsic object type + ContainsObjectLiteral = 1 << 28, // Type is or contains object literal type /* @internal */ - UnionOfUnitTypes = 1 << 28, // Type is union of unit types - /* @internal */ - GenericMappedType = 1 << 29, // Flag used by maybeTypeOfKind + ContainsAnyFunctionType = 1 << 29, // Type is or contains the anyFunctionType + /* @internal */ + AnyOrUnknown = Any | Unknown, /* @internal */ Nullable = Undefined | Null, Literal = StringLiteral | NumberLiteral | BooleanLiteral, @@ -3712,7 +3715,7 @@ namespace ts { DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null, PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean, /* @internal */ - Intrinsic = Any | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive, + Intrinsic = Any | Unknown | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive, /* @internal */ Primitive = String | Number | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal | UniqueESSymbol, StringLike = String | StringLiteral, @@ -3733,8 +3736,8 @@ namespace ts { // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never - Narrowable = Any | StructuredOrInstantiable | StringLike | NumberLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, - NotUnionOrUnit = Any | ESSymbol | Object | NonPrimitive, + Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, + NotUnionOrUnit = Any | Unknown | ESSymbol | Object | NonPrimitive, /* @internal */ NotUnit = Any | String | Number | Boolean | Enum | ESSymbol | Void | Never | StructuredOrInstantiable, /* @internal */ @@ -3749,7 +3752,10 @@ namespace ts { /* @internal */ EmptyObject = ContainsAnyFunctionType, /* @internal */ - ConstructionFlags = NonWideningType | Wildcard | EmptyObject + ConstructionFlags = NonWideningType | Wildcard | EmptyObject, + // The following flag is used for different purposes by maybeTypeOfKind + /* @internal */ + GenericMappedType = ContainsWideningType } export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a3da44c5b1f..426c0d8d1da 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -223,11 +223,11 @@ namespace ts { } /** - * Returns a value indicating whether a name is unique globally or within the current file + * Returns a value indicating whether a name is unique globally or within the current file. + * Note: This does not consider whether a name appears as a free identifier or not, so at the expression `x.y` this includes both `x` and `y`. */ - export function isFileLevelUniqueName(currentSourceFile: SourceFile, name: string, hasGlobalName?: PrintHandlers["hasGlobalName"]): boolean { - return !(hasGlobalName && hasGlobalName(name)) - && !currentSourceFile.identifiers.has(name); + export function isFileLevelUniqueName(sourceFile: SourceFile, name: string, hasGlobalName?: PrintHandlers["hasGlobalName"]): boolean { + return !(hasGlobalName && hasGlobalName(name)) && !sourceFile.identifiers.has(name); } // Returns true if this node is missing from the actual source code. A 'missing' node is different @@ -810,6 +810,7 @@ namespace ts { switch (node.kind) { case SyntaxKind.AnyKeyword: + case SyntaxKind.UnknownKeyword: case SyntaxKind.NumberKeyword: case SyntaxKind.StringKeyword: case SyntaxKind.BooleanKeyword: @@ -5594,13 +5595,18 @@ namespace ts { return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken; } + export type TemplateLiteralToken = NoSubstitutionTemplateLiteral | TemplateHead | TemplateMiddle | TemplateTail; + export function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken { + return isTemplateLiteralKind(node.kind); + } + export function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail { const kind = node.kind; return kind === SyntaxKind.TemplateMiddle || kind === SyntaxKind.TemplateTail; } - export function isStringTextContainingNode(node: Node) { + export function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken { return node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind); } @@ -5777,6 +5783,7 @@ namespace ts { function isTypeNodeKind(kind: SyntaxKind) { return (kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode) || kind === SyntaxKind.AnyKeyword + || kind === SyntaxKind.UnknownKeyword || kind === SyntaxKind.NumberKeyword || kind === SyntaxKind.ObjectKeyword || kind === SyntaxKind.BooleanKeyword diff --git a/src/harness/evaluator.ts b/src/harness/evaluator.ts new file mode 100644 index 00000000000..793fb800f6a --- /dev/null +++ b/src/harness/evaluator.ts @@ -0,0 +1,55 @@ +namespace evaluator { + declare var Symbol: SymbolConstructor; + + const sourceFile = vpath.combine(vfs.srcFolder, "source.ts"); + + function compile(sourceText: string, options?: ts.CompilerOptions) { + const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false); + fs.writeFileSync(sourceFile, sourceText); + const compilerOptions: ts.CompilerOptions = { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS, lib: ["lib.esnext.d.ts"], ...options }; + const host = new fakes.CompilerHost(fs, compilerOptions); + return compiler.compileFiles(host, [sourceFile], compilerOptions); + } + + function noRequire(id: string) { + throw new Error(`Module '${id}' could not be found.`); + } + + // Define a custom "Symbol" constructor to attach missing built-in symbols without + // modifying the global "Symbol" constructor + // tslint:disable-next-line:variable-name + const FakeSymbol: SymbolConstructor = ((description?: string) => Symbol(description)) as any; + (FakeSymbol).prototype = Symbol.prototype; + for (const key of Object.getOwnPropertyNames(Symbol)) { + Object.defineProperty(FakeSymbol, key, Object.getOwnPropertyDescriptor(Symbol, key)!); + } + + // Add "asyncIterator" if missing + if (!ts.hasProperty(FakeSymbol, "asyncIterator")) Object.defineProperty(FakeSymbol, "asyncIterator", { value: Symbol.for("Symbol.asyncIterator"), configurable: true }); + + function evaluate(result: compiler.CompilationResult, globals?: Record) { + globals = { Symbol: FakeSymbol, ...globals }; + + const output = result.getOutput(sourceFile, "js")!; + assert.isDefined(output); + + const globalNames: string[] = []; + const globalArgs: any[] = []; + for (const name in globals) { + if (ts.hasProperty(globals, name)) { + globalNames.push(name); + globalArgs.push(globals[name]); + } + } + + const evaluateText = `(function (module, exports, require, __dirname, __filename, ${globalNames.join(", ")}) { ${output.text} })`; + const evaluateThunk = eval(evaluateText) as (module: any, exports: any, require: (id: string) => any, dirname: string, filename: string, ...globalArgs: any[]) => void; + const module: { exports: any; } = { exports: {} }; + evaluateThunk.call(globals, module, module.exports, noRequire, vpath.dirname(output.file), output.file, FakeSymbol, ...globalArgs); + return module.exports; + } + + export function evaluateTypeScript(sourceText: string, options?: ts.CompilerOptions, globals?: Record) { + return evaluate(compile(sourceText, options), globals); + } +} \ No newline at end of file diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 369709c31e5..f6214d4c719 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -868,7 +868,7 @@ namespace FourSlash { for (const entry of actualCompletions.entries) { if (actualByName.has(entry.name)) { // TODO: GH#23587 - if (entry.name !== "undefined" && entry.name !== "require") this.raiseError(`Duplicate completions for ${entry.name}`); + if (entry.name !== "undefined" && entry.name !== "require") this.raiseError(`Duplicate (${actualCompletions.entries.filter(a => a.name === entry.name).length}) completions for ${entry.name}`); } else { actualByName.set(entry.name, entry); diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 102bddf91c7..ae409e96b87 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -120,6 +120,7 @@ "../services/codefixes/useDefaultImport.ts", "../services/codefixes/fixAddModuleReferTypeMissingTypeof.ts", "../services/codefixes/convertToMappedObjectType.ts", + "../services/refactors/convertImport.ts", "../services/refactors/extractSymbol.ts", "../services/refactors/generateGetAccessorAndSetAccessor.ts", "../services/refactors/moveToNewFile.ts", @@ -148,6 +149,7 @@ "vpath.ts", "vfs.ts", "compiler.ts", + "evaluator.ts", "fakes.ts", "sourceMapRecorder.ts", @@ -169,5 +171,5 @@ "parallel/shared.ts", "runner.ts" ], - "include": ["unittests/**.ts"] + "include": ["unittests/**/*.ts"] } diff --git a/src/harness/unittests/evaluation/asyncGenerator.ts b/src/harness/unittests/evaluation/asyncGenerator.ts new file mode 100644 index 00000000000..9963ea921fa --- /dev/null +++ b/src/harness/unittests/evaluation/asyncGenerator.ts @@ -0,0 +1,30 @@ +describe("asyncGeneratorEvaluation", () => { + it("return (es5)", async () => { + const result = evaluator.evaluateTypeScript(` + async function * g() { + return Promise.resolve(0); + } + export const output: any[] = []; + export async function main() { + output.push(await g().next()); + }`); + await result.main(); + assert.deepEqual(result.output, [ + { value: 0, done: true } + ]); + }); + it("return (es2015)", async () => { + const result = evaluator.evaluateTypeScript(` + async function * g() { + return Promise.resolve(0); + } + export const output: any[] = []; + export async function main() { + output.push(await g().next()); + }`, { target: ts.ScriptTarget.ES2015 }); + await result.main(); + assert.deepEqual(result.output, [ + { value: 0, done: true } + ]); + }); +}); \ No newline at end of file diff --git a/src/harness/unittests/evaluation/forAwaitOf.ts b/src/harness/unittests/evaluation/forAwaitOf.ts new file mode 100644 index 00000000000..b02a45860b9 --- /dev/null +++ b/src/harness/unittests/evaluation/forAwaitOf.ts @@ -0,0 +1,105 @@ +describe("forAwaitOfEvaluation", () => { + it("sync (es5)", async () => { + const result = evaluator.evaluateTypeScript(` + let i = 0; + const iterator = { + [Symbol.iterator]() { return this; }, + next() { + switch (i++) { + case 0: return { value: 1, done: false }; + case 1: return { value: Promise.resolve(2), done: false }; + case 2: return { value: new Promise(resolve => setTimeout(resolve, 100, 3)), done: false }; + default: return { value: undefined: done: true }; + } + } + }; + export const output: any[] = []; + export async function main() { + for await (const item of iterator) { + output.push(item); + } + }`); + await result.main(); + assert.strictEqual(result.output[0], 1); + assert.strictEqual(result.output[1], 2); + assert.strictEqual(result.output[2], 3); + }); + + it("sync (es2015)", async () => { + const result = evaluator.evaluateTypeScript(` + let i = 0; + const iterator = { + [Symbol.iterator]() { return this; }, + next() { + switch (i++) { + case 0: return { value: 1, done: false }; + case 1: return { value: Promise.resolve(2), done: false }; + case 2: return { value: new Promise(resolve => setTimeout(resolve, 100, 3)), done: false }; + default: return { value: undefined: done: true }; + } + } + }; + export const output: any[] = []; + export async function main() { + for await (const item of iterator) { + output.push(item); + } + }`, { target: ts.ScriptTarget.ES2015 }); + await result.main(); + assert.strictEqual(result.output[0], 1); + assert.strictEqual(result.output[1], 2); + assert.strictEqual(result.output[2], 3); + }); + + it("async (es5)", async () => { + const result = evaluator.evaluateTypeScript(` + let i = 0; + const iterator = { + [Symbol.asyncIterator]() { return this; }, + async next() { + switch (i++) { + case 0: return { value: 1, done: false }; + case 1: return { value: Promise.resolve(2), done: false }; + case 2: return { value: new Promise(resolve => setTimeout(resolve, 100, 3)), done: false }; + default: return { value: undefined: done: true }; + } + } + }; + export const output: any[] = []; + export async function main() { + for await (const item of iterator) { + output.push(item); + } + }`); + await result.main(); + assert.strictEqual(result.output[0], 1); + assert.instanceOf(result.output[1], Promise); + assert.instanceOf(result.output[2], Promise); + }); + + it("async (es2015)", async () => { + const result = evaluator.evaluateTypeScript(` + let i = 0; + const iterator = { + [Symbol.asyncIterator]() { return this; }, + async next() { + switch (i++) { + case 0: return { value: 1, done: false }; + case 1: return { value: Promise.resolve(2), done: false }; + case 2: return { value: new Promise(resolve => setTimeout(resolve, 100, 3)), done: false }; + default: return { value: undefined: done: true }; + } + } + }; + export const output: any[] = []; + export async function main() { + for await (const item of iterator) { + output.push(item); + } + }`, { target: ts.ScriptTarget.ES2015 }); + await result.main(); + assert.strictEqual(result.output[0], 1); + assert.instanceOf(result.output[1], Promise); + assert.instanceOf(result.output[2], Promise); + }); +}); \ No newline at end of file diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts index 44b6c8ea887..e6fffbc5e79 100644 --- a/src/harness/unittests/tscWatchMode.ts +++ b/src/harness/unittests/tscWatchMode.ts @@ -10,9 +10,12 @@ namespace ts.tscWatch { import checkArray = TestFSWithWatch.checkArray; import libFile = TestFSWithWatch.libFile; import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles; + import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed; import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories; + import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed; import checkOutputContains = TestFSWithWatch.checkOutputContains; import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain; + import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory; export function checkProgramActualFiles(program: Program, expectedFiles: string[]) { checkArray(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles); @@ -2379,7 +2382,7 @@ declare module "fs" { }); describe("tsc-watch when watchDirectories implementation", () => { - function verifyRenamingFileInSubFolder(tscWatchDirectory: TestFSWithWatch.Tsc_WatchDirectory) { + function verifyRenamingFileInSubFolder(tscWatchDirectory: Tsc_WatchDirectory) { const projectFolder = "/a/username/project"; const projectSrcFolder = `${projectFolder}/src`; const configFile: File = { @@ -2399,8 +2402,8 @@ declare module "fs" { const projectFolders = [projectFolder, projectSrcFolder, `${projectFolder}/node_modules/@types`]; // Watching files config file, file, lib file const expectedWatchedFiles = files.map(f => f.path); - const expectedWatchedDirectories = tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory ? projectFolders : emptyArray; - if (tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.WatchFile) { + const expectedWatchedDirectories = tscWatchDirectory === Tsc_WatchDirectory.NonRecursiveWatchDirectory ? projectFolders : emptyArray; + if (tscWatchDirectory === Tsc_WatchDirectory.WatchFile) { expectedWatchedFiles.push(...projectFolders); } @@ -2410,7 +2413,7 @@ declare module "fs" { file.path = file.path.replace("file1.ts", "file2.ts"); expectedWatchedFiles[0] = file.path; host.reloadFS(files); - if (tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling) { + if (tscWatchDirectory === Tsc_WatchDirectory.DynamicPolling) { // With dynamic polling the fs change would be detected only by running timeouts host.runQueuedTimeoutCallbacks(); } @@ -2429,21 +2432,21 @@ declare module "fs" { checkWatchedDirectories(host, emptyArray, /*recursive*/ true); // Watching config file, file, lib file and directories - TestFSWithWatch.checkMultiMapEachKeyWithCount("watchedFiles", host.watchedFiles, expectedWatchedFiles, 1); - TestFSWithWatch.checkMultiMapEachKeyWithCount("watchedDirectories", host.watchedDirectories, expectedWatchedDirectories, 1); + checkWatchedFilesDetailed(host, expectedWatchedFiles, 1); + checkWatchedDirectoriesDetailed(host, expectedWatchedDirectories, 1, /*recursive*/ false); } } it("uses watchFile when renaming file in subfolder", () => { - verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.WatchFile); + verifyRenamingFileInSubFolder(Tsc_WatchDirectory.WatchFile); }); it("uses non recursive watchDirectory when renaming file in subfolder", () => { - verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory); + verifyRenamingFileInSubFolder(Tsc_WatchDirectory.NonRecursiveWatchDirectory); }); it("uses non recursive dynamic polling when renaming file in subfolder", () => { - verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling); + verifyRenamingFileInSubFolder(Tsc_WatchDirectory.DynamicPolling); }); it("when there are symlinks to folders in recursive folders", () => { @@ -2482,7 +2485,7 @@ declare module "fs" { }; const files = [file1, tsconfig, realA, realB, symLinkA, symLinkB, symLinkBInA, symLinkAInB]; const environmentVariables = createMap(); - environmentVariables.set("TSC_WATCHDIRECTORY", TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory); + environmentVariables.set("TSC_WATCHDIRECTORY", Tsc_WatchDirectory.NonRecursiveWatchDirectory); const host = createWatchedSystem(files, { environmentVariables, currentDirectory: cwd }); createWatchOfConfigFile("tsconfig.json", host); checkWatchedDirectories(host, emptyArray, /*recursive*/ true); @@ -2491,4 +2494,46 @@ declare module "fs" { }); }); }); + + describe("tsc-watch with modules linked to sibling folder", () => { + const projectRoot = "/user/username/projects/project"; + const mainPackageRoot = `${projectRoot}/main`; + const linkedPackageRoot = `${projectRoot}/linked-package`; + const mainFile: File = { + path: `${mainPackageRoot}/index.ts`, + content: "import { Foo } from '@scoped/linked-package'" + }; + const config: File = { + path: `${mainPackageRoot}/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { module: "commonjs", moduleResolution: "node", baseUrl: ".", rootDir: "." }, + files: ["index.ts"] + }) + }; + const linkedPackageInMain: SymLink = { + path: `${mainPackageRoot}/node_modules/@scoped/linked-package`, + symLink: `${linkedPackageRoot}` + }; + const linkedPackageJson: File = { + path: `${linkedPackageRoot}/package.json`, + content: JSON.stringify({ name: "@scoped/linked-package", version: "0.0.1", types: "dist/index.d.ts", main: "dist/index.js" }) + }; + const linkedPackageIndex: File = { + path: `${linkedPackageRoot}/dist/index.d.ts`, + content: "export * from './other';" + }; + const linkedPackageOther: File = { + path: `${linkedPackageRoot}/dist/other.d.ts`, + content: 'export declare const Foo = "BAR";' + }; + + it("verify watched directories", () => { + const files = [libFile, mainFile, config, linkedPackageInMain, linkedPackageJson, linkedPackageIndex, linkedPackageOther]; + const host = createWatchedSystem(files, { currentDirectory: mainPackageRoot }); + createWatchOfConfigFile("tsconfig.json", host); + checkWatchedFilesDetailed(host, [libFile.path, mainFile.path, config.path, linkedPackageIndex.path, linkedPackageOther.path], 1); + checkWatchedDirectories(host, emptyArray, /*recursive*/ false); + checkWatchedDirectoriesDetailed(host, [mainPackageRoot, linkedPackageRoot, `${mainPackageRoot}/node_modules/@types`, `${projectRoot}/node_modules/@types`], 1, /*recursive*/ true); + }); + }); } diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index f6efe8b99dd..4518a740a85 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -19,6 +19,7 @@ namespace ts.projectSystem { export import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories; export import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed; import safeList = TestFSWithWatch.safeList; + import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory; export const customTypesMap = { path: "/typesMap.json", @@ -6259,7 +6260,7 @@ namespace ts.projectSystem { } function verifyCalledOnEachEntryNTimes(callback: CalledMaps, expectedKeys: ReadonlyArray, nTimes: number) { - TestFSWithWatch.checkMultiMapEachKeyWithCount(callback, calledMaps[callback], expectedKeys, nTimes); + TestFSWithWatch.checkMultiMapKeyCount(callback, calledMaps[callback], expectedKeys, nTimes); } function verifyNoHostCalls() { @@ -7813,14 +7814,10 @@ new C();` checkCompleteEvent(session, 2, expectedSequenceId); } - function createSingleWatchMap(paths: string[]) { - return arrayToMap(paths, p => p, () => 1); - } - function verifyWatchedFilesAndDirectories(host: TestServerHost, files: string[], directories: string[]) { - checkWatchedFilesDetailed(host, createSingleWatchMap(files.filter(f => f !== recognizersDateTimeSrcFile.path))); + checkWatchedFilesDetailed(host, files.filter(f => f !== recognizersDateTimeSrcFile.path), 1); checkWatchedDirectories(host, emptyArray, /*recursive*/ false); - checkWatchedDirectoriesDetailed(host, createSingleWatchMap(directories), /*recursive*/ true); + checkWatchedDirectoriesDetailed(host, directories, 1, /*recursive*/ true); } function createSessionAndOpenFile(host: TestServerHost) { @@ -7842,7 +7839,7 @@ new C();` const filesAfterCompilation = [...filesWithNodeModulesSetup, recongnizerTextDistTypingFile]; const watchedDirectoriesWithResolvedModule = [`${recognizersDateTime}/src`, withPathMapping ? packages : recognizersDateTime, ...getTypeRootsFromLocation(recognizersDateTime)]; - const watchedDirectoriesWithUnresolvedModule = [recognizersDateTime, ...watchedDirectoriesWithResolvedModule, ...getNodeModuleDirectories(packages)]; + const watchedDirectoriesWithUnresolvedModule = [recognizersDateTime, ...(withPathMapping ? [recognizersText] : emptyArray), ...watchedDirectoriesWithResolvedModule, ...getNodeModuleDirectories(packages)]; function verifyProjectWithResolvedModule(session: TestSession) { const projectService = session.getProjectService(); @@ -8315,7 +8312,7 @@ new C();` }); describe("tsserverProjectSystem watchDirectories implementation", () => { - function verifyCompletionListWithNewFileInSubFolder(tscWatchDirectory: TestFSWithWatch.Tsc_WatchDirectory) { + function verifyCompletionListWithNewFileInSubFolder(tscWatchDirectory: Tsc_WatchDirectory) { const projectFolder = "/a/username/project"; const projectSrcFolder = `${projectFolder}/src`; const configFile: File = { @@ -8336,9 +8333,9 @@ new C();` // All closed files(files other than index), project folder, project/src folder and project/node_modules/@types folder const expectedWatchedFiles = arrayToMap(fileNames.slice(1), s => s, () => 1); const expectedWatchedDirectories = createMap(); - const mapOfDirectories = tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory ? + const mapOfDirectories = tscWatchDirectory === Tsc_WatchDirectory.NonRecursiveWatchDirectory ? expectedWatchedDirectories : - tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.WatchFile ? + tscWatchDirectory === Tsc_WatchDirectory.WatchFile ? expectedWatchedFiles : createMap(); // For failed resolution lookup and tsconfig files @@ -8385,15 +8382,15 @@ new C();` } it("uses watchFile when file is added to subfolder, completion list has new file", () => { - verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.WatchFile); + verifyCompletionListWithNewFileInSubFolder(Tsc_WatchDirectory.WatchFile); }); it("uses non recursive watchDirectory when file is added to subfolder, completion list has new file", () => { - verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory); + verifyCompletionListWithNewFileInSubFolder(Tsc_WatchDirectory.NonRecursiveWatchDirectory); }); it("uses dynamic polling when file is added to subfolder, completion list has new file", () => { - verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling); + verifyCompletionListWithNewFileInSubFolder(Tsc_WatchDirectory.DynamicPolling); }); }); diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index 0afa67880a4..484d3302c1b 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -175,7 +175,10 @@ interface Array {}` } } - export function checkMultiMapKeyCount(caption: string, actual: MultiMap, expectedKeys: Map) { + export function checkMultiMapKeyCount(caption: string, actual: MultiMap, expectedKeys: ReadonlyMap): void; + export function checkMultiMapKeyCount(caption: string, actual: MultiMap, expectedKeys: ReadonlyArray, eachKeyCount: number): void; + export function checkMultiMapKeyCount(caption: string, actual: MultiMap, expectedKeysMapOrArray: ReadonlyMap | ReadonlyArray, eachKeyCount?: number) { + const expectedKeys = isArray(expectedKeysMapOrArray) ? arrayToMap(expectedKeysMapOrArray, s => s, () => eachKeyCount!) : expectedKeysMapOrArray; verifyMapSize(caption, actual, arrayFrom(expectedKeys.keys())); expectedKeys.forEach((count, name) => { assert.isTrue(actual.has(name), `${caption}: expected to contain ${name}, actual keys: ${arrayFrom(actual.keys())}`); @@ -183,10 +186,6 @@ interface Array {}` }); } - export function checkMultiMapEachKeyWithCount(caption: string, actual: MultiMap, expectedKeys: ReadonlyArray, count: number) { - return checkMultiMapKeyCount(caption, actual, arrayToMap(expectedKeys, s => s, () => count)); - } - export function checkArray(caption: string, actual: ReadonlyArray, expected: ReadonlyArray) { assert.equal(actual.length, expected.length, `${caption}: incorrect actual number of files, expected:\r\n${expected.join("\r\n")}\r\ngot: ${actual.join("\r\n")}`); for (const f of expected) { @@ -198,16 +197,31 @@ interface Array {}` checkMapKeys("watchedFiles", host.watchedFiles, expectedFiles); } - export function checkWatchedFilesDetailed(host: TestServerHost, expectedFiles: Map) { - checkMultiMapKeyCount("watchedFiles", host.watchedFiles, expectedFiles); + export function checkWatchedFilesDetailed(host: TestServerHost, expectedFiles: ReadonlyMap): void; + export function checkWatchedFilesDetailed(host: TestServerHost, expectedFiles: ReadonlyArray, eachFileWatchCount: number): void; + export function checkWatchedFilesDetailed(host: TestServerHost, expectedFiles: ReadonlyMap | ReadonlyArray, eachFileWatchCount?: number) { + if (isArray(expectedFiles)) { + checkMultiMapKeyCount("watchedFiles", host.watchedFiles, expectedFiles, eachFileWatchCount!); + } + else { + checkMultiMapKeyCount("watchedFiles", host.watchedFiles, expectedFiles); + } } export function checkWatchedDirectories(host: TestServerHost, expectedDirectories: string[], recursive: boolean) { checkMapKeys(`watchedDirectories${recursive ? " recursive" : ""}`, recursive ? host.watchedDirectoriesRecursive : host.watchedDirectories, expectedDirectories); } - export function checkWatchedDirectoriesDetailed(host: TestServerHost, expectedDirectories: Map, recursive: boolean) { - checkMultiMapKeyCount(`watchedDirectories${recursive ? " recursive" : ""}`, recursive ? host.watchedDirectoriesRecursive : host.watchedDirectories, expectedDirectories); + export function checkWatchedDirectoriesDetailed(host: TestServerHost, expectedDirectories: ReadonlyMap, recursive: boolean): void; + export function checkWatchedDirectoriesDetailed(host: TestServerHost, expectedDirectories: ReadonlyArray, eachDirectoryWatchCount: number, recursive: boolean): void; + export function checkWatchedDirectoriesDetailed(host: TestServerHost, expectedDirectories: ReadonlyMap | ReadonlyArray, recursiveOrEachDirectoryWatchCount: boolean | number, recursive?: boolean) { + if (isArray(expectedDirectories)) { + checkMultiMapKeyCount(`watchedDirectories${recursive ? " recursive" : ""}`, recursive ? host.watchedDirectoriesRecursive : host.watchedDirectories, expectedDirectories, recursiveOrEachDirectoryWatchCount as number); + } + else { + recursive = recursiveOrEachDirectoryWatchCount as boolean; + checkMultiMapKeyCount(`watchedDirectories${recursive ? " recursive" : ""}`, recursive ? host.watchedDirectoriesRecursive : host.watchedDirectories, expectedDirectories); + } } export function checkOutputContains(host: TestServerHost, expected: ReadonlyArray) { diff --git a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl index e68b3b149ea..7581c49286b 100644 --- a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2394,6 +2394,15 @@ + + + + + + + + + @@ -2559,6 +2568,9 @@ + + + diff --git a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl index bbedf489c37..0d661980ba6 100644 --- a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2394,6 +2394,15 @@ + + + + + + + + + @@ -2556,6 +2565,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl index 4d01ea1789c..fc9952d3b43 100644 --- a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2403,6 +2403,15 @@ + + + + + + + + + @@ -2568,6 +2577,9 @@ + + + diff --git a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl index e076be1b08c..de37564b0cb 100644 --- a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2391,6 +2391,15 @@ + + + + + + + + + @@ -2556,6 +2565,9 @@ + + + diff --git a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl index 5604802bcb3..0ea5759d00d 100644 --- a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2406,6 +2406,15 @@ + + + + + + + + + @@ -2568,6 +2577,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl index 34419b903c1..b49cfdfe469 100644 --- a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2394,6 +2394,15 @@ + + + + + + + + + @@ -2559,6 +2568,9 @@ + + + diff --git a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl index 04e562b0fd4..e2cc92c2ed4 100644 --- a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2394,6 +2394,15 @@ + + + + + + + + + @@ -2559,6 +2568,9 @@ + + + diff --git a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl index 1c9ee893cc3..e61caabaf99 100644 --- a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2394,6 +2394,15 @@ + + + + + + + + + @@ -2559,6 +2568,9 @@ + + + diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 9d9522d2d38..63032699b0e 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2384,6 +2384,15 @@ + + + + + + + + + @@ -2549,6 +2558,9 @@ + + + diff --git a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl index 1308cb03128..339ed012ebb 100644 --- a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2387,6 +2387,15 @@ + + + + + + + + + @@ -2552,6 +2561,9 @@ + + + diff --git a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl index 5ec3b07f2ef..c9be251b033 100644 --- a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2393,6 +2393,15 @@ + + + + + + + + + @@ -2555,6 +2564,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 9480e932325..130887938ee 100644 --- a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2387,6 +2387,15 @@ + + + + + + + + + @@ -2552,6 +2561,9 @@ + + + diff --git a/src/server/session.ts b/src/server/session.ts index 43e36dee8b5..191982a7cd4 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1025,13 +1025,10 @@ namespace ts.server { const position = this.getPosition(args, scriptInfo); if (simplifiedResult) { const nameInfo = defaultProject.getLanguageService().getQuickInfoAtPosition(file, position); - if (!nameInfo) { - return undefined; - } - const displayString = displayPartsToString(nameInfo.displayParts); - const nameSpan = nameInfo.textSpan; - const nameColStart = scriptInfo.positionToLineOffset(nameSpan.start).offset; - const nameText = scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)); + const displayString = nameInfo ? displayPartsToString(nameInfo.displayParts) : ""; + const nameSpan = nameInfo && nameInfo.textSpan; + const nameColStart = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0; + const nameText = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : ""; const refs = combineProjectOutput( file, path => this.projectService.getScriptInfoForPath(path)!.fileName, diff --git a/src/server/tsconfig.json b/src/server/tsconfig.json index 79cd76fc2c0..a92a19f9c01 100644 --- a/src/server/tsconfig.json +++ b/src/server/tsconfig.json @@ -116,6 +116,7 @@ "../services/codefixes/useDefaultImport.ts", "../services/codefixes/fixAddModuleReferTypeMissingTypeof.ts", "../services/codefixes/convertToMappedObjectType.ts", + "../services/refactors/convertImport.ts", "../services/refactors/extractSymbol.ts", "../services/refactors/generateGetAccessorAndSetAccessor.ts", "../services/refactors/moveToNewFile.ts", diff --git a/src/server/tsconfig.library.json b/src/server/tsconfig.library.json index 57f6862cd6f..1675002c653 100644 --- a/src/server/tsconfig.library.json +++ b/src/server/tsconfig.library.json @@ -122,6 +122,7 @@ "../services/codefixes/useDefaultImport.ts", "../services/codefixes/fixAddModuleReferTypeMissingTypeof.ts", "../services/codefixes/convertToMappedObjectType.ts", + "../services/refactors/convertImport.ts", "../services/refactors/extractSymbol.ts", "../services/refactors/generateGetAccessorAndSetAccessor.ts", "../services/refactors/moveToNewFile.ts", diff --git a/src/services/codefixes/convertToEs6Module.ts b/src/services/codefixes/convertToEs6Module.ts index 8eadbc3a306..c763d4da0c8 100644 --- a/src/services/codefixes/convertToEs6Module.ts +++ b/src/services/codefixes/convertToEs6Module.ts @@ -437,15 +437,19 @@ namespace ts.codefix { type FreeIdentifiers = ReadonlyMap>; function collectFreeIdentifiers(file: SourceFile): FreeIdentifiers { const map = createMultiMap(); - file.forEachChild(function recur(node) { - if (isIdentifier(node) && isFreeIdentifier(node)) { - map.add(node.text, node); - } - node.forEachChild(recur); - }); + forEachFreeIdentifier(file, id => map.add(id.text, id)); return map; } + /** + * A free identifier is an identifier that can be accessed through name lookup as a local variable. + * In the expression `x.y`, `x` is a free identifier, but `y` is not. + */ + function forEachFreeIdentifier(node: Node, cb: (id: Identifier) => void): void { + if (isIdentifier(node) && isFreeIdentifier(node)) cb(node); + node.forEachChild(child => forEachFreeIdentifier(child, cb)); + } + function isFreeIdentifier(node: Identifier): boolean { const { parent } = node; switch (parent.kind) { @@ -453,6 +457,8 @@ namespace ts.codefix { return (parent as PropertyAccessExpression).name !== node; case SyntaxKind.BindingElement: return (parent as BindingElement).propertyName !== node; + case SyntaxKind.ImportSpecifier: + return (parent as ImportSpecifier).propertyName !== node; default: return true; } diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index 2eafb5cdd6f..53492211042 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -199,6 +199,13 @@ namespace ts.codefix { preferences: UserPreferences, ): void { const methodDeclaration = createMethodFromCallExpression(callExpression, token.text, inJs, makeStatic, preferences); - changeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, methodDeclaration); + const containingMethodDeclaration = getAncestor(callExpression, SyntaxKind.MethodDeclaration); + + if (containingMethodDeclaration && containingMethodDeclaration.parent === classDeclaration) { + changeTracker.insertNodeAfter(classDeclarationSourceFile, containingMethodDeclaration, methodDeclaration); + } + else { + changeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, methodDeclaration); + } } } diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index 29567db03d5..781f14566c9 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -32,6 +32,10 @@ namespace ts.codefix { return Debug.assertDefined(getContainingClass(getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false))); } + function symbolPointsToNonPrivateMember (symbol: Symbol) { + return !(getModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private); + } + function addMissingDeclarations( checker: TypeChecker, implementedTypeNode: ExpressionWithTypeArguments, @@ -40,11 +44,12 @@ namespace ts.codefix { changeTracker: textChanges.ChangeTracker, preferences: UserPreferences, ): void { + const maybeHeritageClauseSymbol = getHeritageClauseSymbolTable(classDeclaration, checker); // Note that this is ultimately derived from a map indexed by symbol names, // so duplicates cannot occur. const implementedType = checker.getTypeAtLocation(implementedTypeNode) as InterfaceType; const implementedTypeSymbols = checker.getPropertiesOfType(implementedType); - const nonPrivateMembers = implementedTypeSymbols.filter(symbol => !(getModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private)); + const nonPrivateAndNotExistedInHeritageClauseMembers = implementedTypeSymbols.filter(and(symbolPointsToNonPrivateMember, symbol => !maybeHeritageClauseSymbol.has(symbol.escapedName))); const classType = checker.getTypeAtLocation(classDeclaration)!; @@ -55,7 +60,7 @@ namespace ts.codefix { createMissingIndexSignatureDeclaration(implementedType, IndexKind.String); } - createMissingMemberNodes(classDeclaration, nonPrivateMembers, checker, preferences, member => changeTracker.insertNodeAtClassStart(sourceFile, classDeclaration, member)); + createMissingMemberNodes(classDeclaration, nonPrivateAndNotExistedInHeritageClauseMembers, checker, preferences, member => changeTracker.insertNodeAtClassStart(sourceFile, classDeclaration, member)); function createMissingIndexSignatureDeclaration(type: InterfaceType, kind: IndexKind): void { const indexInfoOfKind = checker.getIndexInfoOfType(type, kind); @@ -64,4 +69,12 @@ namespace ts.codefix { } } } + + function getHeritageClauseSymbolTable (classDeclaration: ClassLikeDeclaration, checker: TypeChecker): SymbolTable { + const heritageClauseNode = getClassExtendsHeritageClauseElement(classDeclaration); + if (!heritageClauseNode) return createSymbolTable(); + const heritageClauseType = checker.getTypeAtLocation(heritageClauseNode) as InterfaceType; + const heritageClauseTypeSymbols = checker.getPropertiesOfType(heritageClauseType); + return createSymbolTable(heritageClauseTypeSymbols.filter(symbolPointsToNonPrivateMember)); + } } diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index e2ef6e9ec3c..c97902e7713 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -14,7 +14,8 @@ namespace ts.codefix { registerCodeFix({ errorCodes, getCodeActions(context) { - const { errorCode, sourceFile } = context; + const { errorCode, sourceFile, program } = context; + const checker = program.getTypeChecker(); const startToken = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false); const importDecl = tryGetFullImport(startToken); @@ -22,19 +23,19 @@ namespace ts.codefix { const changes = textChanges.ChangeTracker.with(context, t => t.deleteNode(sourceFile, importDecl)); return [createCodeFixAction(fixName, changes, [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)], fixIdDelete, Diagnostics.Delete_all_unused_declarations)]; } - const delDestructure = textChanges.ChangeTracker.with(context, t => tryDeleteFullDestructure(t, sourceFile, startToken, /*deleted*/ undefined)); + const delDestructure = textChanges.ChangeTracker.with(context, t => tryDeleteFullDestructure(t, sourceFile, startToken, /*deleted*/ undefined, checker, /*isFixAll*/ false)); if (delDestructure.length) { return [createCodeFixAction(fixName, delDestructure, Diagnostics.Remove_destructuring, fixIdDelete, Diagnostics.Delete_all_unused_declarations)]; } const delVar = textChanges.ChangeTracker.with(context, t => tryDeleteFullVariableStatement(t, sourceFile, startToken, /*deleted*/ undefined)); if (delVar.length) { - return [createCodeFixAction(fixName, delDestructure, Diagnostics.Remove_variable_statement, fixIdDelete, Diagnostics.Delete_all_unused_declarations)]; + return [createCodeFixAction(fixName, delVar, Diagnostics.Remove_variable_statement, fixIdDelete, Diagnostics.Delete_all_unused_declarations)]; } const token = getToken(sourceFile, textSpanEnd(context.span)); const result: CodeFixAction[] = []; - const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(t, sourceFile, token, /*deleted*/ undefined)); + const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(t, sourceFile, token, /*deleted*/ undefined, checker, /*isFixAll*/ false)); if (deletion.length) { result.push(createCodeFixAction(fixName, deletion, [Diagnostics.Remove_declaration_for_Colon_0, token.getText(sourceFile)], fixIdDelete, Diagnostics.Delete_all_unused_declarations)); } @@ -50,8 +51,9 @@ namespace ts.codefix { getAllCodeActions: context => { // Track a set of deleted nodes that may be ancestors of other marked for deletion -- only delete the ancestors. const deleted = new NodeSet(); + const { sourceFile, program } = context; + const checker = program.getTypeChecker(); return codeFixAll(context, errorCodes, (changes, diag) => { - const { sourceFile } = context; const startToken = getTokenAtPosition(sourceFile, diag.start, /*includeJsDocComment*/ false); const token = findPrecedingToken(textSpanEnd(diag), diag.file)!; switch (context.fixId) { @@ -68,8 +70,9 @@ namespace ts.codefix { if (importDecl) { changes.deleteNode(sourceFile, importDecl); } - else if (!tryDeleteFullDestructure(changes, sourceFile, startToken, deleted) && !tryDeleteFullVariableStatement(changes, sourceFile, startToken, deleted)) { - tryDeleteDeclaration(changes, sourceFile, token, deleted); + else if (!tryDeleteFullDestructure(changes, sourceFile, startToken, deleted, checker, /*isFixAll*/ true) && + !tryDeleteFullVariableStatement(changes, sourceFile, startToken, deleted)) { + tryDeleteDeclaration(changes, sourceFile, token, deleted, checker, /*isFixAll*/ true); } break; default: @@ -84,7 +87,7 @@ namespace ts.codefix { return startToken.kind === SyntaxKind.ImportKeyword ? tryCast(startToken.parent, isImportDeclaration) : undefined; } - function tryDeleteFullDestructure(changes: textChanges.ChangeTracker, sourceFile: SourceFile, startToken: Node, deletedAncestors: NodeSet | undefined): boolean { + function tryDeleteFullDestructure(changes: textChanges.ChangeTracker, sourceFile: SourceFile, startToken: Node, deletedAncestors: NodeSet | undefined, checker: TypeChecker, isFixAll: boolean): boolean { if (startToken.kind !== SyntaxKind.OpenBraceToken || !isObjectBindingPattern(startToken.parent)) return false; const decl = cast(startToken.parent, isObjectBindingPattern).parent; switch (decl.kind) { @@ -92,6 +95,7 @@ namespace ts.codefix { tryDeleteVariableDeclaration(changes, sourceFile, decl, deletedAncestors); break; case SyntaxKind.Parameter: + if (!mayDeleteParameter(decl, checker, isFixAll)) break; if (deletedAncestors) deletedAncestors.add(decl); changes.deleteNodeInList(sourceFile, decl); break; @@ -144,10 +148,10 @@ namespace ts.codefix { return false; } - function tryDeleteDeclaration(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, deletedAncestors: NodeSet | undefined): void { + function tryDeleteDeclaration(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, deletedAncestors: NodeSet | undefined, checker: TypeChecker, isFixAll: boolean): void { switch (token.kind) { case SyntaxKind.Identifier: - tryDeleteIdentifier(changes, sourceFile, token, deletedAncestors); + tryDeleteIdentifier(changes, sourceFile, token, deletedAncestors, checker, isFixAll); break; case SyntaxKind.PropertyDeclaration: case SyntaxKind.NamespaceImport: @@ -170,7 +174,7 @@ namespace ts.codefix { } } - function tryDeleteIdentifier(changes: textChanges.ChangeTracker, sourceFile: SourceFile, identifier: Identifier, deletedAncestors: NodeSet | undefined): void { + function tryDeleteIdentifier(changes: textChanges.ChangeTracker, sourceFile: SourceFile, identifier: Identifier, deletedAncestors: NodeSet | undefined, checker: TypeChecker, isFixAll: boolean): void { const parent = identifier.parent; switch (parent.kind) { case SyntaxKind.VariableDeclaration: @@ -194,11 +198,8 @@ namespace ts.codefix { break; case SyntaxKind.Parameter: + if (!mayDeleteParameter(parent as ParameterDeclaration, checker, isFixAll)) break; const oldFunction = parent.parent; - if (isSetAccessor(oldFunction)) { - // Setter must have a parameter - break; - } if (isArrowFunction(oldFunction) && oldFunction.parameters.length === 1) { // Lambdas with exactly one parameter are special because, after removal, there @@ -347,4 +348,35 @@ namespace ts.codefix { } } } + + function mayDeleteParameter(p: ParameterDeclaration, checker: TypeChecker, isFixAll: boolean) { + const parent = p.parent; + switch (parent.kind) { + case SyntaxKind.MethodDeclaration: + // Don't remove a parameter if this overrides something + const symbol = checker.getSymbolAtLocation(parent.name)!; + if (isMemberSymbolInBaseType(symbol, checker)) return false; + // falls through + + case SyntaxKind.Constructor: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: { + // Can't remove a non-last parameter. Can remove a parameter in code-fix-all if future parameters are also unused. + const { parameters } = parent; + const index = parameters.indexOf(p); + Debug.assert(index !== -1); + return isFixAll + ? parameters.slice(index + 1).every(p => p.name.kind === SyntaxKind.Identifier && !p.symbol.isReferenced) + : index === parameters.length - 1; + } + + case SyntaxKind.SetAccessor: + // Setter must have a parameter + return false; + + default: + return Debug.failBadSyntaxKind(parent); + } + } } diff --git a/src/services/codefixes/moduleSpecifiers.ts b/src/services/codefixes/moduleSpecifiers.ts index 5279c3cb84f..5a08f7d3dea 100644 --- a/src/services/codefixes/moduleSpecifiers.ts +++ b/src/services/codefixes/moduleSpecifiers.ts @@ -16,15 +16,18 @@ namespace ts.moduleSpecifiers { const getCanonicalFileName = hostGetCanonicalFileName(host); const sourceDirectory = getDirectoryPath(importingSourceFile.fileName); - return getAllModulePaths(program, moduleSymbol.valueDeclaration.getSourceFile()).map(moduleFileName => { - const global = tryGetModuleNameFromAmbientModule(moduleSymbol) - || tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension) - || tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory) - || rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName); - if (global) { - return [global]; - } + const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol); + if (ambient) return [[ambient]]; + const modulePaths = getAllModulePaths(program, moduleSymbol.valueDeclaration.getSourceFile()); + + const global = mapDefined(modulePaths, moduleFileName => + tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension) || + tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory) || + rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName)); + if (global.length) return global.map(g => [g]); + + return modulePaths.map(moduleFileName => { const relativePath = removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), moduleResolutionKind, addJsExtension); if (!baseUrl || preferences.importModuleSpecifierPreference === "relative") { return [relativePath]; @@ -191,11 +194,12 @@ namespace ts.moduleSpecifiers { // Simplify the full file path to something that can be resolved by Node. // If the module could be imported by a directory name, use that directory's name - let moduleSpecifier = getDirectoryOrExtensionlessFileName(moduleFileName); + const moduleSpecifier = getDirectoryOrExtensionlessFileName(moduleFileName); // Get a path that's relative to node_modules or the importing file's path - moduleSpecifier = getNodeResolvablePath(moduleSpecifier); + // if node_modules folder is in this folder or any of its parent folders, no need to keep it. + if (!startsWith(sourceDirectory, moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex))) return undefined; // If the module was found in @types, get the actual Node package name - return getPackageNameFromAtTypesDirectory(moduleSpecifier); + return getPackageNameFromAtTypesDirectory(moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1)); function getDirectoryOrExtensionlessFileName(path: string): string { // If the file is the main module, it can be imported by the package name @@ -224,17 +228,6 @@ namespace ts.moduleSpecifiers { return fullModulePathWithoutExtension; } - - function getNodeResolvablePath(path: string): string { - const basePath = path.substring(0, parts.topLevelNodeModulesIndex); - if (sourceDirectory.indexOf(basePath) === 0) { - // if node_modules folder is in this folder or any of its parent folders, no need to keep it. - return path.substring(parts.topLevelPackageNameIndex + 1); - } - else { - return ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, path, getCanonicalFileName)); - } - } } interface NodeModulePathParts { diff --git a/src/services/completions.ts b/src/services/completions.ts index 45317be065e..522950e87ef 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1320,12 +1320,20 @@ namespace ts.Completions { function getSymbolsFromOtherSourceFileExports(symbols: Symbol[], tokenText: string, target: ScriptTarget): void { const tokenTextLowerCase = tokenText.toLowerCase(); + const seenResolvedModules = createMap(); + codefix.forEachExternalModuleToImportFrom(typeChecker, sourceFile, program.getSourceFiles(), moduleSymbol => { // Perf -- ignore other modules if this is a request for details if (detailsEntryId && detailsEntryId.source && stripQuotes(moduleSymbol.name) !== detailsEntryId.source) { return; } + const resolvedModuleSymbol = typeChecker.resolveExternalModuleSymbol(moduleSymbol); + // resolvedModuleSymbol may be a namespace. A namespace may be `export =` by multiple module declarations, but only keep the first one. + if (!addToSeen(seenResolvedModules, getSymbolId(resolvedModuleSymbol))) { + return; + } + for (let symbol of typeChecker.getExportsOfModule(moduleSymbol)) { // Don't add a completion for a re-export, only for the original. // The actual import fix might end up coming from a re-export -- we don't compute that until getting completion details. @@ -1333,7 +1341,7 @@ namespace ts.Completions { // // If `symbol.parent !== ...`, this comes from an `export * from "foo"` re-export. Those don't create new symbols. // If `some(...)`, this comes from an `export { foo } from "foo"` re-export, which creates a new symbol (thus isn't caught by the first check). - if (typeChecker.getMergedSymbol(symbol.parent!) !== typeChecker.resolveExternalModuleSymbol(moduleSymbol) + if (typeChecker.getMergedSymbol(symbol.parent!) !== resolvedModuleSymbol || some(symbol.declarations, d => isExportSpecifier(d) && !!d.parent.parent.moduleSpecifier)) { continue; } @@ -1478,27 +1486,13 @@ namespace ts.Completions { } function isInStringOrRegularExpressionOrTemplateLiteral(contextToken: Node): boolean { - if (contextToken.kind === SyntaxKind.StringLiteral - || contextToken.kind === SyntaxKind.RegularExpressionLiteral - || isTemplateLiteralKind(contextToken.kind)) { - const start = contextToken.getStart(); - const end = contextToken.getEnd(); - - // To be "in" one of these literals, the position has to be: - // 1. entirely within the token text. - // 2. at the end position of an unterminated token. - // 3. at the end of a regular expression (due to trailing flags like '/foo/g'). - if (start < position && position < end) { - return true; - } - - if (position === end) { - return !!(contextToken).isUnterminated - || contextToken.kind === SyntaxKind.RegularExpressionLiteral; - } - } - - return false; + // To be "in" one of these literals, the position has to be: + // 1. entirely within the token text. + // 2. at the end position of an unterminated token. + // 3. at the end of a regular expression (due to trailing flags like '/foo/g'). + return (isRegularExpressionLiteral(contextToken) || isStringTextContainingNode(contextToken)) && ( + rangeContainsPositionExclusive(createTextRangeFromSpan(createTextSpanFromNode(contextToken)), position) || + position === contextToken.end && (!!contextToken.isUnterminated || isRegularExpressionLiteral(contextToken))); } /** diff --git a/src/services/documentHighlights.ts b/src/services/documentHighlights.ts index cd28f46a841..d4199d80d85 100644 --- a/src/services/documentHighlights.ts +++ b/src/services/documentHighlights.ts @@ -182,7 +182,7 @@ namespace ts.DocumentHighlights { default: // Don't cross function boundaries. // TODO: GH#20090 - return (isFunctionLike(node) && "quit") as false | "quit"; + return isFunctionLike(node) && "quit"; } }); } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index cc13cfd28c4..de1510943c3 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -712,16 +712,23 @@ namespace ts.FindAllReferences.Core { } /** Used as a quick check for whether a symbol is used at all in a file (besides its definition). */ - export function isSymbolReferencedInFile(definition: Identifier, checker: TypeChecker, sourceFile: SourceFile) { + export function isSymbolReferencedInFile(definition: Identifier, checker: TypeChecker, sourceFile: SourceFile): boolean { + return eachSymbolReferenceInFile(definition, checker, sourceFile, () => true) || false; + } + + export function eachSymbolReferenceInFile(definition: Identifier, checker: TypeChecker, sourceFile: SourceFile, cb: (token: Identifier) => T): T | undefined { const symbol = checker.getSymbolAtLocation(definition); - if (!symbol) return true; // Be lenient with invalid code. - return getPossibleSymbolReferenceNodes(sourceFile, symbol.name).some(token => { - if (!isIdentifier(token) || token === definition || token.escapedText !== definition.escapedText) return false; - const referenceSymbol = checker.getSymbolAtLocation(token)!; - return referenceSymbol === symbol + if (!symbol) return undefined; + for (const token of getPossibleSymbolReferenceNodes(sourceFile, symbol.name)) { + if (!isIdentifier(token) || token === definition || token.escapedText !== definition.escapedText) continue; + const referenceSymbol: Symbol = checker.getSymbolAtLocation(token)!; // See GH#19955 for why the type annotation is necessary + if (referenceSymbol === symbol || checker.getShorthandAssignmentValueSymbol(token.parent) === symbol - || isExportSpecifier(token.parent) && getLocalSymbolForExportSpecifier(token, referenceSymbol, token.parent, checker) === symbol; - }); + || isExportSpecifier(token.parent) && getLocalSymbolForExportSpecifier(token, referenceSymbol, token.parent, checker) === symbol) { + const res = cb(token); + if (res) return res; + } + } } function getPossibleSymbolReferenceNodes(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): ReadonlyArray { @@ -1399,34 +1406,6 @@ namespace ts.FindAllReferences.Core { } } - /** - * Find symbol of the given property-name and add the symbol to the given result array - * @param symbol a symbol to start searching for the given propertyName - * @param propertyName a name of property to search for - * @param result an array of symbol of found property symbols - * @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisiting of the same symbol. - * The value of previousIterationSymbol is undefined when the function is first called. - */ - function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, checker: TypeChecker, cb: (symbol: Symbol) => T | undefined): T | undefined { - const seen = createMap(); - return recur(symbol); - - function recur(symbol: Symbol): T | undefined { - // Use `addToSeen` to ensure we don't infinitely recurse in this situation: - // interface C extends C { - // /*findRef*/propName: string; - // } - if (!(symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) || !addToSeen(seen, getSymbolId(symbol))) return; - - return firstDefined(symbol.declarations, declaration => firstDefined(getAllSuperTypeNodes(declaration), typeReference => { - const type = checker.getTypeAtLocation(typeReference); - const propertySymbol = type && type.symbol && checker.getPropertyOfType(type, propertyName); - // Visit the typeReference as well to see if it directly or indirectly uses that property - return propertySymbol && (firstDefined(checker.getRootSymbols(propertySymbol), cb) || recur(type!.symbol)); - })); - } - } - function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): Symbol | undefined { const { checker } = state; return forEachRelatedSymbol(referenceSymbol, referenceLocation, checker, diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 59251fe38b8..bfd371d1154 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -243,7 +243,7 @@ namespace ts.JsDoc { } const tokenAtPos = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); - const tokenStart = tokenAtPos.getStart(); + const tokenStart = tokenAtPos.getStart(sourceFile); if (!tokenAtPos || tokenStart < position) { return undefined; } @@ -253,7 +253,7 @@ namespace ts.JsDoc { return undefined; } const { commentOwner, parameters } = commentOwnerInfo; - if (commentOwner.getStart() < position) { + if (commentOwner.getStart(sourceFile) < position) { return undefined; } @@ -268,19 +268,6 @@ namespace ts.JsDoc { // replace non-whitespace characters in prefix with spaces. const indentationStr = sourceFile.text.substr(lineStart, posLineAndChar.character).replace(/\S/i, () => " "); - const isJavaScriptFile = hasJavaScriptFileExtension(sourceFile.fileName); - - let docParams = ""; - for (let i = 0; i < parameters.length; i++) { - const currentName = parameters[i].name; - const paramName = currentName.kind === SyntaxKind.Identifier ? currentName.escapedText : "param" + i; - if (isJavaScriptFile) { - docParams += `${indentationStr} * @param {any} ${paramName}${newLine}`; - } - else { - docParams += `${indentationStr} * @param ${paramName}${newLine}`; - } - } // A doc comment consists of the following // * The opening comment line @@ -293,13 +280,21 @@ namespace ts.JsDoc { indentationStr + " * "; const result = preamble + newLine + - docParams + + parameterDocComments(parameters, hasJavaScriptFileExtension(sourceFile.fileName), indentationStr, newLine) + indentationStr + " */" + (tokenStart === position ? newLine + indentationStr : ""); return { newText: result, caretOffset: preamble.length }; } + function parameterDocComments(parameters: ReadonlyArray, isJavaScriptFile: boolean, indentationStr: string, newLine: string): string { + return parameters.map(({ name, dotDotDotToken }, i) => { + const paramName = name.kind === SyntaxKind.Identifier ? name.text : "param" + i; + const type = isJavaScriptFile ? (dotDotDotToken ? "{...any} " : "{any} ") : ""; + return `${indentationStr} * @param ${type}${paramName}${newLine}`; + }).join(""); + } + interface CommentOwnerInfo { readonly commentOwner: Node; readonly parameters?: ReadonlyArray; diff --git a/src/services/refactors/convertImport.ts b/src/services/refactors/convertImport.ts new file mode 100644 index 00000000000..bdd3e7f4a96 --- /dev/null +++ b/src/services/refactors/convertImport.ts @@ -0,0 +1,130 @@ +/* @internal */ +namespace ts.refactor.generateGetAccessorAndSetAccessor { + const refactorName = "Convert import"; + const actionNameNamespaceToNamed = "Convert namespace import to named imports"; + const actionNameNamedToNamespace = "Convert named imports to namespace import"; + registerRefactor(refactorName, { + getAvailableActions(context): ApplicableRefactorInfo[] | undefined { + const i = getImportToConvert(context); + if (!i) return undefined; + const description = i.kind === SyntaxKind.NamespaceImport ? Diagnostics.Convert_namespace_import_to_named_imports.message : Diagnostics.Convert_named_imports_to_namespace_import.message; + const actionName = i.kind === SyntaxKind.NamespaceImport ? actionNameNamespaceToNamed : actionNameNamedToNamespace; + return [{ name: refactorName, description, actions: [{ name: actionName, description }] }]; + }, + getEditsForAction(context, actionName): RefactorEditInfo { + Debug.assert(actionName === actionNameNamespaceToNamed || actionName === actionNameNamedToNamespace); + const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, t, Debug.assertDefined(getImportToConvert(context)))); + return { edits, renameFilename: undefined, renameLocation: undefined }; + } + }); + + // Can convert imports of the form `import * as m from "m";` or `import d, { x, y } from "m";`. + function getImportToConvert(context: RefactorContext): NamedImportBindings | undefined { + const { file } = context; + const span = getRefactorContextSpan(context); + const token = getTokenAtPosition(file, span.start, /*includeJsDocComment*/ false); + const importDecl = getParentNodeInSpan(token, file, span); + if (!importDecl || !isImportDeclaration(importDecl)) return undefined; + const { importClause } = importDecl; + return importClause && importClause.namedBindings; + } + + function doChange(sourceFile: SourceFile, program: Program, changes: textChanges.ChangeTracker, toConvert: NamedImportBindings): void { + const checker = program.getTypeChecker(); + if (toConvert.kind === SyntaxKind.NamespaceImport) { + doChangeNamespaceToNamed(sourceFile, checker, changes, toConvert, getAllowSyntheticDefaultImports(program.getCompilerOptions())); + } + else { + doChangeNamedToNamespace(sourceFile, checker, changes, toConvert); + } + } + + function doChangeNamespaceToNamed(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, toConvert: NamespaceImport, allowSyntheticDefaultImports: boolean): void { + let usedAsNamespaceOrDefault = false; + + const nodesToReplace: PropertyAccessExpression[] = []; + const conflictingNames = createMap(); + + FindAllReferences.Core.eachSymbolReferenceInFile(toConvert.name, checker, sourceFile, id => { + if (!isPropertyAccessExpression(id.parent)) { + usedAsNamespaceOrDefault = true; + } + else { + const parent = cast(id.parent, isPropertyAccessExpression); + const exportName = parent.name.text; + if (checker.resolveName(exportName, id, SymbolFlags.All, /*excludeGlobals*/ true)) { + conflictingNames.set(exportName, true); + } + Debug.assert(parent.expression === id); + nodesToReplace.push(parent); + } + }); + + // We may need to change `mod.x` to `_x` to avoid a name conflict. + const exportNameToImportName = createMap(); + + for (const propertyAccess of nodesToReplace) { + const exportName = propertyAccess.name.text; + let importName = exportNameToImportName.get(exportName); + if (importName === undefined) { + exportNameToImportName.set(exportName, importName = conflictingNames.has(exportName) ? getUniqueName(exportName, sourceFile) : exportName); + } + changes.replaceNode(sourceFile, propertyAccess, createIdentifier(importName)); + } + + const importSpecifiers: ImportSpecifier[] = []; + exportNameToImportName.forEach((name, propertyName) => { + importSpecifiers.push(createImportSpecifier(name === propertyName ? undefined : createIdentifier(propertyName), createIdentifier(name))); + }); + + const importDecl = toConvert.parent.parent; + if (usedAsNamespaceOrDefault && !allowSyntheticDefaultImports) { + // Need to leave the namespace import alone + changes.insertNodeAfter(sourceFile, importDecl, updateImport(importDecl, /*defaultImportName*/ undefined, importSpecifiers)); + } + else { + changes.replaceNode(sourceFile, importDecl, updateImport(importDecl, usedAsNamespaceOrDefault ? createIdentifier(toConvert.name.text) : undefined, importSpecifiers)); + } + } + + function doChangeNamedToNamespace(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, toConvert: NamedImports): void { + const importDecl = toConvert.parent.parent; + const { moduleSpecifier } = importDecl; + + const preferredName = moduleSpecifier && isStringLiteral(moduleSpecifier) ? codefix.moduleSpecifierToValidIdentifier(moduleSpecifier.text, ScriptTarget.ESNext) : "module"; + const namespaceNameConflicts = toConvert.elements.some(element => + FindAllReferences.Core.eachSymbolReferenceInFile(element.name, checker, sourceFile, id => + !!checker.resolveName(preferredName, id, SymbolFlags.All, /*excludeGlobals*/ true)) || false); + const namespaceImportName = namespaceNameConflicts ? getUniqueName(preferredName, sourceFile) : preferredName; + + const neededNamedImports: ImportSpecifier[] = []; + + for (const element of toConvert.elements) { + const propertyName = (element.propertyName || element.name).text; + FindAllReferences.Core.eachSymbolReferenceInFile(element.name, checker, sourceFile, id => { + const access = createPropertyAccess(createIdentifier(namespaceImportName), propertyName); + if (isShorthandPropertyAssignment(id.parent)) { + changes.replaceNode(sourceFile, id.parent, createPropertyAssignment(id.text, access)); + } + else if (isExportSpecifier(id.parent) && !id.parent.propertyName) { + if (!neededNamedImports.some(n => n.name === element.name)) { + neededNamedImports.push(createImportSpecifier(element.propertyName && createIdentifier(element.propertyName.text), createIdentifier(element.name.text))); + } + } + else { + changes.replaceNode(sourceFile, id, access); + } + }); + } + + changes.replaceNode(sourceFile, toConvert, createNamespaceImport(createIdentifier(namespaceImportName))); + if (neededNamedImports.length) { + changes.insertNodeAfter(sourceFile, toConvert.parent.parent, updateImport(importDecl, /*defaultImportName*/ undefined, neededNamedImports)); + } + } + + function updateImport(old: ImportDeclaration, defaultImportName: Identifier | undefined, elements: ReadonlyArray | undefined): ImportDeclaration { + return createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, + createImportClause(defaultImportName, elements && elements.length ? createNamedImports(elements) : undefined), old.moduleSpecifier); + } +} diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 073f3badcd2..3f2794e439d 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -718,7 +718,7 @@ namespace ts.refactor.extractSymbol { // Make a unique name for the extracted function const file = scope.getSourceFile(); - const functionNameText = getUniqueName(isClassLike(scope) ? "newMethod" : "newFunction", file.text); + const functionNameText = getUniqueName(isClassLike(scope) ? "newMethod" : "newFunction", file); const isJS = isInJavaScriptFile(scope); const functionName = createIdentifier(functionNameText); @@ -1005,7 +1005,7 @@ namespace ts.refactor.extractSymbol { // Make a unique name for the extracted variable const file = scope.getSourceFile(); - const localNameText = getUniqueName(isClassLike(scope) ? "newProperty" : "newLocal", file.text); + const localNameText = getUniqueName(isClassLike(scope) ? "newProperty" : "newLocal", file); const isJS = isInJavaScriptFile(scope); const variableType = isJS || !checker.isContextSensitive(node) @@ -1744,23 +1744,6 @@ namespace ts.refactor.extractSymbol { } } - function getParentNodeInSpan(node: Node | undefined, file: SourceFile, span: TextSpan): Node | undefined { - if (!node) return undefined; - - while (node.parent) { - if (isSourceFile(node.parent) || !spanContainsNode(span, node.parent, file)) { - return node; - } - - node = node.parent; - } - } - - function spanContainsNode(span: TextSpan, node: Node, file: SourceFile): boolean { - return textSpanContainsPosition(span, node.getStart(file)) && - node.getEnd() <= textSpanEnd(span); - } - /** * Computes whether or not a node represents an expression in a position where it could * be extracted. diff --git a/src/services/refactors/generateGetAccessorAndSetAccessor.ts b/src/services/refactors/generateGetAccessorAndSetAccessor.ts index 07104f8e620..2e4f11c4b27 100644 --- a/src/services/refactors/generateGetAccessorAndSetAccessor.ts +++ b/src/services/refactors/generateGetAccessorAndSetAccessor.ts @@ -129,8 +129,8 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor { const name = declaration.name.text; const startWithUnderscore = startsWithUnderscore(name); - const fieldName = createPropertyName(startWithUnderscore ? name : getUniqueName(`_${name}`, file.text), declaration.name); - const accessorName = createPropertyName(startWithUnderscore ? getUniqueName(name.substring(1), file.text) : name, declaration.name); + const fieldName = createPropertyName(startWithUnderscore ? name : getUniqueName(`_${name}`, file), declaration.name); + const accessorName = createPropertyName(startWithUnderscore ? getUniqueName(name.substring(1), file) : name, declaration.name); return { isStatic: hasStaticModifier(declaration), isReadonly: hasReadonlyModifier(declaration), diff --git a/src/services/refactors/moveToNewFile.ts b/src/services/refactors/moveToNewFile.ts index d04588e01d5..48e361c1b01 100644 --- a/src/services/refactors/moveToNewFile.ts +++ b/src/services/refactors/moveToNewFile.ts @@ -15,7 +15,8 @@ namespace ts.refactor { } }); - function getRangeToMove(context: RefactorContext): ReadonlyArray | undefined { + interface RangeToMove { readonly toMove: ReadonlyArray; readonly afterLast: Statement | undefined; } + function getRangeToMove(context: RefactorContext): RangeToMove | undefined { const { file } = context; const range = createTextRangeFromSpan(getRefactorContextSpan(context)); const { statements } = file; @@ -25,7 +26,7 @@ namespace ts.refactor { const startStatement = statements[startNodeIndex]; if (isNamedDeclaration(startStatement) && startStatement.name && rangeContainsRange(startStatement.name, range)) { - return [statements[startNodeIndex]]; + return { toMove: [statements[startNodeIndex]], afterLast: statements[startNodeIndex + 1] }; } // Can't only partially include the start node or be partially into the next node @@ -34,7 +35,10 @@ namespace ts.refactor { // Can't be partially into the next node if (afterEndNodeIndex !== -1 && (afterEndNodeIndex === 0 || statements[afterEndNodeIndex].getStart(file) < range.end)) return undefined; - return statements.slice(startNodeIndex, afterEndNodeIndex === -1 ? statements.length : afterEndNodeIndex); + return { + toMove: statements.slice(startNodeIndex, afterEndNodeIndex === -1 ? statements.length : afterEndNodeIndex), + afterLast: afterEndNodeIndex === -1 ? undefined : statements[afterEndNodeIndex], + }; } function doChange(oldFile: SourceFile, program: Program, toMove: ToMove, changes: textChanges.ChangeTracker, host: LanguageServiceHost, preferences: UserPreferences): void { @@ -47,14 +51,14 @@ namespace ts.refactor { const newFileNameWithExtension = newModuleName + extension; // If previous file was global, this is easy. - changes.createNewFile(oldFile, combinePaths(currentDirectory, newFileNameWithExtension), getNewStatements(oldFile, usage, changes, toMove, program, newModuleName, preferences)); + changes.createNewFile(oldFile, combinePaths(currentDirectory, newFileNameWithExtension), getNewStatementsAndRemoveFromOldFile(oldFile, usage, changes, toMove, program, newModuleName, preferences)); addNewFileToTsconfig(program, changes, oldFile.fileName, newFileNameWithExtension, hostGetCanonicalFileName(host)); } interface StatementRange { readonly first: Statement; - readonly last: Statement; + readonly afterLast: Statement | undefined; } interface ToMove { readonly all: ReadonlyArray; @@ -67,9 +71,10 @@ namespace ts.refactor { if (rangeToMove === undefined) return undefined; const all: Statement[] = []; const ranges: StatementRange[] = []; - getRangesWhere(rangeToMove, s => !isPureImport(s), (start, afterEnd) => { - for (let i = start; i < afterEnd; i++) all.push(rangeToMove[i]); - ranges.push({ first: rangeToMove[start], last: rangeToMove[afterEnd - 1] }); + const { toMove, afterLast } = rangeToMove; + getRangesWhere(toMove, s => !isPureImport(s), (start, afterEndIndex) => { + for (let i = start; i < afterEndIndex; i++) all.push(toMove[i]); + ranges.push({ first: toMove[start], afterLast }); }); return all.length === 0 ? undefined : { all, ranges }; } @@ -102,7 +107,7 @@ namespace ts.refactor { } } - function getNewStatements( + function getNewStatementsAndRemoveFromOldFile( oldFile: SourceFile, usage: UsageInfo, changes: textChanges.ChangeTracker, toMove: ToMove, program: Program, newModuleName: string, preferences: UserPreferences, ): ReadonlyArray { const checker = program.getTypeChecker(); @@ -130,8 +135,8 @@ namespace ts.refactor { } function deleteMovedStatements(sourceFile: SourceFile, moved: ReadonlyArray, changes: textChanges.ChangeTracker) { - for (const { first, last } of moved) { - changes.deleteNodeRange(sourceFile, first, last); + for (const { first, afterLast } of moved) { + changes.deleteNodeRangeExcludingEnd(sourceFile, first, afterLast); } } diff --git a/src/services/rename.ts b/src/services/rename.ts index efebe72d50f..ab83baf1676 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -21,39 +21,31 @@ namespace ts.Rename { function getRenameInfoForNode(node: Node, typeChecker: TypeChecker, sourceFile: SourceFile, isDefinedInLibraryFile: (declaration: Node) => boolean): RenameInfo | undefined { const symbol = typeChecker.getSymbolAtLocation(node); - + if (!symbol) return; // Only allow a symbol to be renamed if it actually has at least one declaration. - if (symbol) { - const { declarations } = symbol; - if (declarations && declarations.length > 0) { - // Disallow rename for elements that are defined in the standard TypeScript library. - if (declarations.some(isDefinedInLibraryFile)) { - return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library); - } + const { declarations } = symbol; + if (!declarations || declarations.length === 0) return; - // Cannot rename `default` as in `import { default as foo } from "./someModule"; - if (isIdentifier(node) && node.originalKeywordKind === SyntaxKind.DefaultKeyword && symbol.parent!.flags & SymbolFlags.Module) { - return undefined; - } - - // Can't rename a module name. - if (isStringLiteralLike(node) && tryGetImportFromModuleSpecifier(node)) return undefined; - - const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node); - const specifierName = (isImportOrExportSpecifierName(node) || isStringOrNumericLiteral(node) && node.parent.kind === SyntaxKind.ComputedPropertyName) - ? stripQuotes(getTextOfIdentifierOrLiteral(node)) - : undefined; - const displayName = specifierName || typeChecker.symbolToString(symbol); - const fullDisplayName = specifierName || typeChecker.getFullyQualifiedName(symbol); - return getRenameInfoSuccess(displayName, fullDisplayName, kind, SymbolDisplay.getSymbolModifiers(symbol), node, sourceFile); - } + // Disallow rename for elements that are defined in the standard TypeScript library. + if (declarations.some(isDefinedInLibraryFile)) { + return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library); } - else if (isStringLiteral(node)) { - if (isDefinedInLibraryFile(node)) { - return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library); - } - return getRenameInfoSuccess(node.text, node.text, ScriptElementKind.variableElement, ScriptElementKindModifier.none, node, sourceFile); + + // Cannot rename `default` as in `import { default as foo } from "./someModule"; + if (isIdentifier(node) && node.originalKeywordKind === SyntaxKind.DefaultKeyword && symbol.parent!.flags & SymbolFlags.Module) { + return undefined; } + + // Can't rename a module name. + if (isStringLiteralLike(node) && tryGetImportFromModuleSpecifier(node)) return undefined; + + const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node); + const specifierName = (isImportOrExportSpecifierName(node) || isStringOrNumericLiteral(node) && node.parent.kind === SyntaxKind.ComputedPropertyName) + ? stripQuotes(getTextOfIdentifierOrLiteral(node)) + : undefined; + const displayName = specifierName || typeChecker.symbolToString(symbol); + const fullDisplayName = specifierName || typeChecker.getFullyQualifiedName(symbol); + return getRenameInfoSuccess(displayName, fullDisplayName, kind, SymbolDisplay.getSymbolModifiers(symbol), node, sourceFile); } function getRenameInfoSuccess(displayName: string, fullDisplayName: string, kind: ScriptElementKind, kindModifiers: string, node: Node, sourceFile: SourceFile): RenameInfo { diff --git a/src/services/services.ts b/src/services/services.ts index dcea57b7159..441cb5a8ebd 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1735,17 +1735,9 @@ namespace ts { synchronizeHostData(); // Exclude default library when renaming as commonly user don't want to change that file. - let sourceFiles: SourceFile[] = []; - if (options && options.isForRename) { - for (const sourceFile of program.getSourceFiles()) { - if (!program.isSourceFileDefaultLibrary(sourceFile)) { - sourceFiles.push(sourceFile); - } - } - } - else { - sourceFiles = program.getSourceFiles().slice(); - } + const sourceFiles = options && options.isForRename + ? program.getSourceFiles().filter(sourceFile => !program.isSourceFileDefaultLibrary(sourceFile)) + : program.getSourceFiles(); return FindAllReferences.findReferencedEntries(program, cancellationToken, sourceFiles, getValidSourceFile(fileName), position, options); } diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 5fcf3e4866b..94f95641fed 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -161,7 +161,7 @@ namespace ts.SignatureHelp { else if (isNoSubstitutionTemplateLiteral(node) && isTaggedTemplateExpression(parent)) { // Check if we're actually inside the template; // otherwise we'll fall out and return undefined. - if (isInsideTemplateLiteral(node, position)) { + if (isInsideTemplateLiteral(node, position, sourceFile)) { return getArgumentListInfoForTemplate(parent, /*argumentIndex*/ 0, sourceFile); } } @@ -170,7 +170,7 @@ namespace ts.SignatureHelp { const tagExpression = templateExpression.parent; Debug.assert(templateExpression.kind === SyntaxKind.TemplateExpression); - const argumentIndex = isInsideTemplateLiteral(node, position) ? 0 : 1; + const argumentIndex = isInsideTemplateLiteral(node, position, sourceFile) ? 0 : 1; return getArgumentListInfoForTemplate(tagExpression, argumentIndex, sourceFile); } @@ -179,12 +179,12 @@ namespace ts.SignatureHelp { const tagExpression = parent.parent.parent; // If we're just after a template tail, don't show signature help. - if (node.kind === SyntaxKind.TemplateTail && !isInsideTemplateLiteral(node, position)) { + if (isTemplateTail(node) && !isInsideTemplateLiteral(node, position, sourceFile)) { return undefined; } const spanIndex = templateSpan.parent.templateSpans.indexOf(templateSpan); - const argumentIndex = getArgumentIndexForTemplatePiece(spanIndex, node, position); + const argumentIndex = getArgumentIndexForTemplatePiece(spanIndex, node, position, sourceFile); return getArgumentListInfoForTemplate(tagExpression, argumentIndex, sourceFile); } @@ -266,7 +266,7 @@ namespace ts.SignatureHelp { // spanIndex is either the index for a given template span. // This does not give appropriate results for a NoSubstitutionTemplateLiteral - function getArgumentIndexForTemplatePiece(spanIndex: number, node: Node, position: number): number { + function getArgumentIndexForTemplatePiece(spanIndex: number, node: Node, position: number, sourceFile: SourceFile): number { // Because the TemplateStringsArray is the first argument, we have to offset each substitution expression by 1. // There are three cases we can encounter: // 1. We are precisely in the template literal (argIndex = 0). @@ -281,8 +281,8 @@ namespace ts.SignatureHelp { // Case: 1 1 3 2 1 3 2 2 1 // tslint:enable no-double-space Debug.assert(position >= node.getStart(), "Assumed 'position' could not occur before node."); - if (isTemplateLiteralKind(node.kind)) { - if (isInsideTemplateLiteral(node, position)) { + if (isTemplateLiteralToken(node)) { + if (isInsideTemplateLiteral(node, position, sourceFile)) { return 0; } return spanIndex + 2; diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index af32b88e9a1..528ec8268b2 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -248,6 +248,12 @@ namespace ts.textChanges { return this; } + public deleteNodeRangeExcludingEnd(sourceFile: SourceFile, startNode: Node, afterEndNode: Node | undefined, options: ConfigurableStartEnd = {}): void { + const startPosition = getAdjustedStartPosition(sourceFile, startNode, options, Position.FullStart); + const endPosition = afterEndNode === undefined ? sourceFile.text.length : getAdjustedStartPosition(sourceFile, afterEndNode, options, Position.FullStart); + this.deleteRange(sourceFile, { pos: startPosition, end: endPosition }); + } + public deleteNodeInList(sourceFile: SourceFile, node: Node) { const containingList = formatting.SmartIndenter.getContainingList(node, sourceFile); if (!containingList) { diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 2aabfdcd6a3..7d6687fb987 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -113,6 +113,7 @@ "codefixes/useDefaultImport.ts", "codefixes/fixAddModuleReferTypeMissingTypeof.ts", "codefixes/convertToMappedObjectType.ts", + "refactors/convertImport.ts", "refactors/extractSymbol.ts", "refactors/generateGetAccessorAndSetAccessor.ts", "refactors/moveToNewFile.ts", diff --git a/src/services/utilities.ts b/src/services/utilities.ts index de577ec5946..fbccd72c2aa 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -423,6 +423,10 @@ namespace ts { return r.pos <= pos && pos <= r.end; } + export function rangeContainsPositionExclusive(r: TextRange, pos: number) { + return r.pos < pos && pos < r.end; + } + export function startEndContainsRange(start: number, end: number, range: TextRange): boolean { return start <= range.pos && end >= range.end; } @@ -830,7 +834,7 @@ namespace ts { export function isInString(sourceFile: SourceFile, position: number, previousToken = findPrecedingToken(position, sourceFile)): boolean { if (previousToken && isStringTextContainingNode(previousToken)) { - const start = previousToken.getStart(); + const start = previousToken.getStart(sourceFile); const end = previousToken.getEnd(); // To be "in" one of these literals, the position has to be: @@ -1093,9 +1097,9 @@ namespace ts { return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation; } - export function isInsideTemplateLiteral(node: LiteralExpression | TemplateHead, position: number) { + export function isInsideTemplateLiteral(node: TemplateLiteralToken, position: number, sourceFile: SourceFile): boolean { return isTemplateLiteralKind(node.kind) - && (node.getStart() < position && position < node.getEnd()) || (!!node.isUnterminated && position === node.getEnd()); + && (node.getStart(sourceFile) < position && position < node.end) || (!!node.isUnterminated && position === node.end); } export function isAccessibilityModifier(kind: SyntaxKind) { @@ -1293,6 +1297,38 @@ namespace ts { return propSymbol; } + /** + * Find symbol of the given property-name and add the symbol to the given result array + * @param symbol a symbol to start searching for the given propertyName + * @param propertyName a name of property to search for + * @param result an array of symbol of found property symbols + * @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisiting of the same symbol. + * The value of previousIterationSymbol is undefined when the function is first called. + */ + export function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, checker: TypeChecker, cb: (symbol: Symbol) => T | undefined): T | undefined { + const seen = createMap(); + return recur(symbol); + + function recur(symbol: Symbol): T | undefined { + // Use `addToSeen` to ensure we don't infinitely recurse in this situation: + // interface C extends C { + // /*findRef*/propName: string; + // } + if (!(symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) || !addToSeen(seen, getSymbolId(symbol))) return; + + return firstDefined(symbol.declarations, declaration => firstDefined(getAllSuperTypeNodes(declaration), typeReference => { + const type = checker.getTypeAtLocation(typeReference); + const propertySymbol = type && type.symbol && checker.getPropertyOfType(type, propertyName); + // Visit the typeReference as well to see if it directly or indirectly uses that property + return type && propertySymbol && (firstDefined(checker.getRootSymbols(propertySymbol), cb) || recur(type.symbol)); + })); + } + } + + export function isMemberSymbolInBaseType(memberSymbol: Symbol, checker: TypeChecker): boolean { + return getPropertySymbolsFromBaseTypes(memberSymbol.parent!, memberSymbol.name, checker, _ => true) || false; + } + export class NodeSet { private map = createMap(); @@ -1309,6 +1345,23 @@ namespace ts { return forEachEntry(this.map, pred) || false; } } + + export function getParentNodeInSpan(node: Node | undefined, file: SourceFile, span: TextSpan): Node | undefined { + if (!node) return undefined; + + while (node.parent) { + if (isSourceFile(node.parent) || !spanContainsNode(span, node.parent, file)) { + return node; + } + + node = node.parent; + } + } + + function spanContainsNode(span: TextSpan, node: Node, file: SourceFile): boolean { + return textSpanContainsPosition(span, node.getStart(file)) && + node.getEnd() <= textSpanEnd(span); + } } // Display-part writer helpers @@ -1610,9 +1663,9 @@ namespace ts { } /* @internal */ - export function getUniqueName(baseName: string, fileText: string): string { + export function getUniqueName(baseName: string, sourceFile: SourceFile): string { let nameText = baseName; - for (let i = 1; stringContains(fileText, nameText); i++) { + for (let i = 1; !isFileLevelUniqueName(sourceFile, nameText); i++) { nameText = `${baseName}_${i}`; } return nameText; @@ -1631,7 +1684,7 @@ namespace ts { Debug.assert(fileName === renameFilename); for (const change of textChanges) { const { span, newText } = change; - const index = newText.indexOf(name); + const index = indexInTextChange(newText, name); if (index !== -1) { lastPos = span.start + delta + index; @@ -1649,4 +1702,13 @@ namespace ts { Debug.assert(lastPos >= 0); return lastPos; } + + function indexInTextChange(change: string, name: string): number { + if (startsWith(change, name)) return 0; + // Add a " " to avoid references inside words + let idx = change.indexOf(" " + name); + if (idx === -1) idx = change.indexOf("." + name); + if (idx === -1) idx = change.indexOf('"' + name); + return idx === -1 ? -1 : idx + 1; + } } diff --git a/tests/baselines/reference/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.js b/tests/baselines/reference/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.js new file mode 100644 index 00000000000..96a5bfcb068 --- /dev/null +++ b/tests/baselines/reference/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.js @@ -0,0 +1,37 @@ +//// [tests/cases/compiler/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.ts] //// + +//// [color.ts] +interface Color { + c: string; +} +export default Color; +//// [file1.ts] +import Color from "./color"; +export declare function styled(): Color; +//// [file2.ts] +import { styled } from "./file1"; +export const A = styled(); + +//// [color.js] +"use strict"; +exports.__esModule = true; +//// [file1.js] +"use strict"; +exports.__esModule = true; +//// [file2.js] +"use strict"; +exports.__esModule = true; +var file1_1 = require("./file1"); +exports.A = file1_1.styled(); + + +//// [color.d.ts] +interface Color { + c: string; +} +export default Color; +//// [file1.d.ts] +import Color from "./color"; +export declare function styled(): Color; +//// [file2.d.ts] +export declare const A: import("./color").default; diff --git a/tests/baselines/reference/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.symbols b/tests/baselines/reference/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.symbols new file mode 100644 index 00000000000..4b1cd3b370e --- /dev/null +++ b/tests/baselines/reference/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.symbols @@ -0,0 +1,26 @@ +=== tests/cases/compiler/color.ts === +interface Color { +>Color : Symbol(Color, Decl(color.ts, 0, 0)) + + c: string; +>c : Symbol(Color.c, Decl(color.ts, 0, 17)) +} +export default Color; +>Color : Symbol(Color, Decl(color.ts, 0, 0)) + +=== tests/cases/compiler/file1.ts === +import Color from "./color"; +>Color : Symbol(Color, Decl(file1.ts, 0, 6)) + +export declare function styled(): Color; +>styled : Symbol(styled, Decl(file1.ts, 0, 28)) +>Color : Symbol(Color, Decl(file1.ts, 0, 6)) + +=== tests/cases/compiler/file2.ts === +import { styled } from "./file1"; +>styled : Symbol(styled, Decl(file2.ts, 0, 8)) + +export const A = styled(); +>A : Symbol(A, Decl(file2.ts, 1, 12)) +>styled : Symbol(styled, Decl(file2.ts, 0, 8)) + diff --git a/tests/baselines/reference/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.types b/tests/baselines/reference/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.types new file mode 100644 index 00000000000..ffcf611af8c --- /dev/null +++ b/tests/baselines/reference/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.types @@ -0,0 +1,27 @@ +=== tests/cases/compiler/color.ts === +interface Color { +>Color : Color + + c: string; +>c : string +} +export default Color; +>Color : Color + +=== tests/cases/compiler/file1.ts === +import Color from "./color"; +>Color : any + +export declare function styled(): Color; +>styled : () => Color +>Color : Color + +=== tests/cases/compiler/file2.ts === +import { styled } from "./file1"; +>styled : () => import("tests/cases/compiler/color").default + +export const A = styled(); +>A : import("tests/cases/compiler/color").default +>styled() : import("tests/cases/compiler/color").default +>styled : () => import("tests/cases/compiler/color").default + diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 3adc0f014b6..a6657b4d341 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -204,169 +204,170 @@ declare namespace ts { TypeKeyword = 139, UndefinedKeyword = 140, UniqueKeyword = 141, - FromKeyword = 142, - GlobalKeyword = 143, - OfKeyword = 144, - QualifiedName = 145, - ComputedPropertyName = 146, - TypeParameter = 147, - Parameter = 148, - Decorator = 149, - PropertySignature = 150, - PropertyDeclaration = 151, - MethodSignature = 152, - MethodDeclaration = 153, - Constructor = 154, - GetAccessor = 155, - SetAccessor = 156, - CallSignature = 157, - ConstructSignature = 158, - IndexSignature = 159, - TypePredicate = 160, - TypeReference = 161, - FunctionType = 162, - ConstructorType = 163, - TypeQuery = 164, - TypeLiteral = 165, - ArrayType = 166, - TupleType = 167, - UnionType = 168, - IntersectionType = 169, - ConditionalType = 170, - InferType = 171, - ParenthesizedType = 172, - ThisType = 173, - TypeOperator = 174, - IndexedAccessType = 175, - MappedType = 176, - LiteralType = 177, - ImportType = 178, - ObjectBindingPattern = 179, - ArrayBindingPattern = 180, - BindingElement = 181, - ArrayLiteralExpression = 182, - ObjectLiteralExpression = 183, - PropertyAccessExpression = 184, - ElementAccessExpression = 185, - CallExpression = 186, - NewExpression = 187, - TaggedTemplateExpression = 188, - TypeAssertionExpression = 189, - ParenthesizedExpression = 190, - FunctionExpression = 191, - ArrowFunction = 192, - DeleteExpression = 193, - TypeOfExpression = 194, - VoidExpression = 195, - AwaitExpression = 196, - PrefixUnaryExpression = 197, - PostfixUnaryExpression = 198, - BinaryExpression = 199, - ConditionalExpression = 200, - TemplateExpression = 201, - YieldExpression = 202, - SpreadElement = 203, - ClassExpression = 204, - OmittedExpression = 205, - ExpressionWithTypeArguments = 206, - AsExpression = 207, - NonNullExpression = 208, - MetaProperty = 209, - TemplateSpan = 210, - SemicolonClassElement = 211, - Block = 212, - VariableStatement = 213, - EmptyStatement = 214, - ExpressionStatement = 215, - IfStatement = 216, - DoStatement = 217, - WhileStatement = 218, - ForStatement = 219, - ForInStatement = 220, - ForOfStatement = 221, - ContinueStatement = 222, - BreakStatement = 223, - ReturnStatement = 224, - WithStatement = 225, - SwitchStatement = 226, - LabeledStatement = 227, - ThrowStatement = 228, - TryStatement = 229, - DebuggerStatement = 230, - VariableDeclaration = 231, - VariableDeclarationList = 232, - FunctionDeclaration = 233, - ClassDeclaration = 234, - InterfaceDeclaration = 235, - TypeAliasDeclaration = 236, - EnumDeclaration = 237, - ModuleDeclaration = 238, - ModuleBlock = 239, - CaseBlock = 240, - NamespaceExportDeclaration = 241, - ImportEqualsDeclaration = 242, - ImportDeclaration = 243, - ImportClause = 244, - NamespaceImport = 245, - NamedImports = 246, - ImportSpecifier = 247, - ExportAssignment = 248, - ExportDeclaration = 249, - NamedExports = 250, - ExportSpecifier = 251, - MissingDeclaration = 252, - ExternalModuleReference = 253, - JsxElement = 254, - JsxSelfClosingElement = 255, - JsxOpeningElement = 256, - JsxClosingElement = 257, - JsxFragment = 258, - JsxOpeningFragment = 259, - JsxClosingFragment = 260, - JsxAttribute = 261, - JsxAttributes = 262, - JsxSpreadAttribute = 263, - JsxExpression = 264, - CaseClause = 265, - DefaultClause = 266, - HeritageClause = 267, - CatchClause = 268, - PropertyAssignment = 269, - ShorthandPropertyAssignment = 270, - SpreadAssignment = 271, - EnumMember = 272, - SourceFile = 273, - Bundle = 274, - UnparsedSource = 275, - InputFiles = 276, - JSDocTypeExpression = 277, - JSDocAllType = 278, - JSDocUnknownType = 279, - JSDocNullableType = 280, - JSDocNonNullableType = 281, - JSDocOptionalType = 282, - JSDocFunctionType = 283, - JSDocVariadicType = 284, - JSDocComment = 285, - JSDocTypeLiteral = 286, - JSDocSignature = 287, - JSDocTag = 288, - JSDocAugmentsTag = 289, - JSDocClassTag = 290, - JSDocCallbackTag = 291, - JSDocParameterTag = 292, - JSDocReturnTag = 293, - JSDocTypeTag = 294, - JSDocTemplateTag = 295, - JSDocTypedefTag = 296, - JSDocPropertyTag = 297, - SyntaxList = 298, - NotEmittedStatement = 299, - PartiallyEmittedExpression = 300, - CommaListExpression = 301, - MergeDeclarationMarker = 302, - EndOfDeclarationMarker = 303, - Count = 304, + UnknownKeyword = 142, + FromKeyword = 143, + GlobalKeyword = 144, + OfKeyword = 145, + QualifiedName = 146, + ComputedPropertyName = 147, + TypeParameter = 148, + Parameter = 149, + Decorator = 150, + PropertySignature = 151, + PropertyDeclaration = 152, + MethodSignature = 153, + MethodDeclaration = 154, + Constructor = 155, + GetAccessor = 156, + SetAccessor = 157, + CallSignature = 158, + ConstructSignature = 159, + IndexSignature = 160, + TypePredicate = 161, + TypeReference = 162, + FunctionType = 163, + ConstructorType = 164, + TypeQuery = 165, + TypeLiteral = 166, + ArrayType = 167, + TupleType = 168, + UnionType = 169, + IntersectionType = 170, + ConditionalType = 171, + InferType = 172, + ParenthesizedType = 173, + ThisType = 174, + TypeOperator = 175, + IndexedAccessType = 176, + MappedType = 177, + LiteralType = 178, + ImportType = 179, + ObjectBindingPattern = 180, + ArrayBindingPattern = 181, + BindingElement = 182, + ArrayLiteralExpression = 183, + ObjectLiteralExpression = 184, + PropertyAccessExpression = 185, + ElementAccessExpression = 186, + CallExpression = 187, + NewExpression = 188, + TaggedTemplateExpression = 189, + TypeAssertionExpression = 190, + ParenthesizedExpression = 191, + FunctionExpression = 192, + ArrowFunction = 193, + DeleteExpression = 194, + TypeOfExpression = 195, + VoidExpression = 196, + AwaitExpression = 197, + PrefixUnaryExpression = 198, + PostfixUnaryExpression = 199, + BinaryExpression = 200, + ConditionalExpression = 201, + TemplateExpression = 202, + YieldExpression = 203, + SpreadElement = 204, + ClassExpression = 205, + OmittedExpression = 206, + ExpressionWithTypeArguments = 207, + AsExpression = 208, + NonNullExpression = 209, + MetaProperty = 210, + TemplateSpan = 211, + SemicolonClassElement = 212, + Block = 213, + VariableStatement = 214, + EmptyStatement = 215, + ExpressionStatement = 216, + IfStatement = 217, + DoStatement = 218, + WhileStatement = 219, + ForStatement = 220, + ForInStatement = 221, + ForOfStatement = 222, + ContinueStatement = 223, + BreakStatement = 224, + ReturnStatement = 225, + WithStatement = 226, + SwitchStatement = 227, + LabeledStatement = 228, + ThrowStatement = 229, + TryStatement = 230, + DebuggerStatement = 231, + VariableDeclaration = 232, + VariableDeclarationList = 233, + FunctionDeclaration = 234, + ClassDeclaration = 235, + InterfaceDeclaration = 236, + TypeAliasDeclaration = 237, + EnumDeclaration = 238, + ModuleDeclaration = 239, + ModuleBlock = 240, + CaseBlock = 241, + NamespaceExportDeclaration = 242, + ImportEqualsDeclaration = 243, + ImportDeclaration = 244, + ImportClause = 245, + NamespaceImport = 246, + NamedImports = 247, + ImportSpecifier = 248, + ExportAssignment = 249, + ExportDeclaration = 250, + NamedExports = 251, + ExportSpecifier = 252, + MissingDeclaration = 253, + ExternalModuleReference = 254, + JsxElement = 255, + JsxSelfClosingElement = 256, + JsxOpeningElement = 257, + JsxClosingElement = 258, + JsxFragment = 259, + JsxOpeningFragment = 260, + JsxClosingFragment = 261, + JsxAttribute = 262, + JsxAttributes = 263, + JsxSpreadAttribute = 264, + JsxExpression = 265, + CaseClause = 266, + DefaultClause = 267, + HeritageClause = 268, + CatchClause = 269, + PropertyAssignment = 270, + ShorthandPropertyAssignment = 271, + SpreadAssignment = 272, + EnumMember = 273, + SourceFile = 274, + Bundle = 275, + UnparsedSource = 276, + InputFiles = 277, + JSDocTypeExpression = 278, + JSDocAllType = 279, + JSDocUnknownType = 280, + JSDocNullableType = 281, + JSDocNonNullableType = 282, + JSDocOptionalType = 283, + JSDocFunctionType = 284, + JSDocVariadicType = 285, + JSDocComment = 286, + JSDocTypeLiteral = 287, + JSDocSignature = 288, + JSDocTag = 289, + JSDocAugmentsTag = 290, + JSDocClassTag = 291, + JSDocCallbackTag = 292, + JSDocParameterTag = 293, + JSDocReturnTag = 294, + JSDocTypeTag = 295, + JSDocTemplateTag = 296, + JSDocTypedefTag = 297, + JSDocPropertyTag = 298, + SyntaxList = 299, + NotEmittedStatement = 300, + PartiallyEmittedExpression = 301, + CommaListExpression = 302, + MergeDeclarationMarker = 303, + EndOfDeclarationMarker = 304, + Count = 305, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, @@ -374,15 +375,15 @@ declare namespace ts { FirstReservedWord = 72, LastReservedWord = 107, FirstKeyword = 72, - LastKeyword = 144, + LastKeyword = 145, FirstFutureReservedWord = 108, LastFutureReservedWord = 116, - FirstTypeNode = 160, - LastTypeNode = 178, + FirstTypeNode = 161, + LastTypeNode = 179, FirstPunctuation = 17, LastPunctuation = 70, FirstToken = 0, - LastToken = 144, + LastToken = 145, FirstTriviaToken = 2, LastTriviaToken = 7, FirstLiteralToken = 8, @@ -391,11 +392,11 @@ declare namespace ts { LastTemplateToken = 16, FirstBinaryOperator = 27, LastBinaryOperator = 70, - FirstNode = 145, - FirstJSDocNode = 277, - LastJSDocNode = 297, - FirstJSDocTagNode = 288, - LastJSDocTagNode = 297 + FirstNode = 146, + FirstJSDocNode = 278, + LastJSDocNode = 298, + FirstJSDocTagNode = 289, + LastJSDocTagNode = 298 } enum NodeFlags { None = 0, @@ -702,7 +703,7 @@ declare namespace ts { _typeNodeBrand: any; } interface KeywordTypeNode extends TypeNode { - kind: SyntaxKind.AnyKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.StringKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.VoidKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.NullKeyword | SyntaxKind.NeverKeyword; + kind: SyntaxKind.AnyKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.StringKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.VoidKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.NullKeyword | SyntaxKind.NeverKeyword; } interface ImportTypeNode extends NodeWithTypeArguments { kind: SyntaxKind.ImportType; @@ -2128,48 +2129,49 @@ declare namespace ts { type SymbolTable = UnderscoreEscapedMap; enum TypeFlags { Any = 1, - String = 2, - Number = 4, - Boolean = 8, - Enum = 16, - StringLiteral = 32, - NumberLiteral = 64, - BooleanLiteral = 128, - EnumLiteral = 256, - ESSymbol = 512, - UniqueESSymbol = 1024, - Void = 2048, - Undefined = 4096, - Null = 8192, - Never = 16384, - TypeParameter = 32768, - Object = 65536, - Union = 131072, - Intersection = 262144, - Index = 524288, - IndexedAccess = 1048576, - Conditional = 2097152, - Substitution = 4194304, - NonPrimitive = 134217728, - Literal = 224, - Unit = 13536, - StringOrNumberLiteral = 96, - PossiblyFalsy = 14574, - StringLike = 34, - NumberLike = 84, - BooleanLike = 136, - EnumLike = 272, - ESSymbolLike = 1536, - VoidLike = 6144, - UnionOrIntersection = 393216, - StructuredType = 458752, - TypeVariable = 1081344, - InstantiableNonPrimitive = 7372800, - InstantiablePrimitive = 524288, - Instantiable = 7897088, - StructuredOrInstantiable = 8355840, - Narrowable = 142575359, - NotUnionOrUnit = 134283777 + Unknown = 2, + String = 4, + Number = 8, + Boolean = 16, + Enum = 32, + StringLiteral = 64, + NumberLiteral = 128, + BooleanLiteral = 256, + EnumLiteral = 512, + ESSymbol = 1024, + UniqueESSymbol = 2048, + Void = 4096, + Undefined = 8192, + Null = 16384, + Never = 32768, + TypeParameter = 65536, + Object = 131072, + Union = 262144, + Intersection = 524288, + Index = 1048576, + IndexedAccess = 2097152, + Conditional = 4194304, + Substitution = 8388608, + NonPrimitive = 16777216, + Literal = 448, + Unit = 27072, + StringOrNumberLiteral = 192, + PossiblyFalsy = 29148, + StringLike = 68, + NumberLike = 168, + BooleanLike = 272, + EnumLike = 544, + ESSymbolLike = 3072, + VoidLike = 12288, + UnionOrIntersection = 786432, + StructuredType = 917504, + TypeVariable = 2162688, + InstantiableNonPrimitive = 14745600, + InstantiablePrimitive = 1048576, + Instantiable = 15794176, + StructuredOrInstantiable = 16711680, + Narrowable = 33492479, + NotUnionOrUnit = 16909315 } type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; interface Type { @@ -3399,8 +3401,10 @@ declare namespace ts { */ function isToken(n: Node): boolean; function isLiteralExpression(node: Node): node is LiteralExpression; + type TemplateLiteralToken = NoSubstitutionTemplateLiteral | TemplateHead | TemplateMiddle | TemplateTail; + function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken; function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail; - function isStringTextContainingNode(node: Node): boolean; + function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken; function isModifier(node: Node): node is Modifier; function isEntityName(node: Node): node is EntityName; function isPropertyName(node: Node): node is PropertyName; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 70f2e0d0cdb..d71bb5117ba 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -204,169 +204,170 @@ declare namespace ts { TypeKeyword = 139, UndefinedKeyword = 140, UniqueKeyword = 141, - FromKeyword = 142, - GlobalKeyword = 143, - OfKeyword = 144, - QualifiedName = 145, - ComputedPropertyName = 146, - TypeParameter = 147, - Parameter = 148, - Decorator = 149, - PropertySignature = 150, - PropertyDeclaration = 151, - MethodSignature = 152, - MethodDeclaration = 153, - Constructor = 154, - GetAccessor = 155, - SetAccessor = 156, - CallSignature = 157, - ConstructSignature = 158, - IndexSignature = 159, - TypePredicate = 160, - TypeReference = 161, - FunctionType = 162, - ConstructorType = 163, - TypeQuery = 164, - TypeLiteral = 165, - ArrayType = 166, - TupleType = 167, - UnionType = 168, - IntersectionType = 169, - ConditionalType = 170, - InferType = 171, - ParenthesizedType = 172, - ThisType = 173, - TypeOperator = 174, - IndexedAccessType = 175, - MappedType = 176, - LiteralType = 177, - ImportType = 178, - ObjectBindingPattern = 179, - ArrayBindingPattern = 180, - BindingElement = 181, - ArrayLiteralExpression = 182, - ObjectLiteralExpression = 183, - PropertyAccessExpression = 184, - ElementAccessExpression = 185, - CallExpression = 186, - NewExpression = 187, - TaggedTemplateExpression = 188, - TypeAssertionExpression = 189, - ParenthesizedExpression = 190, - FunctionExpression = 191, - ArrowFunction = 192, - DeleteExpression = 193, - TypeOfExpression = 194, - VoidExpression = 195, - AwaitExpression = 196, - PrefixUnaryExpression = 197, - PostfixUnaryExpression = 198, - BinaryExpression = 199, - ConditionalExpression = 200, - TemplateExpression = 201, - YieldExpression = 202, - SpreadElement = 203, - ClassExpression = 204, - OmittedExpression = 205, - ExpressionWithTypeArguments = 206, - AsExpression = 207, - NonNullExpression = 208, - MetaProperty = 209, - TemplateSpan = 210, - SemicolonClassElement = 211, - Block = 212, - VariableStatement = 213, - EmptyStatement = 214, - ExpressionStatement = 215, - IfStatement = 216, - DoStatement = 217, - WhileStatement = 218, - ForStatement = 219, - ForInStatement = 220, - ForOfStatement = 221, - ContinueStatement = 222, - BreakStatement = 223, - ReturnStatement = 224, - WithStatement = 225, - SwitchStatement = 226, - LabeledStatement = 227, - ThrowStatement = 228, - TryStatement = 229, - DebuggerStatement = 230, - VariableDeclaration = 231, - VariableDeclarationList = 232, - FunctionDeclaration = 233, - ClassDeclaration = 234, - InterfaceDeclaration = 235, - TypeAliasDeclaration = 236, - EnumDeclaration = 237, - ModuleDeclaration = 238, - ModuleBlock = 239, - CaseBlock = 240, - NamespaceExportDeclaration = 241, - ImportEqualsDeclaration = 242, - ImportDeclaration = 243, - ImportClause = 244, - NamespaceImport = 245, - NamedImports = 246, - ImportSpecifier = 247, - ExportAssignment = 248, - ExportDeclaration = 249, - NamedExports = 250, - ExportSpecifier = 251, - MissingDeclaration = 252, - ExternalModuleReference = 253, - JsxElement = 254, - JsxSelfClosingElement = 255, - JsxOpeningElement = 256, - JsxClosingElement = 257, - JsxFragment = 258, - JsxOpeningFragment = 259, - JsxClosingFragment = 260, - JsxAttribute = 261, - JsxAttributes = 262, - JsxSpreadAttribute = 263, - JsxExpression = 264, - CaseClause = 265, - DefaultClause = 266, - HeritageClause = 267, - CatchClause = 268, - PropertyAssignment = 269, - ShorthandPropertyAssignment = 270, - SpreadAssignment = 271, - EnumMember = 272, - SourceFile = 273, - Bundle = 274, - UnparsedSource = 275, - InputFiles = 276, - JSDocTypeExpression = 277, - JSDocAllType = 278, - JSDocUnknownType = 279, - JSDocNullableType = 280, - JSDocNonNullableType = 281, - JSDocOptionalType = 282, - JSDocFunctionType = 283, - JSDocVariadicType = 284, - JSDocComment = 285, - JSDocTypeLiteral = 286, - JSDocSignature = 287, - JSDocTag = 288, - JSDocAugmentsTag = 289, - JSDocClassTag = 290, - JSDocCallbackTag = 291, - JSDocParameterTag = 292, - JSDocReturnTag = 293, - JSDocTypeTag = 294, - JSDocTemplateTag = 295, - JSDocTypedefTag = 296, - JSDocPropertyTag = 297, - SyntaxList = 298, - NotEmittedStatement = 299, - PartiallyEmittedExpression = 300, - CommaListExpression = 301, - MergeDeclarationMarker = 302, - EndOfDeclarationMarker = 303, - Count = 304, + UnknownKeyword = 142, + FromKeyword = 143, + GlobalKeyword = 144, + OfKeyword = 145, + QualifiedName = 146, + ComputedPropertyName = 147, + TypeParameter = 148, + Parameter = 149, + Decorator = 150, + PropertySignature = 151, + PropertyDeclaration = 152, + MethodSignature = 153, + MethodDeclaration = 154, + Constructor = 155, + GetAccessor = 156, + SetAccessor = 157, + CallSignature = 158, + ConstructSignature = 159, + IndexSignature = 160, + TypePredicate = 161, + TypeReference = 162, + FunctionType = 163, + ConstructorType = 164, + TypeQuery = 165, + TypeLiteral = 166, + ArrayType = 167, + TupleType = 168, + UnionType = 169, + IntersectionType = 170, + ConditionalType = 171, + InferType = 172, + ParenthesizedType = 173, + ThisType = 174, + TypeOperator = 175, + IndexedAccessType = 176, + MappedType = 177, + LiteralType = 178, + ImportType = 179, + ObjectBindingPattern = 180, + ArrayBindingPattern = 181, + BindingElement = 182, + ArrayLiteralExpression = 183, + ObjectLiteralExpression = 184, + PropertyAccessExpression = 185, + ElementAccessExpression = 186, + CallExpression = 187, + NewExpression = 188, + TaggedTemplateExpression = 189, + TypeAssertionExpression = 190, + ParenthesizedExpression = 191, + FunctionExpression = 192, + ArrowFunction = 193, + DeleteExpression = 194, + TypeOfExpression = 195, + VoidExpression = 196, + AwaitExpression = 197, + PrefixUnaryExpression = 198, + PostfixUnaryExpression = 199, + BinaryExpression = 200, + ConditionalExpression = 201, + TemplateExpression = 202, + YieldExpression = 203, + SpreadElement = 204, + ClassExpression = 205, + OmittedExpression = 206, + ExpressionWithTypeArguments = 207, + AsExpression = 208, + NonNullExpression = 209, + MetaProperty = 210, + TemplateSpan = 211, + SemicolonClassElement = 212, + Block = 213, + VariableStatement = 214, + EmptyStatement = 215, + ExpressionStatement = 216, + IfStatement = 217, + DoStatement = 218, + WhileStatement = 219, + ForStatement = 220, + ForInStatement = 221, + ForOfStatement = 222, + ContinueStatement = 223, + BreakStatement = 224, + ReturnStatement = 225, + WithStatement = 226, + SwitchStatement = 227, + LabeledStatement = 228, + ThrowStatement = 229, + TryStatement = 230, + DebuggerStatement = 231, + VariableDeclaration = 232, + VariableDeclarationList = 233, + FunctionDeclaration = 234, + ClassDeclaration = 235, + InterfaceDeclaration = 236, + TypeAliasDeclaration = 237, + EnumDeclaration = 238, + ModuleDeclaration = 239, + ModuleBlock = 240, + CaseBlock = 241, + NamespaceExportDeclaration = 242, + ImportEqualsDeclaration = 243, + ImportDeclaration = 244, + ImportClause = 245, + NamespaceImport = 246, + NamedImports = 247, + ImportSpecifier = 248, + ExportAssignment = 249, + ExportDeclaration = 250, + NamedExports = 251, + ExportSpecifier = 252, + MissingDeclaration = 253, + ExternalModuleReference = 254, + JsxElement = 255, + JsxSelfClosingElement = 256, + JsxOpeningElement = 257, + JsxClosingElement = 258, + JsxFragment = 259, + JsxOpeningFragment = 260, + JsxClosingFragment = 261, + JsxAttribute = 262, + JsxAttributes = 263, + JsxSpreadAttribute = 264, + JsxExpression = 265, + CaseClause = 266, + DefaultClause = 267, + HeritageClause = 268, + CatchClause = 269, + PropertyAssignment = 270, + ShorthandPropertyAssignment = 271, + SpreadAssignment = 272, + EnumMember = 273, + SourceFile = 274, + Bundle = 275, + UnparsedSource = 276, + InputFiles = 277, + JSDocTypeExpression = 278, + JSDocAllType = 279, + JSDocUnknownType = 280, + JSDocNullableType = 281, + JSDocNonNullableType = 282, + JSDocOptionalType = 283, + JSDocFunctionType = 284, + JSDocVariadicType = 285, + JSDocComment = 286, + JSDocTypeLiteral = 287, + JSDocSignature = 288, + JSDocTag = 289, + JSDocAugmentsTag = 290, + JSDocClassTag = 291, + JSDocCallbackTag = 292, + JSDocParameterTag = 293, + JSDocReturnTag = 294, + JSDocTypeTag = 295, + JSDocTemplateTag = 296, + JSDocTypedefTag = 297, + JSDocPropertyTag = 298, + SyntaxList = 299, + NotEmittedStatement = 300, + PartiallyEmittedExpression = 301, + CommaListExpression = 302, + MergeDeclarationMarker = 303, + EndOfDeclarationMarker = 304, + Count = 305, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, @@ -374,15 +375,15 @@ declare namespace ts { FirstReservedWord = 72, LastReservedWord = 107, FirstKeyword = 72, - LastKeyword = 144, + LastKeyword = 145, FirstFutureReservedWord = 108, LastFutureReservedWord = 116, - FirstTypeNode = 160, - LastTypeNode = 178, + FirstTypeNode = 161, + LastTypeNode = 179, FirstPunctuation = 17, LastPunctuation = 70, FirstToken = 0, - LastToken = 144, + LastToken = 145, FirstTriviaToken = 2, LastTriviaToken = 7, FirstLiteralToken = 8, @@ -391,11 +392,11 @@ declare namespace ts { LastTemplateToken = 16, FirstBinaryOperator = 27, LastBinaryOperator = 70, - FirstNode = 145, - FirstJSDocNode = 277, - LastJSDocNode = 297, - FirstJSDocTagNode = 288, - LastJSDocTagNode = 297 + FirstNode = 146, + FirstJSDocNode = 278, + LastJSDocNode = 298, + FirstJSDocTagNode = 289, + LastJSDocTagNode = 298 } enum NodeFlags { None = 0, @@ -702,7 +703,7 @@ declare namespace ts { _typeNodeBrand: any; } interface KeywordTypeNode extends TypeNode { - kind: SyntaxKind.AnyKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.StringKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.VoidKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.NullKeyword | SyntaxKind.NeverKeyword; + kind: SyntaxKind.AnyKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.StringKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.VoidKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.NullKeyword | SyntaxKind.NeverKeyword; } interface ImportTypeNode extends NodeWithTypeArguments { kind: SyntaxKind.ImportType; @@ -2128,48 +2129,49 @@ declare namespace ts { type SymbolTable = UnderscoreEscapedMap; enum TypeFlags { Any = 1, - String = 2, - Number = 4, - Boolean = 8, - Enum = 16, - StringLiteral = 32, - NumberLiteral = 64, - BooleanLiteral = 128, - EnumLiteral = 256, - ESSymbol = 512, - UniqueESSymbol = 1024, - Void = 2048, - Undefined = 4096, - Null = 8192, - Never = 16384, - TypeParameter = 32768, - Object = 65536, - Union = 131072, - Intersection = 262144, - Index = 524288, - IndexedAccess = 1048576, - Conditional = 2097152, - Substitution = 4194304, - NonPrimitive = 134217728, - Literal = 224, - Unit = 13536, - StringOrNumberLiteral = 96, - PossiblyFalsy = 14574, - StringLike = 34, - NumberLike = 84, - BooleanLike = 136, - EnumLike = 272, - ESSymbolLike = 1536, - VoidLike = 6144, - UnionOrIntersection = 393216, - StructuredType = 458752, - TypeVariable = 1081344, - InstantiableNonPrimitive = 7372800, - InstantiablePrimitive = 524288, - Instantiable = 7897088, - StructuredOrInstantiable = 8355840, - Narrowable = 142575359, - NotUnionOrUnit = 134283777 + Unknown = 2, + String = 4, + Number = 8, + Boolean = 16, + Enum = 32, + StringLiteral = 64, + NumberLiteral = 128, + BooleanLiteral = 256, + EnumLiteral = 512, + ESSymbol = 1024, + UniqueESSymbol = 2048, + Void = 4096, + Undefined = 8192, + Null = 16384, + Never = 32768, + TypeParameter = 65536, + Object = 131072, + Union = 262144, + Intersection = 524288, + Index = 1048576, + IndexedAccess = 2097152, + Conditional = 4194304, + Substitution = 8388608, + NonPrimitive = 16777216, + Literal = 448, + Unit = 27072, + StringOrNumberLiteral = 192, + PossiblyFalsy = 29148, + StringLike = 68, + NumberLike = 168, + BooleanLike = 272, + EnumLike = 544, + ESSymbolLike = 3072, + VoidLike = 12288, + UnionOrIntersection = 786432, + StructuredType = 917504, + TypeVariable = 2162688, + InstantiableNonPrimitive = 14745600, + InstantiablePrimitive = 1048576, + Instantiable = 15794176, + StructuredOrInstantiable = 16711680, + Narrowable = 33492479, + NotUnionOrUnit = 16909315 } type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; interface Type { @@ -3399,8 +3401,10 @@ declare namespace ts { */ function isToken(n: Node): boolean; function isLiteralExpression(node: Node): node is LiteralExpression; + type TemplateLiteralToken = NoSubstitutionTemplateLiteral | TemplateHead | TemplateMiddle | TemplateTail; + function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken; function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail; - function isStringTextContainingNode(node: Node): boolean; + function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken; function isModifier(node: Node): node is Modifier; function isEntityName(node: Node): node is EntityName; function isPropertyName(node: Node): node is PropertyName; diff --git a/tests/baselines/reference/asyncAwaitIsolatedModules_es5.js b/tests/baselines/reference/asyncAwaitIsolatedModules_es5.js index 2c4f827be53..58b887c61a3 100644 --- a/tests/baselines/reference/asyncAwaitIsolatedModules_es5.js +++ b/tests/baselines/reference/asyncAwaitIsolatedModules_es5.js @@ -56,8 +56,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/tests/baselines/reference/asyncAwait_es5.js b/tests/baselines/reference/asyncAwait_es5.js index 6434ae5a766..ee8f160b2a4 100644 --- a/tests/baselines/reference/asyncAwait_es5.js +++ b/tests/baselines/reference/asyncAwait_es5.js @@ -62,8 +62,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/tests/baselines/reference/asyncFunctionNoReturnType.js b/tests/baselines/reference/asyncFunctionNoReturnType.js index 6f4a3795118..b376e398d17 100644 --- a/tests/baselines/reference/asyncFunctionNoReturnType.js +++ b/tests/baselines/reference/asyncFunctionNoReturnType.js @@ -21,8 +21,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/tests/baselines/reference/asyncFunctionTempVariableScoping.js b/tests/baselines/reference/asyncFunctionTempVariableScoping.js index fb4137e1671..c237e03e0f6 100644 --- a/tests/baselines/reference/asyncFunctionTempVariableScoping.js +++ b/tests/baselines/reference/asyncFunctionTempVariableScoping.js @@ -20,8 +20,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/tests/baselines/reference/asyncFunctionWithForStatementNoInitializer.js b/tests/baselines/reference/asyncFunctionWithForStatementNoInitializer.js index 10f6c20eb06..99394281a15 100644 --- a/tests/baselines/reference/asyncFunctionWithForStatementNoInitializer.js +++ b/tests/baselines/reference/asyncFunctionWithForStatementNoInitializer.js @@ -40,8 +40,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/tests/baselines/reference/asyncImportNestedYield.js b/tests/baselines/reference/asyncImportNestedYield.js index 74d6dd59629..b92065950fb 100644 --- a/tests/baselines/reference/asyncImportNestedYield.js +++ b/tests/baselines/reference/asyncImportNestedYield.js @@ -11,8 +11,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/tests/baselines/reference/asyncImportedPromise_es5.js b/tests/baselines/reference/asyncImportedPromise_es5.js index ea9cf265a8a..8b56ebbd1fa 100644 --- a/tests/baselines/reference/asyncImportedPromise_es5.js +++ b/tests/baselines/reference/asyncImportedPromise_es5.js @@ -47,8 +47,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/tests/baselines/reference/asyncMultiFile_es5.js b/tests/baselines/reference/asyncMultiFile_es5.js index 67a3ce258b4..a6dbb44ef9e 100644 --- a/tests/baselines/reference/asyncMultiFile_es5.js +++ b/tests/baselines/reference/asyncMultiFile_es5.js @@ -21,8 +21,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/tests/baselines/reference/awaitUnionPromise.js b/tests/baselines/reference/awaitUnionPromise.js index df4c937fc63..90b894ee0f5 100644 --- a/tests/baselines/reference/awaitUnionPromise.js +++ b/tests/baselines/reference/awaitUnionPromise.js @@ -37,8 +37,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/tests/baselines/reference/blockScopedBindingsInDownlevelGenerator.js b/tests/baselines/reference/blockScopedBindingsInDownlevelGenerator.js index 5f3eed666ab..e177b7d4a0a 100644 --- a/tests/baselines/reference/blockScopedBindingsInDownlevelGenerator.js +++ b/tests/baselines/reference/blockScopedBindingsInDownlevelGenerator.js @@ -14,8 +14,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/tests/baselines/reference/castOfYield.js b/tests/baselines/reference/castOfYield.js index 9ad9ec52a31..86d35bedad4 100644 --- a/tests/baselines/reference/castOfYield.js +++ b/tests/baselines/reference/castOfYield.js @@ -14,8 +14,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { 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]; + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; diff --git a/tests/baselines/reference/checkJsxChildrenProperty14.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty14.errors.txt index 6878372be8b..cf999188ebc 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty14.errors.txt +++ b/tests/baselines/reference/checkJsxChildrenProperty14.errors.txt @@ -1,8 +1,7 @@ -tests/cases/conformance/jsx/file.tsx(42,11): error TS2322: Type '{ children: Element[]; a: number; b: string; }' is not assignable to type 'IntrinsicAttributes & SingleChildProp'. - Type '{ children: Element[]; a: number; b: string; }' is not assignable to type 'SingleChildProp'. - Types of property 'children' are incompatible. - Type 'Element[]' is not assignable to type 'Element'. - Property 'type' is missing in type 'Element[]'. +tests/cases/conformance/jsx/file.tsx(42,11): error TS2322: Type '{ children: Element[]; a: number; b: string; }' is not assignable to type 'SingleChildProp'. + Types of property 'children' are incompatible. + Type 'Element[]' is not assignable to type 'Element'. + Property 'type' is missing in type 'Element[]'. ==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== @@ -49,8 +48,7 @@ tests/cases/conformance/jsx/file.tsx(42,11): error TS2322: Type '{ children: Ele // Error let k5 = <>