diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 35a62a644d839..467c25f549e36 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1550,7 +1550,7 @@ namespace ts { function setExportContextFlag(node: ModuleDeclaration | SourceFile) { // A declaration source file or ambient module declaration that contains no export declarations (but possibly regular // declarations with export modifiers) is an export context in which declarations are implicitly exported. - if (isInAmbientContext(node) && !hasExportDeclarations(node)) { + if (node.flags & NodeFlags.Ambient && !hasExportDeclarations(node)) { node.flags |= NodeFlags.ExportContext; } else { @@ -1726,7 +1726,7 @@ namespace ts { node.originalKeywordKind >= SyntaxKind.FirstFutureReservedWord && node.originalKeywordKind <= SyntaxKind.LastFutureReservedWord && !isIdentifierName(node) && - !isInAmbientContext(node)) { + !(node.flags & NodeFlags.Ambient)) { // Report error only if there are no parse errors in file if (!file.parseDiagnostics.length) { @@ -2481,7 +2481,7 @@ namespace ts { } function bindParameter(node: ParameterDeclaration) { - if (inStrictMode && !isInAmbientContext(node)) { + if (inStrictMode && !(node.flags & NodeFlags.Ambient)) { // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a // strict mode FunctionLikeDeclaration or FunctionExpression(13.1) checkStrictModeEvalOrArguments(node, node.name); @@ -2503,7 +2503,7 @@ namespace ts { } function bindFunctionDeclaration(node: FunctionDeclaration) { - if (!file.isDeclarationFile && !isInAmbientContext(node)) { + if (!file.isDeclarationFile && !(node.flags & NodeFlags.Ambient)) { if (isAsyncFunction(node)) { emitFlags |= NodeFlags.HasAsyncFunctions; } @@ -2520,7 +2520,7 @@ namespace ts { } function bindFunctionExpression(node: FunctionExpression) { - if (!file.isDeclarationFile && !isInAmbientContext(node)) { + if (!file.isDeclarationFile && !(node.flags & NodeFlags.Ambient)) { if (isAsyncFunction(node)) { emitFlags |= NodeFlags.HasAsyncFunctions; } @@ -2534,7 +2534,7 @@ namespace ts { } function bindPropertyOrMethodOrAccessor(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) { - if (!file.isDeclarationFile && !isInAmbientContext(node) && isAsyncFunction(node)) { + if (!file.isDeclarationFile && !(node.flags & NodeFlags.Ambient) && isAsyncFunction(node)) { emitFlags |= NodeFlags.HasAsyncFunctions; } @@ -2583,7 +2583,7 @@ namespace ts { // On the other side we do want to report errors on non-initialized 'lets' because of TDZ const reportUnreachableCode = !options.allowUnreachableCode && - !isInAmbientContext(node) && + !(node.flags & NodeFlags.Ambient) && ( node.kind !== SyntaxKind.VariableStatement || getCombinedNodeFlags((node).declarationList) & NodeFlags.BlockScoped || diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 72438fa27af87..5e56fe6295f9b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -691,7 +691,7 @@ namespace ts { else { // find a module that about to be augmented // do not validate names of augmentations that are defined in ambient context - const moduleNotFoundError = !isInAmbientContext(moduleName.parent.parent) + const moduleNotFoundError = !(moduleName.parent.parent.flags & NodeFlags.Ambient) ? Diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found : undefined; let mainModule = resolveExternalModuleNameWorker(moduleName, moduleName, moduleNotFoundError, /*isForAugmentation*/ true); @@ -796,7 +796,7 @@ namespace ts { if ((modulekind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) || (!compilerOptions.outFile && !compilerOptions.out) || isInTypeQuery(usage) || - isInAmbientContext(declaration)) { + declaration.flags & NodeFlags.Ambient) { // nodes are in different files and order cannot be determined return true; } @@ -1384,7 +1384,7 @@ namespace ts { Debug.assert(declaration !== undefined, "Declaration to checkResolvedBlockScopedVariable is undefined"); - if (!isInAmbientContext(declaration) && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation)) { + if (!(declaration.flags & NodeFlags.Ambient) && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation)) { if (result.flags & SymbolFlags.BlockScopedVariable) { error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(getNameOfDeclaration(declaration))); } @@ -3940,7 +3940,7 @@ namespace ts { const parent = getDeclarationContainer(node); // If the node is not exported or it is not ambient module element (except import declaration) if (!(getCombinedModifierFlags(node) & ModifierFlags.Export) && - !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && isInAmbientContext(parent))) { + !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && parent.flags & NodeFlags.Ambient)) { return isGlobalSourceFile(parent); } // Exported members/ambient module elements (exception import declaration) are visible if parent is visible @@ -4318,7 +4318,7 @@ namespace ts { if ((noImplicitAny || isInJavaScriptFile(declaration)) && declaration.kind === SyntaxKind.VariableDeclaration && !isBindingPattern(declaration.name) && - !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) && !isInAmbientContext(declaration)) { + !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) && !(declaration.flags & NodeFlags.Ambient)) { // If --noImplicitAny is on or the declaration is in a Javascript file, // use control flow tracked 'any' type for non-ambient, non-exported var or let variables with no // initializer or a 'null' or 'undefined' initializer. @@ -5191,7 +5191,7 @@ namespace ts { function isLiteralEnumMember(member: EnumMember) { const expr = member.initializer; if (!expr) { - return !isInAmbientContext(member); + return !(member.flags & NodeFlags.Ambient); } switch (expr.kind) { case SyntaxKind.StringLiteral: @@ -12738,7 +12738,7 @@ namespace ts { const assumeInitialized = isParameter || isAlias || isOuterVariable || type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || node.parent.kind === SyntaxKind.NonNullExpression || - isInAmbientContext(declaration); + declaration.flags & NodeFlags.Ambient; const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, getRootDeclaration(declaration) as VariableLikeDeclaration) : type) : type === autoType || type === autoArrayType ? undefinedType : getNullableType(type, TypeFlags.Undefined); @@ -15189,7 +15189,7 @@ namespace ts { } else if (valueDeclaration.kind === SyntaxKind.ClassDeclaration && node.parent.kind !== SyntaxKind.TypeReference && - !isInAmbientContext(valueDeclaration) && + !(valueDeclaration.flags & NodeFlags.Ambient) && !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right)) { error(right, Diagnostics.Class_0_used_before_its_declaration, idText(right)); } @@ -17057,7 +17057,7 @@ namespace ts { return type; } - function isCommonJsRequire(node: Node) { + function isCommonJsRequire(node: Node): boolean { if (!isRequireCall(node, /*checkArgumentIsStringLiteral*/ true)) { return false; } @@ -17081,7 +17081,7 @@ namespace ts { if (targetDeclarationKind !== SyntaxKind.Unknown) { const decl = getDeclarationOfKind(resolvedRequire, targetDeclarationKind); // function/variable declaration should be ambient - return isInAmbientContext(decl); + return !!(decl.flags & NodeFlags.Ambient); } return false; } @@ -19205,7 +19205,7 @@ namespace ts { checkDecorators(node); checkSignatureDeclaration(node); if (node.kind === SyntaxKind.GetAccessor) { - if (!isInAmbientContext(node) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { + if (!(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { if (!(node.flags & NodeFlags.HasExplicitReturn)) { error(node.name, Diagnostics.A_get_accessor_must_return_a_value); } @@ -19388,7 +19388,7 @@ namespace ts { } function isPrivateWithinAmbient(node: Node): boolean { - return hasModifier(node, ModifierFlags.Private) && isInAmbientContext(node); + return hasModifier(node, ModifierFlags.Private) && !!(node.flags & NodeFlags.Ambient); } function getEffectiveDeclarationFlags(n: Node, flagsToCheck: ModifierFlags): ModifierFlags { @@ -19399,7 +19399,7 @@ namespace ts { if (n.parent.kind !== SyntaxKind.InterfaceDeclaration && n.parent.kind !== SyntaxKind.ClassDeclaration && n.parent.kind !== SyntaxKind.ClassExpression && - isInAmbientContext(n)) { + n.flags & NodeFlags.Ambient) { if (!(flags & ModifierFlags.Ambient)) { // It is nested in an ambient context, which means it is automatically exported flags |= ModifierFlags.Export; @@ -19538,7 +19538,7 @@ namespace ts { let multipleConstructorImplementation = false; for (const current of declarations) { const node = current; - const inAmbientContext = isInAmbientContext(node); + const inAmbientContext = node.flags & NodeFlags.Ambient; const inAmbientContextOrInterface = node.parent.kind === SyntaxKind.InterfaceDeclaration || node.parent.kind === SyntaxKind.TypeLiteral || inAmbientContext; if (inAmbientContextOrInterface) { // check if declarations are consecutive only if they are non-ambient @@ -20393,7 +20393,7 @@ namespace ts { } function checkUnusedLocalsAndParameters(node: Node): void { - if (node.parent.kind !== SyntaxKind.InterfaceDeclaration && noUnusedIdentifiers && !isInAmbientContext(node)) { + if (node.parent.kind !== SyntaxKind.InterfaceDeclaration && noUnusedIdentifiers && !(node.flags & NodeFlags.Ambient)) { node.locals.forEach(local => { if (!local.isReferenced) { if (local.valueDeclaration && getRootDeclaration(local.valueDeclaration).kind === SyntaxKind.Parameter) { @@ -20446,7 +20446,7 @@ namespace ts { } function checkUnusedClassMembers(node: ClassDeclaration | ClassExpression): void { - if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { + if (compilerOptions.noUnusedLocals && !(node.flags & NodeFlags.Ambient)) { if (node.members) { for (const member of node.members) { if (member.kind === SyntaxKind.MethodDeclaration || member.kind === SyntaxKind.PropertyDeclaration) { @@ -20467,7 +20467,7 @@ namespace ts { } function checkUnusedTypeParameters(node: ClassDeclaration | ClassExpression | FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction | ConstructorDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration) { - if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { + if (compilerOptions.noUnusedLocals && !(node.flags & NodeFlags.Ambient)) { if (node.typeParameters) { // Only report errors on the last declaration for the type parameter container; // this ensures that all uses have been accounted for. @@ -20486,7 +20486,7 @@ namespace ts { } function checkUnusedModuleMembers(node: ModuleDeclaration | SourceFile): void { - if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { + if (compilerOptions.noUnusedLocals && !(node.flags & NodeFlags.Ambient)) { node.locals.forEach(local => { if (!local.isReferenced && !local.exportSymbol) { for (const declaration of local.declarations) { @@ -20519,7 +20519,7 @@ namespace ts { function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { // no rest parameters \ declaration context \ overload - no codegen impact - if (!hasRestParameter(node) || isInAmbientContext(node) || nodeIsMissing((node).body)) { + if (!hasRestParameter(node) || node.flags & NodeFlags.Ambient || nodeIsMissing((node).body)) { return; } @@ -20545,7 +20545,7 @@ namespace ts { return false; } - if (isInAmbientContext(node)) { + if (node.flags & NodeFlags.Ambient) { // ambient context - no codegen impact return false; } @@ -20610,7 +20610,7 @@ namespace ts { // bubble up and find containing type const enclosingClass = getContainingClass(node); // if containing type was not found or it is ambient - exit (no codegen) - if (!enclosingClass || isInAmbientContext(enclosingClass)) { + if (!enclosingClass || enclosingClass.flags & NodeFlags.Ambient) { return; } @@ -21925,7 +21925,7 @@ namespace ts { checkClassForDuplicateDeclarations(node); // Only check for reserved static identifiers on non-ambient context. - if (!isInAmbientContext(node)) { + if (!(node.flags & NodeFlags.Ambient)) { checkClassForStaticPropertyNameConflicts(node); } @@ -22231,7 +22231,7 @@ namespace ts { } // In ambient enum declarations that specify no const modifier, enum member declarations that omit // a value are considered computed members (as opposed to having auto-incremented values). - if (isInAmbientContext(member.parent) && !isConst(member.parent)) { + if (member.parent.flags & NodeFlags.Ambient && !isConst(member.parent)) { return undefined; } // If the member declaration specifies no value, the member is considered a constant enum member. @@ -22264,7 +22264,7 @@ namespace ts { else if (isConstEnum) { error(initializer, Diagnostics.In_const_enum_declarations_member_initializer_must_be_constant_expression); } - else if (isInAmbientContext(member.parent)) { + else if (member.parent.flags & NodeFlags.Ambient) { error(initializer, Diagnostics.In_ambient_enum_declarations_member_initializer_must_be_constant_expression); } else { @@ -22377,7 +22377,7 @@ namespace ts { computeEnumMemberValues(node); const enumIsConst = isConst(node); - if (compilerOptions.isolatedModules && enumIsConst && isInAmbientContext(node)) { + if (compilerOptions.isolatedModules && enumIsConst && node.flags & NodeFlags.Ambient) { error(node.name, Diagnostics.Ambient_const_enums_are_not_allowed_when_the_isolatedModules_flag_is_provided); } @@ -22429,7 +22429,7 @@ namespace ts { for (const declaration of declarations) { if ((declaration.kind === SyntaxKind.ClassDeclaration || (declaration.kind === SyntaxKind.FunctionDeclaration && nodeIsPresent((declaration).body))) && - !isInAmbientContext(declaration)) { + !(declaration.flags & NodeFlags.Ambient)) { return declaration; } } @@ -22454,7 +22454,7 @@ namespace ts { if (produceDiagnostics) { // Grammar checking const isGlobalAugmentation = isGlobalScopeAugmentation(node); - const inAmbientContext = isInAmbientContext(node); + const inAmbientContext = node.flags & NodeFlags.Ambient; if (isGlobalAugmentation && !inAmbientContext) { error(node.name, Diagnostics.Augmentations_for_the_global_scope_should_have_declare_modifier_unless_they_appear_in_already_ambient_context); } @@ -22673,7 +22673,7 @@ namespace ts { if (compilerOptions.isolatedModules && node.kind === SyntaxKind.ExportSpecifier && !(target.flags & SymbolFlags.Value) - && !isInAmbientContext(node)) { + && !(node.flags & NodeFlags.Ambient)) { error(node, Diagnostics.Cannot_re_export_a_type_when_the_isolatedModules_flag_is_provided); } } @@ -22724,7 +22724,7 @@ namespace ts { if (hasModifier(node, ModifierFlags.Export)) { markExportAsReferenced(node); } - if (isInternalModuleImportEqualsDeclaration(node)) { + if (node.moduleReference.kind !== SyntaxKind.ExternalModuleReference) { const target = resolveAlias(getSymbolOfNode(node)); if (target !== unknownSymbol) { if (target.flags & SymbolFlags.Value) { @@ -22740,7 +22740,7 @@ namespace ts { } } else { - if (modulekind >= ModuleKind.ES2015 && !isInAmbientContext(node)) { + if (modulekind >= ModuleKind.ES2015 && !(node.flags & NodeFlags.Ambient)) { // Import equals declaration is deprecated in es6 or above grammarErrorOnNode(node, Diagnostics.Import_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_import_d_from_mod_or_another_module_format_instead); } @@ -22766,7 +22766,7 @@ namespace ts { const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && isAmbientModule(node.parent.parent); const inAmbientNamespaceDeclaration = !inAmbientExternalModule && node.parent.kind === SyntaxKind.ModuleBlock && - !node.moduleSpecifier && isInAmbientContext(node); + !node.moduleSpecifier && node.flags & NodeFlags.Ambient; if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule && !inAmbientNamespaceDeclaration) { error(node, Diagnostics.Export_declarations_are_not_permitted_in_a_namespace); } @@ -22839,11 +22839,11 @@ namespace ts { checkExternalModuleExports(container); - if (isInAmbientContext(node) && !isEntityNameExpression(node.expression)) { + if ((node.flags & NodeFlags.Ambient) && !isEntityNameExpression(node.expression)) { grammarErrorOnNode(node.expression, Diagnostics.The_expression_of_an_export_assignment_must_be_an_identifier_or_qualified_name_in_an_ambient_context); } - if (node.isExportEquals && !isInAmbientContext(node)) { + if (node.isExportEquals && !(node.flags & NodeFlags.Ambient)) { if (modulekind >= ModuleKind.ES2015) { // export assignment is not supported in es6 modules grammarErrorOnNode(node, Diagnostics.Export_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_export_default_or_another_module_format_instead); @@ -24475,7 +24475,7 @@ namespace ts { function checkExternalEmitHelpers(location: Node, helpers: ExternalEmitHelpers) { if ((requestedExternalEmitHelpers & helpers) !== helpers && compilerOptions.importHelpers) { const sourceFile = getSourceFileOfNode(location); - if (isEffectiveExternalModule(sourceFile, compilerOptions) && !isInAmbientContext(location)) { + if (isEffectiveExternalModule(sourceFile, compilerOptions) && !(location.flags & NodeFlags.Ambient)) { const helpersModule = resolveHelpersModule(sourceFile, location); if (helpersModule !== unknownSymbol) { const uncheckedHelpers = helpers & ~requestedExternalEmitHelpers; @@ -24677,7 +24677,7 @@ namespace ts { else if (node.kind === SyntaxKind.Parameter) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "declare"); } - else if (isInAmbientContext(node.parent) && node.parent.kind === SyntaxKind.ModuleBlock) { + else if ((node.parent.flags & NodeFlags.Ambient) && node.parent.kind === SyntaxKind.ModuleBlock) { return grammarErrorOnNode(modifier, Diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context); } flags |= ModifierFlags.Ambient; @@ -24713,7 +24713,7 @@ namespace ts { if (flags & ModifierFlags.Async) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "async"); } - else if (flags & ModifierFlags.Ambient || isInAmbientContext(node.parent)) { + else if (flags & ModifierFlags.Ambient || node.parent.flags & NodeFlags.Ambient) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); } else if (node.kind === SyntaxKind.Parameter) { @@ -25061,7 +25061,7 @@ namespace ts { node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.MethodDeclaration); - if (isInAmbientContext(node)) { + if (node.flags & NodeFlags.Ambient) { return grammarErrorOnNode(node.asteriskToken, Diagnostics.Generators_are_not_allowed_in_an_ambient_context); } if (!node.body) { @@ -25248,7 +25248,7 @@ namespace ts { if (languageVersion < ScriptTarget.ES5) { return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher); } - else if (isInAmbientContext(accessor)) { + else if (accessor.flags & NodeFlags.Ambient) { return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_be_declared_in_an_ambient_context); } else if (accessor.body === undefined && !hasModifier(accessor, ModifierFlags.Abstract)) { @@ -25327,7 +25327,7 @@ namespace ts { // However, property declarations disallow computed names in general, // and accessors are not allowed in ambient contexts in general, // so this error only really matters for methods. - if (isInAmbientContext(node)) { + if (node.flags & NodeFlags.Ambient) { return checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_an_ambient_context_must_directly_refer_to_a_built_in_symbol); } else if (!node.body) { @@ -25422,7 +25422,7 @@ namespace ts { function checkGrammarVariableDeclaration(node: VariableDeclaration) { if (node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) { - if (isInAmbientContext(node)) { + if (node.flags & NodeFlags.Ambient) { if (node.initializer) { if (isConst(node) && !node.type) { if (!isStringOrNumberLiteralExpression(node.initializer)) { @@ -25452,7 +25452,7 @@ namespace ts { } if (compilerOptions.module !== ModuleKind.ES2015 && compilerOptions.module !== ModuleKind.ESNext && compilerOptions.module !== ModuleKind.System && !compilerOptions.noEmit && - !isInAmbientContext(node.parent.parent) && hasModifier(node.parent.parent, ModifierFlags.Export)) { + !(node.parent.parent.flags & NodeFlags.Ambient) && hasModifier(node.parent.parent, ModifierFlags.Export)) { checkESModuleMarker(node.name); } @@ -25611,7 +25611,7 @@ namespace ts { } } - if (isInAmbientContext(node) && node.initializer) { + if (node.flags & NodeFlags.Ambient && node.initializer) { return grammarErrorOnFirstToken(node.initializer, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); } } @@ -25654,11 +25654,11 @@ namespace ts { } function checkGrammarSourceFile(node: SourceFile): boolean { - return isInAmbientContext(node) && checkGrammarTopLevelElementsForRequiredDeclareModifier(node); + return !!(node.flags & NodeFlags.Ambient) && checkGrammarTopLevelElementsForRequiredDeclareModifier(node); } function checkGrammarStatementInAmbientContext(node: Node): boolean { - if (isInAmbientContext(node)) { + if (node.flags & NodeFlags.Ambient) { // An accessors is already reported about the ambient context if (isAccessor(node.parent)) { return getNodeLinks(node).hasReportedStatementInAmbientContext = true; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b27d4811ecb43..ebaa89541db5f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -627,6 +627,7 @@ namespace ts { } export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName { + // Choice of `isDeclarationFile` should be arbitrary initializeState(content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS); // Prime the scanner. nextToken(); @@ -639,7 +640,7 @@ namespace ts { export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile { initializeState(sourceText, ScriptTarget.ES2015, /*syntaxCursor*/ undefined, ScriptKind.JSON); // Set source file so that errors will be reported with this file name - sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON); + sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclaration*/ false); const result = sourceFile; // Prime the scanner. @@ -681,7 +682,16 @@ namespace ts { identifierCount = 0; nodeCount = 0; - contextFlags = scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JSON ? NodeFlags.JavaScriptFile : NodeFlags.None; + switch (scriptKind) { + case ScriptKind.JS: + case ScriptKind.JSX: + case ScriptKind.JSON: + contextFlags = NodeFlags.JavaScriptFile; + break; + default: + contextFlags = NodeFlags.None; + break; + } parseErrorBeforeNextFinishedNode = false; // Initialize and prime the scanner before parsing the source elements. @@ -705,7 +715,12 @@ namespace ts { } function parseSourceFileWorker(fileName: string, languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind): SourceFile { - sourceFile = createSourceFile(fileName, languageVersion, scriptKind); + const isDeclarationFile = isDeclarationFileName(fileName); + if (isDeclarationFile) { + contextFlags |= NodeFlags.Ambient; + } + + sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile); sourceFile.flags = contextFlags; // Prime the scanner. @@ -782,7 +797,7 @@ namespace ts { } } - function createSourceFile(fileName: string, languageVersion: ScriptTarget, scriptKind: ScriptKind): SourceFile { + function createSourceFile(fileName: string, languageVersion: ScriptTarget, scriptKind: ScriptKind, isDeclarationFile: boolean): SourceFile { // code from createNode is inlined here so createNode won't have to deal with special case of creating source files // this is quite rare comparing to other nodes and createNode should be as fast as possible const sourceFile = new SourceFileConstructor(SyntaxKind.SourceFile, /*pos*/ 0, /* end */ sourceText.length); @@ -793,7 +808,7 @@ namespace ts { sourceFile.languageVersion = languageVersion; sourceFile.fileName = normalizePath(fileName); sourceFile.languageVariant = getLanguageVariant(scriptKind); - sourceFile.isDeclarationFile = fileExtensionIs(sourceFile.fileName, Extension.Dts); + sourceFile.isDeclarationFile = isDeclarationFile; sourceFile.scriptKind = scriptKind; return sourceFile; @@ -5089,6 +5104,18 @@ namespace ts { const fullStart = getNodePos(); const decorators = parseDecorators(); const modifiers = parseModifiers(); + if (some(modifiers, m => m.kind === SyntaxKind.DeclareKeyword)) { + for (const m of modifiers) { + m.flags |= NodeFlags.Ambient; + } + return doInsideOfContext(NodeFlags.Ambient, () => parseDeclarationWorker(fullStart, decorators, modifiers)); + } + else { + return parseDeclarationWorker(fullStart, decorators, modifiers); + } + } + + function parseDeclarationWorker(fullStart: number, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): Statement { switch (token()) { case SyntaxKind.VarKeyword: case SyntaxKind.LetKeyword: @@ -5446,8 +5473,8 @@ namespace ts { return false; } - function parseDecorators(): NodeArray { - let list: Decorator[]; + function parseDecorators(): NodeArray | undefined { + let list: Decorator[] | undefined; const listPos = getNodePos(); while (true) { const decoratorStart = getNodePos(); @@ -6131,7 +6158,7 @@ namespace ts { export namespace JSDocParser { export function parseJSDocTypeExpressionForTests(content: string, start: number, length: number): { jsDocTypeExpression: JSDocTypeExpression, diagnostics: Diagnostic[] } | undefined { initializeState(content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); - sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS); + sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false); scanner.setText(content, start, length); currentToken = scanner.scan(); const jsDocTypeExpression = parseJSDocTypeExpression(); @@ -7461,4 +7488,8 @@ namespace ts { Value = -1 } } + + function isDeclarationFileName(fileName: string): boolean { + return fileExtensionIs(fileName, Extension.Dts); + } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e1830274c9308..f1387aa40456f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -451,7 +451,8 @@ namespace ts { /* @internal */ PossiblyContainsDynamicImport = 1 << 19, JSDoc = 1 << 20, // If node was parsed inside jsdoc - /* @internal */ InWithStatement = 1 << 21, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`) + /* @internal */ Ambient = 1 << 21, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier. + /* @internal */ InWithStatement = 1 << 22, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`) BlockScoped = Let | Const, @@ -459,7 +460,7 @@ namespace ts { ReachabilityAndEmitFlags = ReachabilityCheckFlags | HasAsyncFunctions, // Parsing context flags - ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | InWithStatement, + ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | InWithStatement | Ambient, // Exclude these flags when parsing a Type TypeExcludesFlags = YieldContext | AwaitContext, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 01bb36e906510..e0c4261f27c83 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1718,16 +1718,6 @@ namespace ts { return false; } - export function isInAmbientContext(node: Node): boolean { - while (node) { - if (hasModifier(node, ModifierFlags.Ambient) || (node.kind === SyntaxKind.SourceFile && (node as SourceFile).isDeclarationFile)) { - return true; - } - node = node.parent; - } - return false; - } - // True if the given identifier, string literal, or number literal is the name of a declaration node export function isDeclarationName(name: Node): boolean { switch (name.kind) { diff --git a/src/harness/unittests/incrementalParser.ts b/src/harness/unittests/incrementalParser.ts index fbd8a60da9233..c71b89d3da68d 100644 --- a/src/harness/unittests/incrementalParser.ts +++ b/src/harness/unittests/incrementalParser.ts @@ -591,7 +591,7 @@ module m3 { }\ const index = 0; const newTextAndChange = withInsert(oldText, index, "declare "); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 3); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); it("Insert function above arrow function with comment", () => { @@ -674,7 +674,7 @@ module m3 { }\ const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withInsert(oldText, 0, "{"); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 9); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4); }); it("Removing block around function declarations", () => { @@ -683,7 +683,7 @@ module m3 { }\ const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withDelete(oldText, 0, "{".length); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 9); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4); }); it("Moving methods from class to object literal", () => { diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index 37aa8df0ca175..3421404a30f35 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -31,7 +31,7 @@ namespace ts.BreakpointResolver { } // Cannot set breakpoint in ambient declarations - if (isInAmbientContext(tokenAtLocation)) { + if (tokenAtLocation.flags & NodeFlags.Ambient) { return undefined; } diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index b18e12d2b96da..01b01fa8d4a62 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -335,7 +335,7 @@ namespace ts.refactor.extractSymbol { return [createDiagnosticForNode(nodeToCheck, Messages.StatementOrExpressionExpected)]; } - if (isInAmbientContext(nodeToCheck)) { + if (nodeToCheck.flags & NodeFlags.Ambient) { return [createDiagnosticForNode(nodeToCheck, Messages.CannotExtractAmbientBlock)]; } diff --git a/src/services/services.ts b/src/services/services.ts index d6e75868852ae..e307f7deddd64 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -41,6 +41,7 @@ namespace ts { kind === SyntaxKind.Identifier ? new IdentifierObject(SyntaxKind.Identifier, pos, end) : new TokenObject(kind, pos, end); node.parent = parent; + node.flags = parent.flags & NodeFlags.ContextFlags; return node; } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 2b116eb1cd05c..d014f48a3f371 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -947,7 +947,7 @@ namespace ts { if (flags & ModifierFlags.Static) result.push(ScriptElementKindModifier.staticModifier); if (flags & ModifierFlags.Abstract) result.push(ScriptElementKindModifier.abstractModifier); if (flags & ModifierFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); - if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); + if (node.flags & NodeFlags.Ambient) result.push(ScriptElementKindModifier.ambientModifier); return result.length > 0 ? result.join(",") : ScriptElementKindModifier.none; } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 26c03954b4544..fc5d6790b6484 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -408,7 +408,7 @@ declare namespace ts { BlockScoped = 3, ReachabilityCheckFlags = 384, ReachabilityAndEmitFlags = 1408, - ContextFlags = 2193408, + ContextFlags = 6387712, TypeExcludesFlags = 20480, } enum ModifierFlags { diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 6abf9d0cb6e16..94bdeb93339f3 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -408,7 +408,7 @@ declare namespace ts { BlockScoped = 3, ReachabilityCheckFlags = 384, ReachabilityAndEmitFlags = 1408, - ContextFlags = 2193408, + ContextFlags = 6387712, TypeExcludesFlags = 20480, } enum ModifierFlags { diff --git a/tests/baselines/reference/parserConstructorDeclaration4.errors.txt b/tests/baselines/reference/parserConstructorDeclaration4.errors.txt index b5329a1cb47ad..bd27ccbb255ee 100644 --- a/tests/baselines/reference/parserConstructorDeclaration4.errors.txt +++ b/tests/baselines/reference/parserConstructorDeclaration4.errors.txt @@ -1,12 +1,9 @@ tests/cases/conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration4.ts(2,3): error TS1031: 'declare' modifier cannot appear on a class element. -tests/cases/conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration4.ts(2,25): error TS1183: An implementation cannot be declared in ambient contexts. -==== tests/cases/conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration4.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration4.ts (1 errors) ==== class C { declare constructor() { } ~~~~~~~ !!! error TS1031: 'declare' modifier cannot appear on a class element. - ~ -!!! error TS1183: An implementation cannot be declared in ambient contexts. } \ No newline at end of file diff --git a/tests/baselines/reference/parserMemberAccessorDeclaration11.errors.txt b/tests/baselines/reference/parserMemberAccessorDeclaration11.errors.txt index 5da5e536e067a..3a04bfbbd0296 100644 --- a/tests/baselines/reference/parserMemberAccessorDeclaration11.errors.txt +++ b/tests/baselines/reference/parserMemberAccessorDeclaration11.errors.txt @@ -1,9 +1,12 @@ tests/cases/conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration11.ts(2,5): error TS1031: 'declare' modifier cannot appear on a class element. +tests/cases/conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration11.ts(2,17): error TS2378: A 'get' accessor must return a value. -==== tests/cases/conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration11.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration11.ts (2 errors) ==== class C { declare get Foo() { } ~~~~~~~ !!! error TS1031: 'declare' modifier cannot appear on a class element. + ~~~ +!!! error TS2378: A 'get' accessor must return a value. } \ No newline at end of file diff --git a/tests/baselines/reference/parserMemberFunctionDeclaration5.errors.txt b/tests/baselines/reference/parserMemberFunctionDeclaration5.errors.txt index 402355919a031..dc19cb0f8550a 100644 --- a/tests/baselines/reference/parserMemberFunctionDeclaration5.errors.txt +++ b/tests/baselines/reference/parserMemberFunctionDeclaration5.errors.txt @@ -1,12 +1,9 @@ tests/cases/conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration5.ts(2,5): error TS1031: 'declare' modifier cannot appear on a class element. -tests/cases/conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration5.ts(2,19): error TS1183: An implementation cannot be declared in ambient contexts. -==== tests/cases/conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration5.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration5.ts (1 errors) ==== class C { declare Foo() { } ~~~~~~~ !!! error TS1031: 'declare' modifier cannot appear on a class element. - ~ -!!! error TS1183: An implementation cannot be declared in ambient contexts. } \ No newline at end of file