diff --git a/src/compiler/_namespaces/ts.ts b/src/compiler/_namespaces/ts.ts index 20fa80074efca..4026133359586 100644 --- a/src/compiler/_namespaces/ts.ts +++ b/src/compiler/_namespaces/ts.ts @@ -57,7 +57,6 @@ export * from "../transformers/module/system"; export * from "../transformers/module/esnextAnd2015"; export * from "../transformers/module/node"; export * from "../transformers/declarations/diagnostics"; -export * from "../transformers/declarations/emitBinder"; export * from "../transformers/declarations/emitResolver"; export * from "../transformers/declarations/transpileDeclaration"; export * from "../transformers/declarations/localInferenceResolver"; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index aa13fd95c7636..34feb987c932d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -116,6 +116,7 @@ import { createModeAwareCacheKey, createModuleNotFoundChain, createMultiMap, + createNameResolver, createPrinterWithDefaults, createPrinterWithRemoveComments, createPrinterWithRemoveCommentsNeverAsciiEscape, @@ -189,6 +190,7 @@ import { find, findAncestor, findBestPatternMatch, + findConstructorDeclaration, findIndex, findLast, findLastIndex, @@ -241,7 +243,6 @@ import { getAllJSDocTags, getAllowSyntheticDefaultImports, getAncestor, - getAnyImportSyntax, getAssignedExpandoInitializer, getAssignmentDeclarationKind, getAssignmentDeclarationPropertyAccessKind, @@ -324,11 +325,11 @@ import { getJSXTransformEnabled, getLeftmostAccessExpression, getLineAndCharacterOfPosition, - getLocalSymbolForExportDefault, getMembersOfDeclaration, getModeForUsageLocation, getModifiers, getModuleInstanceState, + getModuleSpecifierForImportOrExport, getNameFromImportAttribute, getNameFromIndexInfo, getNameOfDeclaration, @@ -486,7 +487,6 @@ import { isCatchClauseVariableDeclarationOrBindingElement, isCheckJsEnabledForFile, isClassDeclaration, - isClassElement, isClassExpression, isClassInstanceProperty, isClassLike, @@ -497,6 +497,7 @@ import { isCompoundAssignment, isComputedNonLiteralName, isComputedPropertyName, + isConstAssertion, isConstructorDeclaration, isConstructorTypeNode, isConstructSignatureDeclaration, @@ -602,7 +603,6 @@ import { isJSDocParameterTag, isJSDocPropertyLikeTag, isJSDocPropertyTag, - isJSDocReturnTag, isJSDocSatisfiesExpression, isJSDocSatisfiesTag, isJSDocSignature, @@ -613,7 +613,6 @@ import { isJSDocTypedefTag, isJSDocTypeExpression, isJSDocTypeLiteral, - isJSDocTypeTag, isJSDocUnknownType, isJSDocVariadicType, isJsonSourceFile, @@ -658,7 +657,6 @@ import { isNewExpression, isNodeDescendantOf, isNonNullAccess, - isNullishCoalesce, isNumericLiteral, isNumericLiteralName, isObjectBindingPattern, @@ -1477,7 +1475,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : ObjectFlags.FreshLiteral; var exactOptionalPropertyTypes = compilerOptions.exactOptionalPropertyTypes; - var { hasVisibleDeclarations, isEntityNameVisible } = createEntityVisibilityChecker({ + var { hasVisibleDeclarations, isEntityNameVisible, collectLinkedAliases } = createEntityVisibilityChecker({ defaultSymbolAccessibility: SymbolAccessibility.NotAccessible, isThisAccessible, isDeclarationVisible, @@ -1485,6 +1483,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getNodeLinks(declaration).isVisible = true; }, resolveName, + getTargetOfExportSpecifier, }); var checkBinaryExpression = createCheckBinaryExpression(); var emitResolver = createResolver(); @@ -1869,6 +1868,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { typeHasCallOrConstructSignatures, }; + var resolveNameHelper = createNameResolver( + compilerOptions, + getSymbolOfDeclaration, + error, + globals, + argumentsSymbol, + requireSymbol, + emptySymbols, + extendedResolveErrorReporting, + getSymbol, + getNodeLinks, + ); + var resolveNameHelperForSuggestions = createNameResolver( + compilerOptions, + getSymbolOfDeclaration, + error, + globals, + argumentsSymbol, + requireSymbol, + emptySymbols, + extendedResolveErrorReporting, + suggestionGetSymbol, + getNodeLinks, + ); + function getCandidateSignaturesForStringLiteralCompletions(call: CallLikeExpression, editingArgument: Node) { const candidatesSet = new Set(); const candidates: Signature[] = []; @@ -3010,74 +3034,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function useOuterVariableScopeInParameter(result: Symbol, location: Node, lastLocation: Node) { - const target = getEmitScriptTarget(compilerOptions); - const functionLocation = location as FunctionLikeDeclaration; - if ( - isParameter(lastLocation) - && functionLocation.body - && result.valueDeclaration - && result.valueDeclaration.pos >= functionLocation.body.pos - && result.valueDeclaration.end <= functionLocation.body.end - ) { - // check for several cases where we introduce temporaries that require moving the name/initializer of the parameter to the body - // - static field in a class expression - // - optional chaining pre-es2020 - // - nullish coalesce pre-es2020 - // - spread assignment in binding pattern pre-es2017 - if (target >= ScriptTarget.ES2015) { - const links = getNodeLinks(functionLocation); - if (links.declarationRequiresScopeChange === undefined) { - links.declarationRequiresScopeChange = forEach(functionLocation.parameters, requiresScopeChange) || false; - } - return !links.declarationRequiresScopeChange; - } - } - return false; - - function requiresScopeChange(node: ParameterDeclaration): boolean { - return requiresScopeChangeWorker(node.name) - || !!node.initializer && requiresScopeChangeWorker(node.initializer); - } - - function requiresScopeChangeWorker(node: Node): boolean { - switch (node.kind) { - case SyntaxKind.ArrowFunction: - case SyntaxKind.FunctionExpression: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.Constructor: - // do not descend into these - return false; - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.PropertyAssignment: - return requiresScopeChangeWorker((node as MethodDeclaration | AccessorDeclaration | PropertyAssignment).name); - case SyntaxKind.PropertyDeclaration: - // static properties in classes introduce temporary variables - if (hasStaticModifier(node)) { - return !emitStandardClassFields; - } - return requiresScopeChangeWorker((node as PropertyDeclaration).name); - default: - // null coalesce and optional chain pre-es2020 produce temporary variables - if (isNullishCoalesce(node) || isOptionalChain(node)) { - return target < ScriptTarget.ES2020; - } - if (isBindingElement(node) && node.dotDotDotToken && isObjectBindingPattern(node.parent)) { - return target < ScriptTarget.ES2017; - } - if (isTypeNode(node)) return false; - return forEachChild(node, requiresScopeChangeWorker) || false; - } - } - } - - function isConstAssertion(location: Node) { - return (isAssertionExpression(location) && isConstTypeReference(location.type)) - || (isJSDocTypeTag(location) && isConstTypeReference(location.typeExpression)); - } - /** * Resolve a given name for a given meaning at a given location. An error is reported if the name was not found and * the nameNotFoundMessage argument is not undefined. Returns the resolved symbol, or undefined if no symbol with @@ -3096,413 +3052,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { excludeGlobals = false, getSpellingSuggestions = true, ): Symbol | undefined { - return resolveNameHelper(location, name, meaning, nameNotFoundMessage, nameArg, isUse, excludeGlobals, getSpellingSuggestions, getSymbol); + return resolveNameHelper(location, name, meaning, nameNotFoundMessage, nameArg, isUse, excludeGlobals, getSpellingSuggestions); } - function resolveNameHelper( - location: Node | undefined, + // The invalid initializer error is needed in two situation: + // 1. When result of name lookup is undefined, after checking for a missing "this." + // 2. When result of name lookup is defined + function checkAndReportErrorForInvalidInitializer(errorLocation: Node | undefined, propertyWithInvalidInitializer: PropertyDeclaration | undefined, nameArg: __String | Identifier | undefined) { + if (propertyWithInvalidInitializer && !emitStandardClassFields) { + // We have a match, but the reference occurred within a property initializer and the identifier also binds + // to a local variable in the constructor where the code will be emitted. Note that this is actually allowed + // with emitStandardClassFields because the scope semantics are different. + error( + errorLocation, + errorLocation && propertyWithInvalidInitializer.type && textRangeContainsPositionInclusive(propertyWithInvalidInitializer.type, errorLocation.pos) + ? Diagnostics.Type_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor + : Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor, + declarationNameToString(propertyWithInvalidInitializer.name), + diagnosticName(nameArg!), + ); + return true; + } + return false; + } + + function extendedResolveErrorReporting( + result: Symbol | undefined, + originalLocation: Node | undefined, name: __String, meaning: SymbolFlags, nameNotFoundMessage: DiagnosticMessage | undefined, nameArg: __String | Identifier | undefined, - isUse: boolean, - excludeGlobals: boolean, getSpellingSuggestions: boolean, - lookup: typeof getSymbol, - ): Symbol | undefined { - const originalLocation = location; // needed for did-you-mean error reporting, which gathers candidates starting from the original location - let result: Symbol | undefined; - let lastLocation: Node | undefined; - let lastSelfReferenceLocation: Declaration | undefined; - let propertyWithInvalidInitializer: PropertyDeclaration | undefined; - let associatedDeclarationForContainingInitializerOrBindingName: ParameterDeclaration | BindingElement | undefined; - let withinDeferredContext = false; - const errorLocation = location; - let grandparent: Node; - let isInExternalModule = false; - - loop: - while (location) { - if (name === "const" && isConstAssertion(location)) { - // `const` in an `as const` has no symbol, but issues no error because there is no *actual* lookup of the type - // (it refers to the constant type of the expression instead) - return undefined; - } - if (isModuleOrEnumDeclaration(location) && lastLocation && location.name === lastLocation) { - // If lastLocation is the name of a namespace or enum, skip the parent since it will have is own locals that could - // conflict. - lastLocation = location; - location = location.parent; - } - // Locals of a source file are not in scope (because they get merged into the global symbol table) - if (canHaveLocals(location) && location.locals && !isGlobalSourceFile(location)) { - if (result = lookup(location.locals, name, meaning)) { - let useResult = true; - if (isFunctionLike(location) && lastLocation && lastLocation !== (location as FunctionLikeDeclaration).body) { - // symbol lookup restrictions for function-like declarations - // - Type parameters of a function are in scope in the entire function declaration, including the parameter - // list and return type. However, local types are only in scope in the function body. - // - parameters are only in the scope of function body - // This restriction does not apply to JSDoc comment types because they are parented - // at a higher level than type parameters would normally be - if (meaning & result.flags & SymbolFlags.Type && lastLocation.kind !== SyntaxKind.JSDoc) { - useResult = result.flags & SymbolFlags.TypeParameter - // type parameters are visible in parameter list, return type and type parameter list - ? lastLocation === (location as FunctionLikeDeclaration).type || - lastLocation.kind === SyntaxKind.Parameter || - lastLocation.kind === SyntaxKind.JSDocParameterTag || - lastLocation.kind === SyntaxKind.JSDocReturnTag || - lastLocation.kind === SyntaxKind.TypeParameter - // local types not visible outside the function body - : false; - } - if (meaning & result.flags & SymbolFlags.Variable) { - // expression inside parameter will lookup as normal variable scope when targeting es2015+ - if (useOuterVariableScopeInParameter(result, location, lastLocation)) { - useResult = false; - } - else if (result.flags & SymbolFlags.FunctionScopedVariable) { - // parameters are visible only inside function body, parameter list and return type - // technically for parameter list case here we might mix parameters and variables declared in function, - // however it is detected separately when checking initializers of parameters - // to make sure that they reference no variables declared after them. - useResult = lastLocation.kind === SyntaxKind.Parameter || - ( - lastLocation === (location as FunctionLikeDeclaration).type && - !!findAncestor(result.valueDeclaration, isParameter) - ); - } - } - } - else if (location.kind === SyntaxKind.ConditionalType) { - // A type parameter declared using 'infer T' in a conditional type is visible only in - // the true branch of the conditional type. - useResult = lastLocation === location.trueType; - } - - if (useResult) { - break loop; - } - else { - result = undefined; - } - } - } - withinDeferredContext = withinDeferredContext || getIsDeferredContext(location, lastLocation); - switch (location.kind) { - case SyntaxKind.SourceFile: - if (!isExternalOrCommonJsModule(location as SourceFile)) break; - isInExternalModule = true; - // falls through - case SyntaxKind.ModuleDeclaration: - const moduleExports = getSymbolOfDeclaration(location as SourceFile | ModuleDeclaration)?.exports || emptySymbols; - if (location.kind === SyntaxKind.SourceFile || (isModuleDeclaration(location) && location.flags & NodeFlags.Ambient && !isGlobalScopeAugmentation(location))) { - // It's an external module. First see if the module has an export default and if the local - // name of that export default matches. - if (result = moduleExports.get(InternalSymbolName.Default)) { - const localSymbol = getLocalSymbolForExportDefault(result); - if (localSymbol && (result.flags & meaning) && localSymbol.escapedName === name) { - break loop; - } - result = undefined; - } - - // Because of module/namespace merging, a module's exports are in scope, - // yet we never want to treat an export specifier as putting a member in scope. - // Therefore, if the name we find is purely an export specifier, it is not actually considered in scope. - // Two things to note about this: - // 1. We have to check this without calling getSymbol. The problem with calling getSymbol - // on an export specifier is that it might find the export specifier itself, and try to - // resolve it as an alias. This will cause the checker to consider the export specifier - // a circular alias reference when it might not be. - // 2. We check === SymbolFlags.Alias in order to check that the symbol is *purely* - // an alias. If we used &, we'd be throwing out symbols that have non alias aspects, - // which is not the desired behavior. - const moduleExport = moduleExports.get(name); - if ( - moduleExport && - moduleExport.flags === SymbolFlags.Alias && - (getDeclarationOfKind(moduleExport, SyntaxKind.ExportSpecifier) || getDeclarationOfKind(moduleExport, SyntaxKind.NamespaceExport)) - ) { - break; - } - } - - // 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))) { - if (isSourceFile(location) && location.commonJsModuleIndicator && !result.declarations?.some(isJSDocTypeAlias)) { - result = undefined; - } - else { - break loop; - } - } - break; - case SyntaxKind.EnumDeclaration: - if (result = lookup(getSymbolOfDeclaration(location as EnumDeclaration)?.exports || emptySymbols, name, meaning & SymbolFlags.EnumMember)) { - if (nameNotFoundMessage && getIsolatedModules(compilerOptions) && !(location.flags & NodeFlags.Ambient) && getSourceFileOfNode(location) !== getSourceFileOfNode(result.valueDeclaration)) { - error( - errorLocation, - Diagnostics.Cannot_access_0_from_another_file_without_qualification_when_1_is_enabled_Use_2_instead, - unescapeLeadingUnderscores(name), - isolatedModulesLikeFlagName, - `${unescapeLeadingUnderscores(getSymbolOfNode(location)!.escapedName)}.${unescapeLeadingUnderscores(name)}`, - ); - } - break loop; - } - break; - case SyntaxKind.PropertyDeclaration: - // TypeScript 1.0 spec (April 2014): 8.4.1 - // Initializer expressions for instance member variables are evaluated in the scope - // of the class constructor body but are not permitted to reference parameters or - // local variables of the constructor. This effectively means that entities from outer scopes - // by the same name as a constructor parameter or local variable are inaccessible - // in initializer expressions for instance member variables. - if (!isStatic(location)) { - const ctor = findConstructorDeclaration(location.parent as ClassLikeDeclaration); - if (ctor && ctor.locals) { - if (lookup(ctor.locals, name, meaning & SymbolFlags.Value)) { - // Remember the property node, it will be used later to report appropriate error - Debug.assertNode(location, isPropertyDeclaration); - propertyWithInvalidInitializer = location; - } - } - } - break; - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - case SyntaxKind.InterfaceDeclaration: - // The below is used to lookup type parameters within a class or interface, as they are added to the class/interface locals - // These can never be latebound, so the symbol's raw members are sufficient. `getMembersOfNode` cannot be used, as it would - // trigger resolving late-bound names, which we may already be in the process of doing while we're here! - if (result = lookup(getSymbolOfDeclaration(location as ClassLikeDeclaration | InterfaceDeclaration).members || emptySymbols, name, meaning & SymbolFlags.Type)) { - if (!isTypeParameterSymbolDeclaredInContainer(result, location)) { - // ignore type parameters not declared in this container - result = undefined; - break; - } - if (lastLocation && isStatic(lastLocation)) { - // TypeScript 1.0 spec (April 2014): 3.4.1 - // The scope of a type parameter extends over the entire declaration with which the type - // parameter list is associated, with the exception of static member declarations in classes. - if (nameNotFoundMessage) { - error(errorLocation, Diagnostics.Static_members_cannot_reference_class_type_parameters); - } - return undefined; - } - break loop; - } - if (isClassExpression(location) && meaning & SymbolFlags.Class) { - const className = location.name; - if (className && name === className.escapedText) { - result = location.symbol; - break loop; - } - } - break; - case SyntaxKind.ExpressionWithTypeArguments: - // The type parameters of a class are not in scope in the base class expression. - if (lastLocation === (location as ExpressionWithTypeArguments).expression && (location.parent as HeritageClause).token === SyntaxKind.ExtendsKeyword) { - const container = location.parent.parent; - if (isClassLike(container) && (result = lookup(getSymbolOfDeclaration(container).members!, name, meaning & SymbolFlags.Type))) { - if (nameNotFoundMessage) { - error(errorLocation, Diagnostics.Base_class_expressions_cannot_reference_class_type_parameters); - } - return undefined; - } - } - break; - // It is not legal to reference a class's own type parameters from a computed property name that - // belongs to the class. For example: - // - // function foo() { return '' } - // class C { // <-- Class's own type parameter T - // [foo()]() { } // <-- Reference to T from class's own computed property - // } - // - case SyntaxKind.ComputedPropertyName: - grandparent = location.parent.parent; - if (isClassLike(grandparent) || grandparent.kind === SyntaxKind.InterfaceDeclaration) { - // A reference to this grandparent's type parameters would be an error - if (result = lookup(getSymbolOfDeclaration(grandparent as ClassLikeDeclaration | InterfaceDeclaration).members!, name, meaning & SymbolFlags.Type)) { - if (nameNotFoundMessage) { - error(errorLocation, Diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type); - } - return undefined; - } - } - break; - case SyntaxKind.ArrowFunction: - // when targeting ES6 or higher there is no 'arguments' in an arrow function - // for lower compile targets the resolved symbol is used to emit an error - if (getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015) { - break; - } - // falls through - case SyntaxKind.MethodDeclaration: - case SyntaxKind.Constructor: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.FunctionDeclaration: - if (meaning & SymbolFlags.Variable && name === "arguments") { - result = argumentsSymbol; - break loop; - } - break; - case SyntaxKind.FunctionExpression: - if (meaning & SymbolFlags.Variable && name === "arguments") { - result = argumentsSymbol; - break loop; - } - - if (meaning & SymbolFlags.Function) { - const functionName = (location as FunctionExpression).name; - if (functionName && name === functionName.escapedText) { - result = (location as FunctionExpression).symbol; - break loop; - } - } - break; - case SyntaxKind.Decorator: - // Decorators are resolved at the class declaration. Resolving at the parameter - // or member would result in looking up locals in the method. - // - // function y() {} - // class C { - // method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter. - // } - // - if (location.parent && location.parent.kind === SyntaxKind.Parameter) { - location = location.parent; - } - // - // function y() {} - // class C { - // @y method(x, y) {} // <-- decorator y should be resolved at the class declaration, not the method. - // } - // - - // class Decorators are resolved outside of the class to avoid referencing type parameters of that class. - // - // type T = number; - // declare function y(x: T): any; - // @param(1 as T) // <-- T should resolve to the type alias outside of class C - // class C {} - if (location.parent && (isClassElement(location.parent) || location.parent.kind === SyntaxKind.ClassDeclaration)) { - location = location.parent; - } - break; - case SyntaxKind.JSDocTypedefTag: - case SyntaxKind.JSDocCallbackTag: - case SyntaxKind.JSDocEnumTag: - // js type aliases do not resolve names from their host, so skip past it - const root = getJSDocRoot(location); - if (root) { - location = root.parent; - } - break; - case SyntaxKind.Parameter: - if ( - lastLocation && ( - lastLocation === (location as ParameterDeclaration).initializer || - lastLocation === (location as ParameterDeclaration).name && isBindingPattern(lastLocation) - ) - ) { - if (!associatedDeclarationForContainingInitializerOrBindingName) { - associatedDeclarationForContainingInitializerOrBindingName = location as ParameterDeclaration; - } - } - break; - case SyntaxKind.BindingElement: - if ( - lastLocation && ( - lastLocation === (location as BindingElement).initializer || - lastLocation === (location as BindingElement).name && isBindingPattern(lastLocation) - ) - ) { - if (isParameterDeclaration(location as BindingElement) && !associatedDeclarationForContainingInitializerOrBindingName) { - associatedDeclarationForContainingInitializerOrBindingName = location as BindingElement; - } - } - break; - case SyntaxKind.InferType: - if (meaning & SymbolFlags.TypeParameter) { - const parameterName = (location as InferTypeNode).typeParameter.name; - if (parameterName && name === parameterName.escapedText) { - result = (location as InferTypeNode).typeParameter.symbol; - break loop; - } - } - break; - case SyntaxKind.ExportSpecifier: - // External module export bindings shouldn't be resolved to local symbols. - if ( - lastLocation && - lastLocation === (location as ExportSpecifier).propertyName && - (location as ExportSpecifier).parent.parent.moduleSpecifier - ) { - location = location.parent.parent.parent; - } - break; - } - if (isSelfReferenceLocation(location)) { - lastSelfReferenceLocation = location; - } - lastLocation = location; - location = isJSDocTemplateTag(location) ? getEffectiveContainerForJSDocTemplateTag(location) || location.parent : - isJSDocParameterTag(location) || isJSDocReturnTag(location) ? getHostSignatureFromJSDoc(location) || location.parent : - location.parent; - } - - // We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`. - // If `result === lastSelfReferenceLocation.symbol`, that means that we are somewhere inside `lastSelfReferenceLocation` looking up a name, and resolving to `lastLocation` itself. - // That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used. - if (isUse && result && (!lastSelfReferenceLocation || result !== lastSelfReferenceLocation.symbol)) { - result.isReferenced! |= meaning; - } - - if (!result) { - if (lastLocation) { - Debug.assertNode(lastLocation, isSourceFile); - if (lastLocation.commonJsModuleIndicator && name === "exports" && meaning & lastLocation.symbol.flags) { - return lastLocation.symbol; - } - } - - if (!excludeGlobals) { - result = lookup(globals, name, meaning); - } - } - if (!result) { - if (originalLocation && isInJSFile(originalLocation) && originalLocation.parent) { - if (isRequireCall(originalLocation.parent, /*requireStringLiteralLikeArgument*/ false)) { - return requireSymbol; - } - } - } - - // The invalid initializer error is needed in two situation: - // 1. When result is undefined, after checking for a missing "this." - // 2. When result is defined - function checkAndReportErrorForInvalidInitializer() { - if (propertyWithInvalidInitializer && !emitStandardClassFields) { - // We have a match, but the reference occurred within a property initializer and the identifier also binds - // to a local variable in the constructor where the code will be emitted. Note that this is actually allowed - // with emitStandardClassFields because the scope semantics are different. - error( - errorLocation, - errorLocation && propertyWithInvalidInitializer.type && textRangeContainsPositionInclusive(propertyWithInvalidInitializer.type, errorLocation.pos) - ? Diagnostics.Type_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor - : Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor, - declarationNameToString(propertyWithInvalidInitializer.name), - diagnosticName(nameArg!), - ); - return true; - } - return false; - } - + lookup: (symbols: SymbolTable, name: __String, meaning: SymbolFlags) => Symbol | undefined, + lastLocation: Node | undefined, + errorLocation: Node | undefined, + propertyWithInvalidInitializer: PropertyDeclaration | undefined, + associatedDeclarationForContainingInitializerOrBindingName: ParameterDeclaration | BindingElement | undefined, + withinDeferredContext: boolean, + isInExternalModule: boolean, + ) { if (!result) { if (nameNotFoundMessage) { addLazyDiagnostic(() => { @@ -3510,7 +3099,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { !errorLocation || errorLocation.parent.kind !== SyntaxKind.JSDocLink && !checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg!) && // TODO: GH#18217 - !checkAndReportErrorForInvalidInitializer() && + !checkAndReportErrorForInvalidInitializer(errorLocation, propertyWithInvalidInitializer, nameArg) && !checkAndReportErrorForExtendingInterface(errorLocation) && !checkAndReportErrorForUsingTypeAsNamespace(errorLocation, name, meaning) && !checkAndReportErrorForExportingPrimitiveType(errorLocation, name) && @@ -3560,7 +3149,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return undefined; } - else if (nameNotFoundMessage && checkAndReportErrorForInvalidInitializer()) { + else if (nameNotFoundMessage && checkAndReportErrorForInvalidInitializer(errorLocation, propertyWithInvalidInitializer, nameArg)) { return undefined; } @@ -3583,7 +3172,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { (meaning & SymbolFlags.BlockScopedVariable || ((meaning & SymbolFlags.Class || meaning & SymbolFlags.Enum) && (meaning & SymbolFlags.Value) === SymbolFlags.Value)) ) { - const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result!); + const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result); if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable || exportOrLocalSymbol.flags & SymbolFlags.Class || exportOrLocalSymbol.flags & SymbolFlags.Enum) { checkResolvedBlockScopedVariable(exportOrLocalSymbol, errorLocation); } @@ -3656,65 +3245,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ); } - function getIsDeferredContext(location: Node, lastLocation: Node | undefined): boolean { - if (location.kind !== SyntaxKind.ArrowFunction && location.kind !== SyntaxKind.FunctionExpression) { - // initializers in instance property declaration of class like entities are executed in constructor and thus deferred - return isTypeQueryNode(location) || (( - isFunctionLikeDeclaration(location) || - (location.kind === SyntaxKind.PropertyDeclaration && !isStatic(location)) - ) && (!lastLocation || lastLocation !== (location as SignatureDeclaration | PropertyDeclaration).name)); // A name is evaluated within the enclosing scope - so it shouldn't count as deferred - } - if (lastLocation && lastLocation === (location as FunctionExpression | ArrowFunction).name) { - return false; - } - // generator functions and async functions are not inlined in control flow when immediately invoked - if ((location as FunctionExpression | ArrowFunction).asteriskToken || hasSyntacticModifier(location, ModifierFlags.Async)) { - return true; - } - return !getImmediatelyInvokedFunctionExpression(location); - } - - type SelfReferenceLocation = - | FunctionDeclaration - | ClassDeclaration - | InterfaceDeclaration - | EnumDeclaration - | TypeAliasDeclaration - | ModuleDeclaration; - - function isSelfReferenceLocation(node: Node): node is SelfReferenceLocation { - switch (node.kind) { - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.TypeAliasDeclaration: - case SyntaxKind.ModuleDeclaration: // For `namespace N { N; }` - return true; - default: - return false; - } - } - function diagnosticName(nameArg: __String | Identifier | PrivateIdentifier) { return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier); } - function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) { - if (symbol.declarations) { - for (const decl of symbol.declarations) { - if (decl.kind === SyntaxKind.TypeParameter) { - const parent = isJSDocTemplateTag(decl.parent) ? getJSDocHost(decl.parent) : decl.parent; - if (parent === container) { - return !(isJSDocTemplateTag(decl.parent) && find((decl.parent.parent as JSDoc).tags, isJSDocTypeAlias)); - } - } - } - } - - return false; - } - function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: __String, nameArg: __String | Identifier): boolean { if (!isIdentifier(errorLocation) || errorLocation.escapedText !== name || isTypeReferenceIdentifier(errorLocation) || isInTypeQuery(errorLocation)) { return false; @@ -4168,23 +3702,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return exportDefaultSymbol; } - function getModuleSpecifierForImportOrExport(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportOrExportSpecifier): Expression | undefined { - switch (node.kind) { - case SyntaxKind.ImportClause: - return node.parent.moduleSpecifier; - case SyntaxKind.ImportEqualsDeclaration: - return isExternalModuleReference(node.moduleReference) ? node.moduleReference.expression : undefined; - case SyntaxKind.NamespaceImport: - return node.parent.parent.moduleSpecifier; - case SyntaxKind.ImportSpecifier: - return node.parent.parent.parent.moduleSpecifier; - case SyntaxKind.ExportSpecifier: - return node.parent.parent.moduleSpecifier; - default: - return Debug.assertNever(node); - } - } - function reportNonDefaultExport(moduleSymbol: Symbol, node: ImportClause) { if (moduleSymbol.exports?.has(node.symbol.escapedName)) { error( @@ -5747,15 +5264,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ); } - function findConstructorDeclaration(node: ClassLikeDeclaration): ConstructorDeclaration | undefined { - const members = node.members; - for (const member of members) { - if (member.kind === SyntaxKind.Constructor && nodeIsPresent((member as ConstructorDeclaration).body)) { - return member as ConstructorDeclaration; - } - } - } - function createType(flags: TypeFlags): Type { const result = new Type(checker, flags); typeCount++; @@ -10367,49 +9875,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined { - let exportSymbol: Symbol | undefined; - if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) { - exportSymbol = resolveName(node, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, node, /*isUse*/ false); - } - else if (node.parent.kind === SyntaxKind.ExportSpecifier) { - exportSymbol = getTargetOfExportSpecifier(node.parent as ExportSpecifier, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); - } - let result: Node[] | undefined; - let visited: Set | undefined; - if (exportSymbol) { - visited = new Set(); - visited.add(getSymbolId(exportSymbol)); - buildVisibleNodeList(exportSymbol.declarations); - } - return result; - - function buildVisibleNodeList(declarations: Declaration[] | undefined) { - forEach(declarations, declaration => { - const resultNode = getAnyImportSyntax(declaration) || declaration; - if (setVisibility) { - getNodeLinks(declaration).isVisible = true; - } - else { - result = result || []; - pushIfUnique(result, resultNode); - } - - if (isInternalModuleImportEqualsDeclaration(declaration)) { - // Add the referenced top container visible - const internalModuleReference = declaration.moduleReference as Identifier | QualifiedName; - const firstIdentifier = getFirstIdentifier(internalModuleReference); - const importSymbol = resolveName(declaration, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); - if (importSymbol && visited) { - if (tryAddToSet(visited, getSymbolId(importSymbol))) { - buildVisibleNodeList(importSymbol.declarations); - } - } - } - }); - } - } - /** * Push an entry on the type resolution stack. If an entry with the given target and the given property name * is already on the stack, and no entries in between already have a type, then a circularity has occurred. @@ -33144,30 +32609,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return suggestion && symbolName(suggestion); } + function suggestionGetSymbol(symbols: SymbolTable, name: __String, meaning: SymbolFlags) { + // Debug.assertEqual(outerName, name, "name should equal outerName"); + const symbol = getSymbol(symbols, name, meaning); + // Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function + // So the table *contains* `x` but `x` isn't actually in scope. + // However, resolveNameHelper will continue and call this callback again, so we'll eventually get a correct suggestion. + if (symbol) return symbol; + let candidates: Symbol[]; + if (symbols === globals) { + const primitives = mapDefined( + ["string", "number", "boolean", "object", "bigint", "symbol"], + s => symbols.has((s.charAt(0).toUpperCase() + s.slice(1)) as __String) + ? createSymbol(SymbolFlags.TypeAlias, s as __String) as Symbol + : undefined, + ); + candidates = primitives.concat(arrayFrom(symbols.values())); + } + else { + candidates = arrayFrom(symbols.values()); + } + return getSpellingSuggestionForName(unescapeLeadingUnderscores(name), candidates, meaning); + } function getSuggestedSymbolForNonexistentSymbol(location: Node | undefined, outerName: __String, meaning: SymbolFlags): Symbol | undefined { Debug.assert(outerName !== undefined, "outername should always be defined"); - const result = resolveNameHelper(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, outerName, /*isUse*/ false, /*excludeGlobals*/ false, /*getSpellingSuggestions*/ true, (symbols, name, meaning) => { - Debug.assertEqual(outerName, name, "name should equal outerName"); - const symbol = getSymbol(symbols, name, meaning); - // Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function - // So the table *contains* `x` but `x` isn't actually in scope. - // However, resolveNameHelper will continue and call this callback again, so we'll eventually get a correct suggestion. - if (symbol) return symbol; - let candidates: Symbol[]; - if (symbols === globals) { - const primitives = mapDefined( - ["string", "number", "boolean", "object", "bigint", "symbol"], - s => symbols.has((s.charAt(0).toUpperCase() + s.slice(1)) as __String) - ? createSymbol(SymbolFlags.TypeAlias, s as __String) as Symbol - : undefined, - ); - candidates = primitives.concat(arrayFrom(symbols.values())); - } - else { - candidates = arrayFrom(symbols.values()); - } - return getSpellingSuggestionForName(unescapeLeadingUnderscores(name), candidates, meaning); - }); + const result = resolveNameHelperForSuggestions(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, outerName, /*isUse*/ false, /*excludeGlobals*/ false, /*getSpellingSuggestions*/ true); return result; } diff --git a/src/compiler/debug.ts b/src/compiler/debug.ts index aca37cbe325b1..a07e302de0d0c 100644 --- a/src/compiler/debug.ts +++ b/src/compiler/debug.ts @@ -4,6 +4,7 @@ import { AssertionLevel, BigIntLiteralType, CheckMode, + Comparer, compareValues, EmitFlags, every, @@ -356,15 +357,6 @@ export namespace Debug { } } - /** - * Asserts the symbol is defined and is of the right kind (originating in TSC or sample DTE depending o the test that is currently being run) - * The default implementation just asserts the symbol is not null - * In tests it is overridden to ensure we don't accidentally use TSC symbols in DTE - */ - // eslint-disable-next-line prefer-const - export let assertSymbolValid = (symbol: Symbol) => { - assert(symbol, "Symbol not defined"); - }; /** * Asserts a value has the specified type in typespace only (does not perform a runtime assertion). * This is useful in cases where we switch on `node.kind` and can be reasonably sure the type is accurate, and @@ -395,7 +387,7 @@ export namespace Debug { * Formats an enum value as a string for debugging and debug assertions. */ export function formatEnum(value = 0, enumObject: any, isFlags?: boolean) { - const members = getEnumMembers(enumObject); + const members = getEnumMembers(enumObject, isFlags); if (value === 0) { return members.length > 0 && members[0][0] === 0 ? members[0][1] : "0"; } @@ -403,10 +395,10 @@ export namespace Debug { const result: string[] = []; let remainingFlags = value; for (const [enumValue, enumName] of members) { - if (enumValue > value) { + if (enumValue > remainingFlags) { break; } - if (enumValue !== 0 && enumValue & value) { + if (enumValue !== 0 && enumValue & remainingFlags) { result.push(enumName); remainingFlags &= ~enumValue; } @@ -427,7 +419,7 @@ export namespace Debug { const enumMemberCache = new Map>(); - function getEnumMembers(enumObject: any) { + function getEnumMembers(enumObject: any, isFlags?: boolean) { // Assuming enum objects do not change at runtime, we can cache the enum members list // to reuse later. This saves us from reconstructing this each and every time we call // a formatting function (which can be expensive for large enums like SyntaxKind). @@ -444,7 +436,10 @@ export namespace Debug { } } - const sorted = stableSort<[number, string]>(result, (x, y) => compareValues(x[0], y[0])); + const comparer: Comparer<[number, string]> = isFlags ? + (x, y) => compareValues(x[0] >>> 0, y[0] >>> 0) : + (x, y) => compareValues(x[0], y[0]); + const sorted = stableSort(result, comparer); enumMemberCache.set(enumObject, sorted); return sorted; } diff --git a/src/compiler/transformers/declarations/emitBinder.ts b/src/compiler/transformers/declarations/emitBinder.ts deleted file mode 100644 index 08153e76f2f4a..0000000000000 --- a/src/compiler/transformers/declarations/emitBinder.ts +++ /dev/null @@ -1,914 +0,0 @@ -import { - __String, - ArrayBindingElement, - ArrowFunction, - BindingPattern, - CallSignatureDeclaration, - ClassDeclaration, - ClassExpression, - ComputedPropertyName, - ConditionalTypeNode, - ConstructorDeclaration, - ConstructorTypeNode, - ConstructSignatureDeclaration, - Declaration, - EnumDeclaration, - ExportAssignment, - ExportDeclaration, - Expression, - factory, - findAncestor, - forEachChild, - FunctionDeclaration, - FunctionExpression, - FunctionTypeNode, - GetAccessorDeclaration, - getCombinedNodeFlags, - getModuleInstanceState, - getNodeId, - hasAmbientModifier, - hasSyntacticModifier, - ImportDeclaration, - ImportEqualsDeclaration, - InferTypeNode, - InterfaceDeclaration, - isArrayBindingPattern, - isBinaryExpression, - isBindingPattern, - isBlockOrCatchScoped, - isBlockScopedContainerTopLevel, - isComputedPropertyName, - isConditionalTypeNode, - isConstructorDeclaration, - isConstructSignatureDeclaration, - isDeclaration, - isElementAccessExpression, - isEnumConst, - isExpression, - isFunctionDeclaration, - isFunctionExpressionOrArrowFunction, - isIdentifier, - isJsxNamespacedName, - isModuleBlock, - isModuleDeclaration, - isNamedExports, - isNumericLiteral, - isObjectBindingPattern, - isPrefixUnaryExpression, - isPrivateIdentifier, - isPropertyAccessExpression, - isPropertyName, - isSourceFile, - isStringLiteralLike, - isVarConst, - isVariableDeclaration, - MappedTypeNode, - MethodDeclaration, - MethodSignature, - ModifierFlags, - ModuleDeclaration, - ModuleInstanceState, - NamedDeclaration, - Node, - NodeArray, - NodeFlags, - NoSubstitutionTemplateLiteral, - ObjectLiteralExpression, - ParameterDeclaration, - PropertyDeclaration, - PropertyName, - SetAccessorDeclaration, - setValueDeclaration, - SourceFile, - Symbol, - SymbolFlags, - SyntaxKind, - TypeAliasDeclaration, - TypeLiteralNode, - TypeParameterDeclaration, - VariableDeclaration, -} from "../../_namespaces/ts"; - -/** @internal */ -export interface EmitDeclarationNodeLinks { - isVisible?: boolean; - symbol?: EmitDeclarationSymbol; - localSymbol?: EmitDeclarationSymbol; - locals?: EmitDeclarationSymbolTable; - enumValue?: string | number | undefined; -} - -/** @internal */ -export type EmitDeclarationSymbolTable = Map; - -/** @internal */ -export interface EmitDeclarationSymbol { - name?: MemberKey; - parent?: EmitDeclarationSymbol; - exportSymbol?: EmitDeclarationSymbol; - declarations: Declaration[]; - valueDeclaration?: Declaration; - signatureDeclarations?: Node[]; - flags: SymbolFlags; - members?: EmitDeclarationSymbolTable; - exports?: EmitDeclarationSymbolTable; -} - -interface SymbolRegistrationFlags { - includes: SymbolFlags; - excludes: SymbolFlags; -} -const syntaxKindToSymbolMap = { - [SyntaxKind.TypeParameter]: { includes: SymbolFlags.TypeParameter, excludes: SymbolFlags.TypeParameterExcludes }, - [SyntaxKind.Parameter]: { includes: SymbolFlags.FunctionScopedVariable, excludes: SymbolFlags.ParameterExcludes }, - [SyntaxKind.VariableDeclaration]: { - fnScope: { includes: SymbolFlags.FunctionScopedVariable, excludes: SymbolFlags.FunctionScopedVariableExcludes }, - blockScope: { includes: SymbolFlags.BlockScopedVariable, excludes: SymbolFlags.BlockScopedVariableExcludes }, - }, - [SyntaxKind.BindingElement]: { includes: SymbolFlags.BlockScopedVariable, excludes: SymbolFlags.BlockScopedVariableExcludes }, - [SyntaxKind.PropertyDeclaration]: { includes: SymbolFlags.Property, excludes: SymbolFlags.PropertyExcludes }, - [SyntaxKind.PropertySignature]: { includes: SymbolFlags.Property, excludes: SymbolFlags.PropertyExcludes }, - [SyntaxKind.PropertyAssignment]: { includes: SymbolFlags.Property, excludes: SymbolFlags.PropertyExcludes }, - [SyntaxKind.ShorthandPropertyAssignment]: { includes: SymbolFlags.Property, excludes: SymbolFlags.PropertyExcludes }, - [SyntaxKind.EnumMember]: { includes: SymbolFlags.EnumMember, excludes: SymbolFlags.EnumMemberExcludes }, - [SyntaxKind.CallSignature]: { includes: SymbolFlags.Signature, excludes: SymbolFlags.None }, - [SyntaxKind.ConstructSignature]: { includes: SymbolFlags.Signature, excludes: SymbolFlags.None }, - [SyntaxKind.IndexSignature]: { includes: SymbolFlags.Signature, excludes: SymbolFlags.None }, - [SyntaxKind.MethodDeclaration]: { includes: SymbolFlags.Method, excludes: SymbolFlags.MethodExcludes }, - [SyntaxKind.MethodSignature]: { includes: SymbolFlags.Method, excludes: SymbolFlags.MethodExcludes }, - [SyntaxKind.FunctionDeclaration]: { includes: SymbolFlags.Function, excludes: SymbolFlags.FunctionExcludes }, - [SyntaxKind.Constructor]: { includes: SymbolFlags.Constructor, excludes: SymbolFlags.None }, - [SyntaxKind.GetAccessor]: { includes: SymbolFlags.GetAccessor, excludes: SymbolFlags.GetAccessorExcludes }, - [SyntaxKind.SetAccessor]: { includes: SymbolFlags.SetAccessor, excludes: SymbolFlags.SetAccessorExcludes }, - [SyntaxKind.ClassExpression]: { includes: SymbolFlags.Class, excludes: SymbolFlags.ClassExcludes }, - [SyntaxKind.ClassDeclaration]: { includes: SymbolFlags.Class, excludes: SymbolFlags.ClassExcludes }, - [SyntaxKind.InterfaceDeclaration]: { includes: SymbolFlags.Interface, excludes: SymbolFlags.InterfaceExcludes }, - [SyntaxKind.TypeAliasDeclaration]: { includes: SymbolFlags.TypeAlias, excludes: SymbolFlags.TypeAliasExcludes }, - [SyntaxKind.EnumDeclaration]: { - const: { includes: SymbolFlags.ConstEnum, excludes: SymbolFlags.ConstEnumExcludes }, - regular: { includes: SymbolFlags.RegularEnum, excludes: SymbolFlags.RegularEnumExcludes }, - }, - [SyntaxKind.ModuleDeclaration]: { - value: { includes: SymbolFlags.ValueModule, excludes: SymbolFlags.ValueModuleExcludes }, - namespace: { includes: SymbolFlags.NamespaceModule, excludes: SymbolFlags.NamespaceModuleExcludes }, - }, - [SyntaxKind.ImportEqualsDeclaration]: { includes: SymbolFlags.Alias, excludes: SymbolFlags.AliasExcludes }, - [SyntaxKind.NamespaceImport]: { includes: SymbolFlags.Alias, excludes: SymbolFlags.AliasExcludes }, - [SyntaxKind.ImportSpecifier]: { includes: SymbolFlags.Alias, excludes: SymbolFlags.AliasExcludes }, - [SyntaxKind.ExportSpecifier]: { includes: SymbolFlags.Alias | SymbolFlags.ExportValue, excludes: SymbolFlags.AliasExcludes }, - [SyntaxKind.NamespaceExportDeclaration]: { includes: SymbolFlags.Alias, excludes: SymbolFlags.AliasExcludes }, - [SyntaxKind.ImportClause]: { includes: SymbolFlags.Alias, excludes: SymbolFlags.AliasExcludes }, -} as const satisfies Partial>>; - -/** - * Assigning values to a property of a function will usually cause those members to be implicitly declared on the function - * even if they were were not declared (expando functions) - * DTE needs to detect these members and error on them since this behavior is not supported in isolated declarations - * There are however members that can be assigned on a function that are not expando members, namely members that come from Function - * In DTE we do not load the full d.ts so we keep a list of known members of function that can be assigned without considering them expando members. - */ -const knownFunctionMembers = new Set([ - "I:apply", - "I:call", - "I:bind", - "I:toString", - "I:prototype", - "I:length", -]); - -/** @internal */ -export function bindSourceFileForDeclarationEmit(file: SourceFile) { - const nodeLinks: EmitDeclarationNodeLinks[] = []; - function tryGetNodeLinks(node: Node): EmitDeclarationNodeLinks | undefined { - const id = node.id; - if (!id) return undefined; - return nodeLinks[id]; - } - function getNodeLinks(node: Node): EmitDeclarationNodeLinks { - const nodeId = getNodeId(node); - return nodeLinks[nodeId] || (nodeLinks[nodeId] = {}); - } - - bind(); - - return { - tryGetNodeLinks, - getNodeLinks, - resolveName, - resolveMemberKey, - resolveEntityName, - getMemberKey, - }; - - function resolveEntityName(location: Node, node: Expression, meaning: SymbolFlags): EmitDeclarationSymbol | undefined { - if (isIdentifier(node)) { - return resolveName(location, node.escapedText, meaning); - } - else if (isPropertyAccessExpression(node) || isElementAccessExpression(node)) { - const symbol = resolveEntityName(location, node.expression, meaning); - if (symbol === undefined) return undefined; - - const name = isElementAccessExpression(node) ? node.argumentExpression : node.name; - if (!isPropertyName(name)) return; - - const memberSymbol = symbol.exports?.get(getMemberKey(name)); - if (!memberSymbol || !(memberSymbol.flags & meaning)) { - if (symbol.valueDeclaration && isModuleDeclaration(symbol.valueDeclaration)) { - return getNodeLinks(symbol.valueDeclaration)?.locals?.get(getMemberKey(name)); - } - return undefined; - } - return memberSymbol; - } - else { - return undefined; - } - } - - function resolveName(enclosingDeclaration: Node, escapedText: __String, meaning: SymbolFlags) { - return resolveMemberKey(enclosingDeclaration, getMemberKey(escapedText as string), meaning); - } - function resolveMemberKey(enclosingDeclaration: Node, key: MemberKey, meaning: SymbolFlags) { - function getSymbolFromScope(table: EmitDeclarationSymbolTable | undefined) { - const symbol = table?.get(key); - if (symbol && ((symbol.flags & meaning) || (symbol.flags & SymbolFlags.Alias))) { - return symbol; - } - } - - let currentScope = enclosingDeclaration; - while (currentScope) { - const links = tryGetNodeLinks(currentScope); - let symbol = getSymbolFromScope(links?.locals); - if (!symbol && (isModuleDeclaration(currentScope) || isSourceFile(currentScope))) { - symbol = getSymbolFromScope(links?.symbol?.exports); - } - if (symbol) return symbol; - currentScope = currentScope.parent; - } - return undefined; - } - - function tryGetSymbolFlagsForNode(node: Node): SymbolRegistrationFlags | undefined { - return getSymbolFlagsForNode(node as Node & { kind: keyof typeof syntaxKindToSymbolMap; }); - } - function getSymbolFlagsForNode(node: Node & { kind: keyof typeof syntaxKindToSymbolMap; }): SymbolRegistrationFlags { - if (node.kind === SyntaxKind.VariableDeclaration) { - return getCombinedNodeFlags(node) & NodeFlags.BlockScoped ? - syntaxKindToSymbolMap[node.kind].blockScope : - syntaxKindToSymbolMap[node.kind].fnScope; - } - if (node.kind === SyntaxKind.EnumDeclaration) { - return isEnumConst(node as EnumDeclaration) ? - syntaxKindToSymbolMap[node.kind].const : - syntaxKindToSymbolMap[node.kind].regular; - } - if (node.kind === SyntaxKind.ModuleDeclaration) { - return getModuleInstanceState(node as ModuleDeclaration) === ModuleInstanceState.Instantiated ? - syntaxKindToSymbolMap[node.kind].value : - syntaxKindToSymbolMap[node.kind].namespace; - } - return syntaxKindToSymbolMap[node.kind]; - } - function bind() { - /* eslint-disable no-var */ - var currentScope: Node = undefined!; - var currentFunctionLocalSymbolTable: EmitDeclarationSymbolTable = undefined!; - var currentParent: EmitDeclarationSymbol = undefined!; - var currentLocalSymbolTable: EmitDeclarationSymbolTable = undefined!; - var currentExportsSymbolTable: EmitDeclarationSymbolTable | undefined; - var postBindingAction: (() => void)[] = []; - - var fileLinks = getNodeLinks(file).symbol = createEmitSymbol(); - fileLinks.declarations.push(file); - setValueDeclaration(fileLinks as Symbol, file); - /* eslint-enable no-var */ - fileLinks.exports = new Map(); - withScope(file, fileLinks.exports, () => bindEachFunctionsFirst(file.statements)); - postBindingAction.forEach(fn => fn()); - - function createAnonymousEmitSymbol(node: Declaration): EmitDeclarationSymbol { - const symbol = createEmitSymbol(); - symbol.declarations.push(node); - setValueDeclaration(symbol as Symbol, node); - node.symbol = symbol as Symbol; - return symbol; - } - function createEmitSymbol(): EmitDeclarationSymbol { - return { - parent: currentParent, - declarations: [], - flags: 0, - }; - } - function getSymbol(table: EmitDeclarationSymbolTable, name: MemberKey) { - let symbol = table.get(name); - if (!symbol) { - symbol = createEmitSymbol(); - symbol.name = name; - table.set(name, symbol); - } - return symbol; - } - function addLocalAndExportDeclaration(name: LocalAndExportName | MemberKey | undefined, node: Declaration, flags: SymbolRegistrationFlags, isExport: boolean, isBlockScoped = true) { - const { exportName, localName } = typeof name === "object" ? name : { exportName: name, localName: name }; - if (isExport) { - const exportKind = flags.includes & SymbolFlags.Value ? SymbolFlags.ExportValue : 0; - const localSymbol = addLocalOnlyDeclaration(localName, node, { includes: exportKind, excludes: flags.excludes }, isBlockScoped); - const exportSymbol = addExportOnlyDeclaration(exportName, node, flags); - localSymbol.exportSymbol = exportSymbol; - // Export symbol can be undefined if the export modifier was placed in an unexpected position. - // We just assume the local symbol should be used. There are already bigger issues in the file anyway. - return exportSymbol ?? localSymbol; - } - else { - return addLocalOnlyDeclaration(localName, node, flags, isBlockScoped); - } - } - function addExportOnlyDeclaration(name: MemberKey | undefined, node: Declaration, flagsAndForbiddenFlags: SymbolRegistrationFlags) { - if (!currentExportsSymbolTable) { - return undefined; - } - return addDeclaration(currentExportsSymbolTable, name, node, flagsAndForbiddenFlags); - } - function addLocalOnlyDeclaration(name: MemberKey | undefined, node: Declaration, flagsAndForbiddenFlags: SymbolRegistrationFlags, isBlockScoped = true) { - return addDeclaration(isBlockScoped ? currentLocalSymbolTable : currentFunctionLocalSymbolTable, name, node, flagsAndForbiddenFlags); - } - - function addDeclaration(table: EmitDeclarationSymbolTable, name: MemberKey | undefined, node: Declaration, { includes, excludes }: SymbolRegistrationFlags) { - let symbol = name !== undefined ? getSymbol(table, name) : createEmitSymbol(); - // Symbols don't merge, create new one - if (excludes & symbol.flags) { - // Variables and expando members from assignments are always allowed to merge - if (!(includes & SymbolFlags.Variable && symbol.flags & SymbolFlags.Assignment)) { - symbol = createEmitSymbol(); - } - } - symbol.declarations.push(node); - setValueDeclaration(symbol as Symbol, node); - symbol.flags |= includes; - getNodeLinks(node).symbol = symbol; - // Some parts of declarations.ts use the symbol directly. We provide enough of it for everything to work. - node.symbol = symbol as Symbol; - return symbol; - } - function withScope(scope: Node, exports: EmitDeclarationSymbolTable | undefined, fn: () => void) { - const old = [currentScope, currentParent, currentFunctionLocalSymbolTable, currentLocalSymbolTable, currentExportsSymbolTable] as const; - currentScope = scope; - const links = getNodeLinks(scope); - currentLocalSymbolTable = links.locals ??= new Map(); - currentParent = links.symbol ?? currentParent; - currentExportsSymbolTable = exports; - if (isBlockScopedContainerTopLevel(scope)) { - currentFunctionLocalSymbolTable = currentLocalSymbolTable; - } - fn(); - [currentScope, currentParent, currentFunctionLocalSymbolTable, currentLocalSymbolTable, currentExportsSymbolTable] = old; - } - function withMembers(symbol: EmitDeclarationSymbol, addToExports = false, fn: () => void) { - const old = [currentLocalSymbolTable, currentParent] as const; - currentParent = symbol; - currentLocalSymbolTable = addToExports ? symbol.exports ??= new Map() : symbol.members ??= new Map(); - fn(); - [currentLocalSymbolTable, currentParent] = old; - } - - interface LocalAndExportName { - exportName?: MemberKey; - localName?: MemberKey; - } - function getStatementName(s: NamedDeclaration): undefined | MemberKey | LocalAndExportName { - if (hasSyntacticModifier(s, ModifierFlags.Export) && hasSyntacticModifier(s, ModifierFlags.Default)) { - return { - exportName: "default" as MemberKey, - localName: getMemberKeyFromElement(s), - }; - } - if (s) { - return getMemberKeyFromElement(s); - } - } - - function bindTypeParameters(typeParameters: TypeParameterDeclaration[] | NodeArray | undefined) { - typeParameters?.forEach(t => addLocalOnlyDeclaration(getMemberKey(t.name), t, getSymbolFlagsForNode(t))); - } - function bindVariable(d: VariableDeclaration | ParameterDeclaration | PropertyDeclaration) { - bindNode(d.type); - const isExported = isExportedVariable(d); - const isBlockScoped = isBlockOrCatchScoped(d); - if (d.initializer) { - bindNode(d.initializer); - } - if (isBindingPattern(d.name)) { - function bindBindingPattern(pattern: BindingPattern) { - // type BindingPattern = ObjectBindingPattern | ArrayBindingPattern; - (pattern.elements as NodeArray).forEach(b => { - if (b.kind === SyntaxKind.OmittedExpression) return; - if (!b.name) return; - - if (isIdentifier(b.name)) { - addLocalAndExportDeclaration(getMemberKey(b.name), b, getSymbolFlagsForNode(b), isExported, isBlockScoped); - } - else { - bindBindingPattern(b.name); - } - }); - } - bindBindingPattern(d.name); - } - else { - addLocalAndExportDeclaration(getMemberKeyFromElement(d), d, getSymbolFlagsForNode(d), isExported, isBlockScoped); - } - function isExportedVariable(d: VariableDeclaration | ParameterDeclaration | PropertyDeclaration) { - if (!isVariableDeclaration(d)) return false; - // exported directly - if (hasSyntacticModifier(d.parent.parent, ModifierFlags.Export)) { - return true; - } - // or part of an ambient module declaration - const module = findAncestor(d, isBlockScopedContainerTopLevel); - return !!module && hasAmbientModifier(module); - } - } - function bindEachFunctionsFirst(nodes: NodeArray | undefined): void { - if (!nodes) return; - bindContainer(nodes, n => n.kind === SyntaxKind.FunctionDeclaration); - bindContainer(nodes, n => n.kind !== SyntaxKind.FunctionDeclaration); - } - function bindExpandoMembers(expression: Node) { - if (isBinaryExpression(expression) && expression.operatorToken.kind === SyntaxKind.EqualsToken) { - const assignmentTarget = expression.left; - const isPropertyAccess = isPropertyAccessExpression(assignmentTarget); - if ( - (isPropertyAccess || isElementAccessExpression(assignmentTarget)) - ) { - let name; - if (isPropertyAccess) { - name = assignmentTarget.name; - } - else { - const argumentExpression = assignmentTarget.argumentExpression; - name = factory.createComputedPropertyName(argumentExpression); - } - const key = getMemberKey(name); - if (!key || knownFunctionMembers.has(key)) return; - const target = resolveEntityName(expression, assignmentTarget.expression, SymbolFlags.Value | SymbolFlags.ExportValue); - if (!target) return; - const fn = target.declarations.find(canHaveExpandoMembers); - if (!fn) return; - - const parentLocals = target.parent?.valueDeclaration && getNodeLinks(target.parent.valueDeclaration).locals; - if (currentFunctionLocalSymbolTable !== parentLocals && target.parent?.valueDeclaration?.kind !== SyntaxKind.ModuleDeclaration) return; - - target.exports ??= new Map(); - if (target.exportSymbol) { - target.exportSymbol.exports = target.exports; - } - withScope(fn, target.exports, () => { - const { includes, excludes } = syntaxKindToSymbolMap[SyntaxKind.PropertyDeclaration]; - addExportOnlyDeclaration(key, assignmentTarget, { - includes: includes | SymbolFlags.Assignment, - excludes: excludes & ~SymbolFlags.Assignment, - }); - }); - } - } - } - - function canHaveExpandoMembers(declaration: Node) { - if (isFunctionDeclaration(declaration)) { - return true; - } - else if (isVariableDeclaration(declaration)) { - if (declaration.type || !isVarConst(declaration)) { - return false; - } - if (!(declaration.initializer && isFunctionExpressionOrArrowFunction(declaration.initializer))) { - return false; - } - return true; - } - } - function bindObjectLiteral(object: ObjectLiteralExpression) { - const objectSymbol = createAnonymousEmitSymbol(object); - - withMembers(objectSymbol, /*addToExports*/ false, () => { - object.properties.forEach(m => { - bindNode(m); - }); - }); - } - function bindContainer(statements: NodeArray | Node[], filter: (node: Node) => boolean) { - statements.forEach(statement => { - if (!filter(statement)) return; - bindNode(statement); - }); - } - function bindChildren(node: Node) { - forEachChild(node, bindNode, arr => arr.forEach(bindNode)); - } - function bindNode(node: Node | undefined) { - if (!node) return; - - switch (node.kind) { - case SyntaxKind.ObjectLiteralExpression: - bindObjectLiteralExpression(node as ObjectLiteralExpression); - break; - case SyntaxKind.TypeLiteral: - bindTypeLiteralNode(node as TypeLiteralNode); - break; - case SyntaxKind.TypeAliasDeclaration: - bindTypeAliasDeclaration(node as TypeAliasDeclaration); - break; - case SyntaxKind.MappedType: - bindMappedTypeNode(node as MappedTypeNode); - break; - case SyntaxKind.ConditionalType: - bindConditionalTypeNode(node as ConditionalTypeNode); - break; - case SyntaxKind.InferType: - bindInferTypeNode(node as InferTypeNode); - break; - case SyntaxKind.ImportEqualsDeclaration: - bindImportEqualsDeclaration(node as ImportEqualsDeclaration); - break; - case SyntaxKind.ImportDeclaration: - bindImportDeclaration(node as ImportDeclaration); - break; - case SyntaxKind.ExportAssignment: - bindExportAssignment(node as ExportAssignment); - break; - case SyntaxKind.ExportDeclaration: - bindExportDeclaration(node as ExportDeclaration); - break; - case SyntaxKind.VariableDeclaration: - bindVariable(node as VariableDeclaration); - break; - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - bindFunctionExpressionOrArrowFunction(node as FunctionExpression | ArrowFunction); - break; - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.Constructor: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.MethodSignature: - case SyntaxKind.CallSignature: - case SyntaxKind.ConstructSignature: - case SyntaxKind.FunctionType: - case SyntaxKind.ConstructorType: - bindFunctionLikeContainer(node as FunctionLikeContainer); - break; - case SyntaxKind.ClassExpression: - // Class Expressions are not supported - break; - case SyntaxKind.EnumDeclaration: - bindEnumDeclaration(node as EnumDeclaration); - break; - case SyntaxKind.ModuleDeclaration: - bindModuleDeclaration(node as ModuleDeclaration); - break; - case SyntaxKind.InterfaceDeclaration: - bindInterfaceDeclaration(node as InterfaceDeclaration); - break; - case SyntaxKind.ClassDeclaration: - bindClassDeclaration(node as ClassDeclaration); - break; - case SyntaxKind.ForOfStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForStatement: - case SyntaxKind.Block: - withScope(node, /*exports*/ undefined, () => { - bindChildren(node); - }); - break; - default: - if (isDeclaration(node)) { - bindDeclaration(node); - } - else if (isExpression(node)) { - bindExpandoMembers(node); - bindChildren(node); - } - else { - bindChildren(node); - } - break; - } - } - function bindObjectLiteralExpression(node: ObjectLiteralExpression) { - bindObjectLiteral(node); - } - function bindMappedTypeNode(node: MappedTypeNode) { - const mappedType = node; - withScope(node, /*exports*/ undefined, () => { - bindTypeParameters([mappedType.typeParameter]); - }); - bindNode(mappedType.nameType); - bindNode(mappedType.type); - } - function bindConditionalTypeNode(node: ConditionalTypeNode) { - withScope(node.extendsType, /*exports*/ undefined, () => { - bindNode(node.extendsType); - }); - bindNode(node.checkType); - bindNode(node.falseType); - getNodeLinks(node.trueType).locals = getNodeLinks(node.extendsType).locals; - bindNode(node.trueType); - } - function bindInferTypeNode(node: InferTypeNode) { - const conditionalTypeOwner = findAncestor(node, isConditionalTypeNode); - // Probably an error, infer not in a conditional type context - // Try to bind the rest of it - if (conditionalTypeOwner) { - withScope(conditionalTypeOwner, /*exports*/ undefined, () => { - bindTypeParameters([node.typeParameter]); - }); - } - bindChildren(node); - } - function bindFunctionExpressionOrArrowFunction(node: FunctionExpression | ArrowFunction) { - createAnonymousEmitSymbol(node); - withScope(node, /*exports*/ undefined, () => { - bindTypeParameters(node.typeParameters); - bindNode(node.type); - node.parameters.forEach(bindVariable); - }); - } - function bindImportEqualsDeclaration(node: ImportEqualsDeclaration) { - addLocalOnlyDeclaration(getMemberKey(node.name), node, getSymbolFlagsForNode(node)); - } - function bindImportDeclaration(node: ImportDeclaration) { - if (!node.importClause) { - return; - } - if (node.importClause.name) { - addLocalOnlyDeclaration(getMemberKey(node.importClause.name), node.importClause, getSymbolFlagsForNode(node.importClause)); - } - if (node.importClause.namedBindings) { - const namedBindings = node.importClause.namedBindings; - if (namedBindings.kind === SyntaxKind.NamedImports) { - namedBindings.elements.forEach(v => { - addLocalOnlyDeclaration(getMemberKey(v.name), v, getSymbolFlagsForNode(v)); - }); - } - else if (namedBindings.kind === SyntaxKind.NamespaceImport) { - addLocalOnlyDeclaration(getMemberKey(namedBindings.name), namedBindings, getSymbolFlagsForNode(namedBindings)); - } - else { - throw new Error("Not supported"); - } - } - } - type FunctionLikeContainer = - | FunctionDeclaration - | MethodDeclaration - | ConstructorDeclaration - | GetAccessorDeclaration - | SetAccessorDeclaration - | MethodSignature - | FunctionDeclaration - | CallSignatureDeclaration - | ConstructSignatureDeclaration - | FunctionTypeNode - | ConstructorTypeNode; - function bindFunctionLikeContainer(node: FunctionLikeContainer) { - const isExported = hasSyntacticModifier(node, ModifierFlags.Export); - const declarationFlags = tryGetSymbolFlagsForNode(node); - if (declarationFlags) { - addLocalAndExportDeclaration(getStatementName(node), node, declarationFlags, isExported); - } - withScope(node, /*exports*/ undefined, () => { - bindTypeParameters(node.typeParameters); - bindNode(node.type); - node.parameters.forEach(bindVariable); - }); - } - function bindTypeLiteralNode(node: TypeLiteralNode) { - const objectSymbol = createAnonymousEmitSymbol(node); - withMembers(objectSymbol, /*addToExports*/ false, () => { - node.members.forEach(bindNode); - }); - } - function bindTypeAliasDeclaration(node: TypeAliasDeclaration) { - const isExported = hasSyntacticModifier(node, ModifierFlags.Export); - addLocalAndExportDeclaration(getStatementName(node), node, getSymbolFlagsForNode(node), isExported); - withScope(node, /*exports*/ undefined, () => { - bindTypeParameters(node.typeParameters); - bindNode(node.type); - }); - } - // Default export declarations set isVisible on true on associated symbols in the type checker. - function bindExportAssignment(node: ExportAssignment) { - bindNode(node.expression); - if (node.expression && isIdentifier(node.expression)) { - const name = node.expression.escapedText; - postBindingAction.push(() => { - const resolvedSymbol = resolveName(node.expression, name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); - if (resolvedSymbol) { - resolvedSymbol.declarations.forEach(d => getNodeLinks(d).isVisible = true); - } - }); - } - } - function bindExportDeclaration(node: ExportDeclaration) { - if (node.exportClause && isNamedExports(node.exportClause)) { - const elements = node.exportClause.elements; - if (node.moduleSpecifier) { - // TODO is currentExportsSymbolTable ok here? - withScope(node, /*exports*/ undefined, () => { - elements.forEach(e => { - const { includes, excludes } = getSymbolFlagsForNode(e); - addLocalOnlyDeclaration(getMemberKey(e.propertyName ?? e.name), e, { - includes: includes | SymbolFlags.ExportValue, - excludes, - }); - }); - }); - } - for (const e of elements) { - postBindingAction.push(() => { - const resolvedSymbol = resolveName(e, (e.propertyName ?? e.name).escapedText, ~0); - if (resolvedSymbol) { - resolvedSymbol.declarations.forEach(d => getNodeLinks(d).isVisible = true); - } - }); - } - } - } - function bindEnumDeclaration(node: EnumDeclaration) { - const isExported = hasSyntacticModifier(node, ModifierFlags.Export); - addLocalAndExportDeclaration(getStatementName(node), node, getSymbolFlagsForNode(node), isExported); - withScope(node, /*exports*/ undefined, () => { - node.members.forEach(m => { - addLocalOnlyDeclaration(getMemberKeyFromElement(m), m, getSymbolFlagsForNode(m)); - }); - }); - } - function bindModuleDeclaration(node: ModuleDeclaration) { - const isExported = hasSyntacticModifier(node, ModifierFlags.Export); - function bindModuleDeclaration(moduleDeclaration: ModuleDeclaration) { - const name = isIdentifier(moduleDeclaration.name) ? moduleDeclaration.name : undefined; - const moduleSymbol = addLocalAndExportDeclaration(getMemberKey(name), moduleDeclaration, getSymbolFlagsForNode(moduleDeclaration), isExported); - moduleSymbol.exports ??= new Map(); - withScope(moduleDeclaration, moduleSymbol.exports, () => { - if (moduleDeclaration.body) { - if (isModuleBlock(moduleDeclaration.body)) { - const moduleBlock = moduleDeclaration.body; - bindEachFunctionsFirst(moduleBlock.statements); - } - else if (isModuleDeclaration(moduleDeclaration.body)) { - const subModule = moduleDeclaration.body; - bindModuleDeclaration(subModule); - } - else { - throw new Error("Unsupported body type"); - } - } - }); - } - bindModuleDeclaration(node); - } - function bindInterfaceDeclaration(node: InterfaceDeclaration) { - const isExported = hasSyntacticModifier(node, ModifierFlags.Export); - const interfaceDeclaration = node; - const interfaceSymbol = addLocalAndExportDeclaration(getStatementName(interfaceDeclaration), interfaceDeclaration, getSymbolFlagsForNode(interfaceDeclaration), isExported); - withScope(interfaceDeclaration, /*exports*/ undefined, () => { - bindTypeParameters(interfaceDeclaration.typeParameters); - }); - withMembers(interfaceSymbol, /*addToExports*/ false, () => { - interfaceDeclaration.members.forEach(m => { - bindNode(m); - }); - }); - } - function bindClassDeclaration(node: ClassExpression | ClassDeclaration) { - const isExported = hasSyntacticModifier(node, ModifierFlags.Export); - const classDeclaration = node; - const classSymbol = addLocalAndExportDeclaration(getStatementName(classDeclaration), classDeclaration, getSymbolFlagsForNode(classDeclaration), isExported); - withScope(classDeclaration, /*exports*/ undefined, () => { - bindTypeParameters(classDeclaration.typeParameters); - }); - withMembers(classSymbol, /*addToExports*/ false, () => { - classDeclaration.members.forEach(m => { - if (hasSyntacticModifier(m, ModifierFlags.Static)) return; - if (m.kind === SyntaxKind.SemicolonClassElement || m.kind === SyntaxKind.ClassStaticBlockDeclaration) return; - - bindNode(m); - }); - }); - withMembers(classSymbol, /*addToExports*/ true, () => { - classDeclaration.members.forEach(m => { - if (!hasSyntacticModifier(m, ModifierFlags.Static)) return; - if ( - m.kind === SyntaxKind.SemicolonClassElement - || m.kind === SyntaxKind.ClassStaticBlockDeclaration - ) return; - - bindNode(m); - }); - }); - } - function bindDeclaration(node: Declaration) { - const flags = tryGetSymbolFlagsForNode(node); - // Unsupported declaration - if (!flags) { - return; - } - addLocalOnlyDeclaration(getMemberKeyFromElement(node), node, flags); - bindChildren(node); - } - } -} - -/** @internal */ -export type MemberKey = string & { - __memberKey: void; -}; - -/** - * Gets the symbolic name for a member from its type. - * @internal - */ -export function getMemberKey(name: string | Exclude | NoSubstitutionTemplateLiteral): MemberKey; -/** - * Gets the symbolic name for a member from its type. - * @internal - */ -export function getMemberKey(name: string | PropertyName | NoSubstitutionTemplateLiteral | undefined): MemberKey | undefined; -export function getMemberKey(name: string | PropertyName | NoSubstitutionTemplateLiteral | undefined): string | undefined { - if (name === undefined) { - return undefined; - } - if (typeof name === "string") { - return ("I:" + name); - } - if (isPrivateIdentifier(name)) { - return ("P:" + name.escapedText); - } - if (isIdentifier(name)) { - return ("I:" + name.escapedText); - } - if (isStringLiteralLike(name)) { - return ("I:" + name.text); - } - if (isNumericLiteral(name)) { - return ("I:" + (+name.text)); - } - if (isComputedPropertyName(name)) { - let computedName = name.expression; - - if (isStringLiteralLike(computedName)) { - return ("I:" + computedName.text); - } - if (isNumericLiteral(computedName)) { - return ("I:" + (+computedName.text)); - } - if ( - isPrefixUnaryExpression(computedName) - && isNumericLiteral(computedName.operand) - ) { - if (computedName.operator === SyntaxKind.MinusToken) { - return ("I:" + (-computedName.operand.text)); - } - else if (computedName.operator === SyntaxKind.PlusToken) { - return ("I:" + (+computedName.operand.text)); - } - else { - return undefined; - } - } - let fullId = "C:"; - // We only support dotted identifiers as property keys - while (true) { - if (isIdentifier(computedName)) { - fullId += computedName.escapedText; - break; - } - else if (isPropertyAccessExpression(computedName)) { - fullId += computedName.name.escapedText; - computedName = computedName.expression; - } - else { - // Can't compute a property key, bail - return undefined; - } - } - return fullId; - } - return undefined; -} - -/** - * Gets the symbolic name for a member from its type. - * @internal - */ -export function getMemberKeyFromElement(element: NamedDeclaration): MemberKey | undefined { - if (isConstructorDeclaration(element) || isConstructSignatureDeclaration(element)) { - return "@constructor" as MemberKey; - } - const name = element.name; - if (!name || isElementAccessExpression(name) || isObjectBindingPattern(name) || isArrayBindingPattern(name) || isJsxNamespacedName(name) || isPropertyAccessExpression(name)) return undefined; - return getMemberKey(name); -} diff --git a/src/compiler/transformers/declarations/emitResolver.ts b/src/compiler/transformers/declarations/emitResolver.ts index 29bc1430827d3..ccef24871a1f3 100644 --- a/src/compiler/transformers/declarations/emitResolver.ts +++ b/src/compiler/transformers/declarations/emitResolver.ts @@ -1,37 +1,52 @@ import { - bindSourceFileForDeclarationEmit, + __String, + BigIntLiteral, + bindSourceFile, + CompilerOptions, ComputedPropertyName, CoreEmitResolver, createEntityVisibilityChecker, createEvaluator, + createNameResolver, + createSymbolTable, Debug, + Declaration, DeclarationName, determineIfDeclarationIsVisible, ElementAccessExpression, - EmitDeclarationNodeLinks, - EmitDeclarationSymbol, emptyArray, + entityNameToString, EnumDeclaration, EnumMember, + ExportSpecifier, Expression, factory, + forEachChild, forEachEntry, FunctionDeclaration, FunctionLikeDeclaration, - getMemberKey, + getMembersOfDeclaration, getNameOfDeclaration, + getNodeId, getParseTreeNode, + getPropertyNameForPropertyNameNode, hasDynamicName, hasProperty, + hasStaticModifier, hasSyntacticModifier, + Identifier, + InternalSymbolName, isAccessor, - isBigIntLiteral, + isBinaryExpression, + isComputedPropertyName, isDeclarationReadonly, isElementAccessExpression, isEntityNameExpression, isEnumDeclaration, isEnumMember, isExpandoPropertyDeclaration, + isExportAssignment, + isExportSpecifier, isFunctionDeclaration, isFunctionExpressionOrArrowFunction, isFunctionLike, @@ -39,14 +54,13 @@ import { isGetAccessorDeclaration, isIdentifier, isInfinityOrNaNString, - isNumericLiteral, - isPrefixUnaryExpression, + isModuleDeclaration, isPrimitiveLiteralValue, isPropertyAccessExpression, + isPropertyName, isSetAccessor, isSetAccessorDeclaration, isStringLiteralLike, - isTemplateExpression, isVarConst, isVariableDeclaration, LateBoundDeclaration, @@ -55,25 +69,48 @@ import { NodeFlags, nodeIsPresent, NoSubstitutionTemplateLiteral, + NumericLiteral, + objectAllocator, ParameterDeclaration, parsePseudoBigInt, + PrefixUnaryExpression, PropertyAccessExpression, PropertyDeclaration, PropertyName, PropertySignature, skipParentheses, + some, SourceFile, + StringLiteralLike, + Symbol, SymbolAccessibility, SymbolFlags, + SymbolTable, SyntaxKind, + TemplateExpression, VariableDeclaration, } from "../../_namespaces/ts"; +interface EmitSymbolLinks { + lateBoundSymbol?: Symbol; + signatureDeclarations?: Node[]; + lateBoundMembers?: SymbolTable; + lateBoundExports?: SymbolTable; +} +interface EmitDeclarationNodeLinks { + signatureDeclarations?: Node[]; + isVisible?: boolean; + enumValue?: string | number | undefined; + isVisibilityComputed?: boolean; + declarationRequiresScopeChange?: boolean; + resolvedSymbol?: Symbol; +} + /** @internal */ -export function createEmitDeclarationResolver(file: SourceFile): CoreEmitResolver { - const { getNodeLinks, resolveMemberKey, resolveName, resolveEntityName } = bindSourceFileForDeclarationEmit(file); +export function createEmitDeclarationResolver(file: SourceFile, options: CompilerOptions): CoreEmitResolver { + const nodeLinks: EmitDeclarationNodeLinks[] = []; - const { isEntityNameVisible } = createEntityVisibilityChecker({ + const { isEntityNameVisible, collectLinkedAliases } = createEntityVisibilityChecker({ defaultSymbolAccessibility: SymbolAccessibility.Accessible, isDeclarationVisible, markDeclarationAsVisible(declaration) { @@ -83,13 +120,198 @@ export function createEmitDeclarationResolver(file: SourceFile): CoreEmitResolve return { accessibility: SymbolAccessibility.Accessible }; }, resolveName, + getTargetOfExportSpecifier, }); + /* eslint-disable-next-line no-var */ + var Symbol = objectAllocator.getSymbolConstructor(); + const resolverWorker = createNameResolver( + options, + getSymbolOfDeclaration, + () => {}, + createSymbolTable(), + new Symbol(SymbolFlags.Property, "arguments" as __String), + new Symbol(SymbolFlags.Property, "require" as __String), + createSymbolTable(), + r => r, + lookupSymbolName, + getNodeLinks, + ); + + bindSourceFile(file, options); + collectAllLinkedAliases(file); + + function getTargetOfExportSpecifier(node: ExportSpecifier, meaning: SymbolFlags): Symbol | undefined { + const resolved = resolveEntityName(node, node.propertyName || node.name, meaning); + return resolved; + } + + function collectAllLinkedAliases(node: Node) { + if (isExportAssignment(node)) { + if (node.expression.kind === SyntaxKind.Identifier) { + collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true); + } + return; + } + else if (isExportSpecifier(node)) { + collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true); + return; + } + forEachChild(node, collectAllLinkedAliases); + } + + function getNodeLinks(node: Node): EmitDeclarationNodeLinks { + const nodeId = getNodeId(node); + return nodeLinks[nodeId] || (nodeLinks[nodeId] = {}); + } + + function resolveEntityName(location: Node, node: Expression, meaning: SymbolFlags): Symbol | undefined { + if (isIdentifier(node)) { + return resolveName(location, node.escapedText, meaning); + } + else if (isPropertyAccessExpression(node) || isElementAccessExpression(node)) { + const symbol = resolveEntityName(location, node.expression, meaning); + if (symbol === undefined) return undefined; + + const name = isElementAccessExpression(node) ? node.argumentExpression : node.name; + if (!isPropertyName(name)) return; + + const memberSymbol = symbol.exports?.get(getSymbolName(name)); + if (!memberSymbol || !(memberSymbol.flags & meaning)) { + if (symbol.valueDeclaration && isModuleDeclaration(symbol.valueDeclaration)) { + return symbol.valueDeclaration.locals?.get(getSymbolName(name)); + } + return undefined; + } + return memberSymbol; + } + else { + return undefined; + } + } + + function resolveName(enclosingDeclaration: Node, name: __String, meaning: SymbolFlags) { + return resolverWorker(enclosingDeclaration, name, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false, /*excludeGlobals*/ true, /*getSpellingSuggestions*/ false); + } + + const symbolLinks = new Map(); + function getSymbolLinks(symbol: Symbol) { + let links = symbolLinks.get(symbol); + if (!links) symbolLinks.set(symbol, links = {}); + return links; + } + function getSymbolOfDeclaration(node: Declaration): Symbol { + const symbol = node.symbol; + if (symbol.escapedName !== InternalSymbolName.Computed) { + return symbol; + } + + const links = getSymbolLinks(symbol); + if (!links.lateBoundSymbol) { + const parentSymbol = symbol.parent; + if (parentSymbol) { + const isStatic = some(symbol.declarations, hasStaticModifier); + resolveAllLateBoundSymbols(parentSymbol, isStatic); + } + } + return links.lateBoundSymbol ?? symbol; + } + + function resolveAllLateBoundSymbols(symbol: Symbol, isStatic: boolean) { + const links = getSymbolLinks(symbol); + let lateSymbols: SymbolTable; + if (isStatic) { + if (links.lateBoundExports) { + return links.lateBoundExports; + } + lateSymbols = links.lateBoundExports = createSymbolTable(); + } + else { + if (links.lateBoundMembers) { + return links.lateBoundMembers; + } + lateSymbols = links.lateBoundMembers = createSymbolTable(); + } + if (symbol.declarations) { + for (const decl of symbol.declarations) { + const members = getMembersOfDeclaration(decl); + if (members) { + for (const member of members) { + if (isStatic === hasStaticModifier(member)) { + const memberName = member.name && getDynamicSymbolName(member.name); + if (memberName) { + lateBindMember(symbol, lateSymbols, memberName, member); + } + } + } + } + } + const expandoFunction = symbol.valueDeclaration?.kind === SyntaxKind.ArrowFunction || symbol.valueDeclaration?.kind === SyntaxKind.FunctionExpression + ? getSymbolOfDeclaration(symbol.valueDeclaration.parent as VariableDeclaration) || symbol + : symbol; + const assignments = expandoFunction.assignmentDeclarationMembers; + if (assignments) { + for (const member of assignments.values()) { + if (!isBinaryExpression(member)) continue; + const memberNameNode = isPropertyAccessExpression(member.left) ? member.left.name : + isElementAccessExpression(member.left) ? member.left : + undefined; + + const memberName = memberNameNode && getDynamicSymbolName(memberNameNode); + if (memberName) { + lateBindMember(symbol, lateSymbols, memberName, member); + } + } + } + } + return lateSymbols; + } + + function lateBindMember(parent: Symbol, lateSymbols: SymbolTable, memberName: __String, member: Declaration) { + const links = getNodeLinks(member); + if (links.resolvedSymbol) return links.resolvedSymbol; + let lateSymbol = lateSymbols.get(memberName); + if (!lateSymbol) { + lateSymbols.set(memberName, lateSymbol = new Symbol(SymbolFlags.None, memberName)); + lateSymbol.parent = parent; + } + Debug.assert(lateSymbol.parent === parent, "Existing symbol parent should match new one"); + const symbolFlags = member.symbol.flags; + + lateSymbol.flags |= symbolFlags; + if (!lateSymbol.declarations) { + lateSymbol.declarations = [member]; + } + else if (!member.symbol.isReplaceableByMethod) { + lateSymbol.declarations.push(member); + } + if (symbolFlags & SymbolFlags.Value) { + if (!lateSymbol.valueDeclaration || lateSymbol.valueDeclaration.kind !== member.kind) { + lateSymbol.valueDeclaration = member; + } + } + getSymbolLinks(member.symbol).lateBoundSymbol = links.resolvedSymbol = lateSymbol; + } + + function lookupSymbolName(symbols: SymbolTable, name: __String, meaning: SymbolFlags): Symbol | undefined { + if (meaning) { + const symbol = symbols.get(name); + if (symbol) { + if (symbol.flags & meaning) { + return symbol; + } + if (symbol.flags & SymbolFlags.Alias) { + return symbol; + } + } + } + // return undefined if we can't find a symbol. + } function getEnumValueFromName(name: PropertyName | NoSubstitutionTemplateLiteral, location: EnumDeclaration) { - const enumKey = getMemberKey(name); + const enumKey = getSymbolName(name); if (!enumKey) return undefined; - const enumMemberSymbol = resolveMemberKey(location, enumKey, SymbolFlags.Value); - const enumMemberDeclaration = enumMemberSymbol?.declarations[0]; + const enumMemberSymbol = resolveName(location, enumKey, SymbolFlags.Value); + const enumMemberDeclaration = enumMemberSymbol?.declarations?.[0]; if (enumMemberDeclaration && isEnumMember(enumMemberDeclaration)) { return getNodeLinks(enumMemberDeclaration).enumValue; } @@ -99,7 +321,7 @@ export function createEmitDeclarationResolver(file: SourceFile): CoreEmitResolve function isExpressionMemberOfEnum(target: Expression, location: EnumDeclaration) { const symbol = resolveEntityName(location, target, SymbolFlags.Namespace); - return !!symbol?.declarations.some(d => d === location); + return !!symbol?.declarations?.some(d => d === location); } const evaluate = createEvaluator({ evaluateElementAccessExpression(expr, location) { @@ -136,48 +358,44 @@ export function createEmitDeclarationResolver(file: SourceFile): CoreEmitResolve onNumericLiteral() {}, }); function clonePrimitiveLiteralValue(node: Expression): Expression { - if (isNumericLiteral(node)) { - return factory.createNumericLiteral(node.text); - } - if (isBigIntLiteral(node)) { - return factory.createBigIntLiteral({ negative: false, base10Value: parsePseudoBigInt(node.text) }); - } - if (isStringLiteralLike(node)) { - return factory.createStringLiteral(node.text); - } - - if (node.kind === SyntaxKind.FalseKeyword) { - return factory.createFalse(); - } - - if (node.kind === SyntaxKind.TrueKeyword) { - return factory.createTrue(); - } - - if (isPrefixUnaryExpression(node)) { - return factory.createPrefixUnaryExpression( - node.operator, - clonePrimitiveLiteralValue(node.operand), - ); - } - if (isTemplateExpression(node)) { - const evaluatedValue = evaluate(node); - if (evaluatedValue !== undefined) { - return factory.createStringLiteral(evaluatedValue); - } - return factory.createTemplateExpression( - factory.createTemplateHead(node.head.text, node.head.rawText, node.head.templateFlags), - node.templateSpans.map(t => - factory.createTemplateSpan( - clonePrimitiveLiteralValue(t.expression), - t.literal.kind === SyntaxKind.TemplateMiddle ? - factory.createTemplateMiddle(t.literal.text, t.literal.rawText, t.literal.templateFlags) : - factory.createTemplateTail(t.literal.text, t.literal.rawText, t.literal.templateFlags), - ) - ), - ); + switch(node.kind) { + case SyntaxKind.NumericLiteral: + return factory.createNumericLiteral((node as NumericLiteral).text); + case SyntaxKind.BigIntLiteral: + return factory.createBigIntLiteral({ negative: false, base10Value: parsePseudoBigInt((node as BigIntLiteral).text) }); + case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + return factory.createStringLiteral((node as StringLiteralLike).text); + case SyntaxKind.FalseKeyword: + return factory.createFalse(); + case SyntaxKind.TrueKeyword: + return factory.createTrue(); + case SyntaxKind.PrefixUnaryExpression: + return factory.createPrefixUnaryExpression( + (node as PrefixUnaryExpression).operator, + clonePrimitiveLiteralValue((node as PrefixUnaryExpression).operand), + ); + case SyntaxKind.TemplateExpression: + const templateExpression = node as TemplateExpression + const evaluatedValue = evaluate(templateExpression); + if (evaluatedValue !== undefined) { + return factory.createStringLiteral(evaluatedValue); + } + const templateHead = templateExpression.head + return factory.createTemplateExpression( + factory.createTemplateHead(templateHead.text, templateHead.rawText, templateHead.templateFlags), + templateExpression.templateSpans.map(t => + factory.createTemplateSpan( + clonePrimitiveLiteralValue(t.expression), + t.literal.kind === SyntaxKind.TemplateMiddle ? + factory.createTemplateMiddle(t.literal.text, t.literal.rawText, t.literal.templateFlags) : + factory.createTemplateTail(t.literal.text, t.literal.rawText, t.literal.templateFlags), + ) + ), + ); + default: + Debug.assert(false, `Unable to clone unknown literal type. Kind: ${node.kind}`); } - Debug.assert(false, `Unable to clone unknown literal type. Kind: ${node.kind}`); } function isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean { @@ -223,7 +441,6 @@ export function createEmitDeclarationResolver(file: SourceFile): CoreEmitResolve if (!declaration) { return false; } - const symbol = declaration.symbol; if (isVariableDeclaration(declaration)) { if (declaration.type || !isVarConst(declaration)) { return false; @@ -232,7 +449,13 @@ export function createEmitDeclarationResolver(file: SourceFile): CoreEmitResolve return false; } } - return !!symbol.exports && !!forEachEntry(symbol.exports, p => p.flags & SymbolFlags.Value && isExpandoPropertyDeclaration(p.valueDeclaration)); + + const symbol = getSymbolOfDeclaration(declaration); + if (!!symbol.exports && !!forEachEntry(symbol.exports, p => p.flags & SymbolFlags.Value && isExpandoPropertyDeclaration(p.valueDeclaration))) { + return true; + } + const lateBoundSymbols = resolveAllLateBoundSymbols(symbol, /*isStatic*/ true); + return !!forEachEntry(lateBoundSymbols, p => p.flags & SymbolFlags.Value && isExpandoPropertyDeclaration(p.valueDeclaration)); } return { @@ -243,10 +466,11 @@ export function createEmitDeclarationResolver(file: SourceFile): CoreEmitResolve return undefined; }, getPropertiesOfContainerFunction(node: FunctionDeclaration | VariableDeclaration) { - return [...node.symbol.exports?.values() ?? []]; + const symbol = getSymbolOfDeclaration(node); + return [...symbol.exports?.values() ?? [], ...resolveAllLateBoundSymbols(symbol, /*isStatic*/ true).values()]; }, getAllAccessorDeclarations(declaration) { - const symbol = declaration.symbol; + const symbol = getSymbolOfDeclaration(declaration); const declaredAccessors = symbol?.declarations?.filter(isAccessor); const declarations = declaredAccessors?.length ? declaredAccessors : [declaration]; return { @@ -303,22 +527,16 @@ export function createEmitDeclarationResolver(file: SourceFile): CoreEmitResolve return !hasDynamicName(node) || isIdentifierComputedName(name); }, isImplementationOfOverload(node) { - function getSignaturesOfSymbol(symbol: EmitDeclarationSymbol | undefined): Node[] { - if (!symbol) return emptyArray; - if (symbol.signatureDeclarations) return symbol.signatureDeclarations; + function getSignaturesOfSymbol(symbol: Symbol): Node[] { + const links = getSymbolLinks(symbol); + if (links.signatureDeclarations) return links.signatureDeclarations; + + if (!symbol || !symbol.declarations) return (links.signatureDeclarations = emptyArray); - if (!symbol || !symbol.declarations) return (symbol.signatureDeclarations = emptyArray); - const result: Node[] = symbol.signatureDeclarations = []; + const result: Node[] = links.signatureDeclarations = []; for (let i = 0; i < symbol.declarations.length; i++) { const decl = symbol.declarations[i]; - if (!isFunctionLike(decl) || isGetAccessor(decl) || isSetAccessor(decl)) { - // If non methods got merged in a class member bail with an empty array - // This is TS error behavior and we want to preserve iot as much as possible - // if(isClassElement(decl)) { - // return emptyArray; - // } - continue; - } + if (!isFunctionLike(decl)) continue; // Don't include signature if node is the implementation of an overloaded function. A node is considered // an implementation node if it has a body and the previous node is of the same kind and immediately // precedes the implementation node (i.e. has the same parent and ends where the implementation starts). @@ -337,7 +555,7 @@ export function createEmitDeclarationResolver(file: SourceFile): CoreEmitResolve if (nodeIsPresent((node as FunctionLikeDeclaration).body)) { if (isGetAccessor(node) || isSetAccessor(node)) return false; // Get or set accessors can never be overload implementations, but can have up to 2 signatures - const symbol = getNodeLinks(node).symbol; + const symbol = getSymbolOfDeclaration(node); const signaturesOfSymbol = getSignaturesOfSymbol(symbol); // If this function body corresponds to function with multiple signature, it is implementation of overload // e.g.: function foo(a: string): string; @@ -393,3 +611,25 @@ export function createEmitDeclarationResolver(file: SourceFile): CoreEmitResolve return false; } } + +function getSymbolName(name: Exclude): __String; +function getSymbolName(name: ElementAccessExpression | PropertyName): __String | undefined; +function getSymbolName(name: ElementAccessExpression | PropertyName): __String | undefined { + const staticName = isPropertyName(name) ? getPropertyNameForPropertyNameNode(name) : + isElementAccessExpression(name) && isPropertyName(name.argumentExpression) ? getPropertyNameForPropertyNameNode(name.argumentExpression) : + undefined; + + if (staticName) return staticName; + + return getDynamicSymbolName(name); +} + +function getDynamicSymbolName(name: ElementAccessExpression | PropertyName) { + const computedName = isComputedPropertyName(name) ? name.expression : + isElementAccessExpression(name) ? name.argumentExpression : + undefined; + if (computedName && isEntityNameExpression(computedName)) { + return ("__!" + entityNameToString(computedName)) as __String; + } + return undefined; +} diff --git a/src/compiler/transformers/declarations/localInferenceResolver.ts b/src/compiler/transformers/declarations/localInferenceResolver.ts index 48597a2bf78e7..ec3851a3c7c0e 100644 --- a/src/compiler/transformers/declarations/localInferenceResolver.ts +++ b/src/compiler/transformers/declarations/localInferenceResolver.ts @@ -19,7 +19,6 @@ import { GetAccessorDeclaration, getCommentRange, getEmitScriptTarget, - getMemberKeyFromElement, getNameOfDeclaration, getTextOfNode, HasInferredType, @@ -498,7 +497,7 @@ export function createLocalInferenceResolver({ } } - const nameKey = getMemberKeyFromElement(prop); + const nameKey = prop.symbol.escapedName; const name = normalizePropertyName(prop.symbol, isMethodDeclaration(prop)) ?? deepClone(visitNode(prop.name, visitDeclarationSubtree, isPropertyName)!); @@ -530,7 +529,6 @@ export function createLocalInferenceResolver({ }); if (nameKey) { - Debug.assertSymbolValid(prop.symbol); const exitingIndex = members.get(prop.symbol); if (exitingIndex !== undefined && !isMethodOrAccessor(prop)) { properties[exitingIndex] = newProp; @@ -664,7 +662,6 @@ export function createLocalInferenceResolver({ function normalizePropertyName(symbol: Symbol, isMethod: boolean) { let nameText; - Debug.assertSymbolValid(symbol); Debug.assert(symbol.declarations !== undefined, "Symbol has no declarations"); let stringNamed = !!length(symbol.declarations); let singleQuote = stringNamed; @@ -790,7 +787,6 @@ export function createLocalInferenceResolver({ return localInference(node.expression, NarrowBehavior.KeepLiterals); } else if (isVariableDeclaration(node)) { - Debug.assertSymbolValid(node.symbol); const firstDeclaration = node.symbol.valueDeclaration; // Use first declaration of variable for the type if (node !== firstDeclaration && firstDeclaration && isVariableDeclaration(firstDeclaration)) { diff --git a/src/compiler/transformers/declarations/transpileDeclaration.ts b/src/compiler/transformers/declarations/transpileDeclaration.ts index ad839eb0a34a1..ff457c261ccab 100644 --- a/src/compiler/transformers/declarations/transpileDeclaration.ts +++ b/src/compiler/transformers/declarations/transpileDeclaration.ts @@ -38,7 +38,7 @@ export function transpileDeclaration(sourceFile: SourceFile, transpileOptions: T getCompilerOptions: () => compilerOptions.compilerOptions, getCommonSourceDirectory: () => commonSourceDirectory, }; - const emitResolver = createEmitDeclarationResolver(sourceFile); + const emitResolver = createEmitDeclarationResolver(sourceFile, compilerOptions); const diagnostics: Diagnostic[] = []; const transformationContext: IsolatedTransformationContext = { ...nullTransformationContext, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 93b6cd696abe7..289977b77acce 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -43,6 +43,7 @@ import { CallLikeExpression, CallSignatureDeclaration, canHaveDecorators, + canHaveLocals, canHaveModifiers, CaseBlock, CaseClause, @@ -229,21 +230,25 @@ import { ImportDeclaration, ImportEqualsDeclaration, ImportMetaProperty, + ImportOrExportSpecifier, ImportSpecifier, ImportTypeNode, IndexInfo, indexOfAnyCharCode, IndexSignatureDeclaration, + InferTypeNode, InitializedVariableDeclaration, insertSorted, InstanceofExpression, InterfaceDeclaration, InternalEmitFlags, + InternalSymbolName, isAccessor, isAnyDirectorySeparator, isArray, isArrayLiteralExpression, isArrowFunction, + isAssertionExpression, isAutoAccessorPropertyDeclaration, isBigIntLiteral, isBinaryExpression, @@ -258,6 +263,7 @@ import { isCommaListExpression, isComputedPropertyName, isConstructorDeclaration, + isConstTypeReference, isDeclaration, isDecorator, isElementAccessExpression, @@ -294,6 +300,7 @@ import { isJSDocOverloadTag, isJSDocParameterTag, isJSDocPropertyLikeTag, + isJSDocReturnTag, isJSDocSatisfiesTag, isJSDocSignature, isJSDocTag, @@ -315,15 +322,19 @@ import { isMethodOrAccessor, isModifierLike, isModuleDeclaration, + isModuleOrEnumDeclaration, isNamedDeclaration, isNamespaceExport, isNamespaceExportDeclaration, isNamespaceImport, isNonNullExpression, isNoSubstitutionTemplateLiteral, + isNullishCoalesce, isNumericLiteral, + isObjectBindingPattern, isObjectLiteralExpression, isOmittedExpression, + isOptionalChain, isParameter, isParameterPropertyDeclaration, isParenthesizedExpression, @@ -350,6 +361,7 @@ import { isTypeLiteralNode, isTypeNode, isTypeParameterDeclaration, + isTypeQueryNode, isTypeReferenceNode, isVariableDeclaration, isVariableStatement, @@ -465,6 +477,7 @@ import { PseudoBigInt, PunctuationOrKeywordSyntaxKind, PunctuationSyntaxKind, + pushIfUnique, QualifiedName, QuestionQuestionEqualsToken, ReadonlyCollection, @@ -537,6 +550,7 @@ import { TransformFlags, TransientSymbol, TriviaSyntaxKind, + tryAddToSet, tryCast, tryRemovePrefix, TryStatement, @@ -5104,6 +5118,9 @@ export function isIdentifierComputedName(name: DeclarationName): boolean { } /** @internal */ +export function getPropertyNameForPropertyNameNode(name: Exclude | JsxAttributeName): __String; +/** @internal */ +export function getPropertyNameForPropertyNameNode(name: PropertyName | JsxAttributeName): __String | undefined; export function getPropertyNameForPropertyNameNode(name: PropertyName | JsxAttributeName): __String | undefined { switch (name.kind) { case SyntaxKind.Identifier: @@ -10925,11 +10942,30 @@ export function createEvaluator({ evaluateElementAccessExpression, evaluateEntit } /** @internal */ -export function createEntityVisibilityChecker({ isDeclarationVisible, isThisAccessible, markDeclarationAsVisible: markNodeAsVisible, resolveName, defaultSymbolAccessibility }: { +export function getModuleSpecifierForImportOrExport(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportOrExportSpecifier): Expression | undefined { + switch (node.kind) { + case SyntaxKind.ImportClause: + return node.parent.moduleSpecifier; + case SyntaxKind.ImportEqualsDeclaration: + return isExternalModuleReference(node.moduleReference) ? node.moduleReference.expression : undefined; + case SyntaxKind.NamespaceImport: + return node.parent.parent.moduleSpecifier; + case SyntaxKind.ImportSpecifier: + return node.parent.parent.parent.moduleSpecifier; + case SyntaxKind.ExportSpecifier: + return node.parent.parent.moduleSpecifier; + default: + return Debug.assertNever(node); + } +} + +/** @internal */ +export function createEntityVisibilityChecker({ isDeclarationVisible, isThisAccessible, markDeclarationAsVisible, resolveName, defaultSymbolAccessibility, getTargetOfExportSpecifier }: { defaultSymbolAccessibility: SymbolAccessibility; isDeclarationVisible(node: Node): boolean; isThisAccessible(identifier: Identifier, meaning: SymbolFlags): SymbolVisibilityResult; markDeclarationAsVisible(node: Node): void; + getTargetOfExportSpecifier(exportSpecifier: ExportSpecifier, flags: SymbolFlags): Symbol | undefined; resolveName( location: Node | undefined, name: __String, @@ -10939,9 +10975,52 @@ export function createEntityVisibilityChecker | undefined; + if (exportSymbol) { + visited = new Set(); + visited.add(getSymbolId(exportSymbol)); + buildVisibleNodeList(exportSymbol.declarations); + } + return result; + + function buildVisibleNodeList(declarations: Declaration[] | undefined) { + forEach(declarations, declaration => { + const resultNode = getAnyImportSyntax(declaration) || declaration; + if (setVisibility) { + markDeclarationAsVisible(declaration); + } + else { + result = result || []; + pushIfUnique(result, resultNode); + } + + if (isInternalModuleImportEqualsDeclaration(declaration)) { + // Add the referenced top container visible + const internalModuleReference = declaration.moduleReference as Identifier | QualifiedName; + const firstIdentifier = getFirstIdentifier(internalModuleReference); + const importSymbol = resolveName(declaration, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); + if (importSymbol && visited) { + if (tryAddToSet(visited, getSymbolId(importSymbol))) { + buildVisibleNodeList(importSymbol.declarations); + } + } + } + }); + } + } + + function hasVisibleDeclarations(symbol: Symbol, shouldComputeAliasToMakeVisible: boolean): SymbolVisibilityResult | undefined { let aliasesToMakeVisible: LateVisibilityPaintedStatement[] | undefined; if (!every(filter(symbol.declarations, d => d.kind !== SyntaxKind.Identifier), getIsDeclarationVisible)) { return undefined; @@ -11010,7 +11089,7 @@ export function createEntityVisibilityChecker Symbol, + error: (location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments) => void, + globals: SymbolTable, + argumentsSymbol: Symbol, + requireSymbol: Symbol, + emptySymbols: SymbolTable, + extendedResolveErrorReporting: ( + result: Symbol | undefined, + originalLocation: Node | undefined, + name: __String, + meaning: SymbolFlags, + nameNotFoundMessage: DiagnosticMessage | undefined, + nameArg: __String | Identifier | undefined, + getSpellingSuggestions: boolean, + lookup: (symbols: SymbolTable, name: __String, meaning: SymbolFlags) => Symbol | undefined, + lastLocation: Node | undefined, + errorLocation: Node | undefined, + propertyWithInvalidInitializer: PropertyDeclaration | undefined, + associatedDeclarationForContainingInitializerOrBindingName: ParameterDeclaration | BindingElement | undefined, + withinDeferredContext: boolean, + isInExternalModule: boolean, + ) => Symbol | undefined, + lookup: (symbols: SymbolTable, name: __String, meaning: SymbolFlags) => Symbol | undefined, + getNodeLinks: (node: Node) => { declarationRequiresScopeChange?: boolean; }, +) { + /* eslint-disable no-var */ + var isolatedModulesLikeFlagName = compilerOptions.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules"; + /* eslint-disable no-var */ + var emitStandardClassFields = getEmitStandardClassFields(compilerOptions); + + return resolveNameHelper; + + function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) { + if (symbol.declarations) { + for (const decl of symbol.declarations) { + if (decl.kind === SyntaxKind.TypeParameter) { + const parent = isJSDocTemplateTag(decl.parent) ? getJSDocHost(decl.parent) : decl.parent; + if (parent === container) { + return !(isJSDocTemplateTag(decl.parent) && find((decl.parent.parent as JSDoc).tags, isJSDocTypeAlias)); + } + } + } + } + + return false; + } + + type SelfReferenceLocation = + | FunctionDeclaration + | ClassDeclaration + | InterfaceDeclaration + | EnumDeclaration + | TypeAliasDeclaration + | ModuleDeclaration; + + function isSelfReferenceLocation(node: Node): node is SelfReferenceLocation { + switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.ModuleDeclaration: // For `namespace N { N; }` + return true; + default: + return false; + } + } + + function getIsDeferredContext(location: Node, lastLocation: Node | undefined): boolean { + if (location.kind !== SyntaxKind.ArrowFunction && location.kind !== SyntaxKind.FunctionExpression) { + // initializers in instance property declaration of class like entities are executed in constructor and thus deferred + return isTypeQueryNode(location) || (( + isFunctionLikeDeclaration(location) || + (location.kind === SyntaxKind.PropertyDeclaration && !isStatic(location)) + ) && (!lastLocation || lastLocation !== (location as SignatureDeclaration | PropertyDeclaration).name)); // A name is evaluated within the enclosing scope - so it shouldn't count as deferred + } + if (lastLocation && lastLocation === (location as FunctionExpression | ArrowFunction).name) { + return false; + } + // generator functions and async functions are not inlined in control flow when immediately invoked + if ((location as FunctionExpression | ArrowFunction).asteriskToken || hasSyntacticModifier(location, ModifierFlags.Async)) { + return true; + } + return !getImmediatelyInvokedFunctionExpression(location); + } + + function useOuterVariableScopeInParameter(result: Symbol, location: Node, lastLocation: Node) { + const target = getEmitScriptTarget(compilerOptions); + const functionLocation = location as FunctionLikeDeclaration; + if ( + isParameter(lastLocation) + && functionLocation.body + && result.valueDeclaration + && result.valueDeclaration.pos >= functionLocation.body.pos + && result.valueDeclaration.end <= functionLocation.body.end + ) { + // check for several cases where we introduce temporaries that require moving the name/initializer of the parameter to the body + // - static field in a class expression + // - optional chaining pre-es2020 + // - nullish coalesce pre-es2020 + // - spread assignment in binding pattern pre-es2017 + if (target >= ScriptTarget.ES2015) { + const links = getNodeLinks(functionLocation); + if (links.declarationRequiresScopeChange === undefined) { + links.declarationRequiresScopeChange = forEach(functionLocation.parameters, requiresScopeChange) || false; + } + return !links.declarationRequiresScopeChange; + } + } + return false; + + function requiresScopeChange(node: ParameterDeclaration): boolean { + return requiresScopeChangeWorker(node.name) + || !!node.initializer && requiresScopeChangeWorker(node.initializer); + } + + function requiresScopeChangeWorker(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.Constructor: + // do not descend into these + return false; + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.PropertyAssignment: + return requiresScopeChangeWorker((node as MethodDeclaration | AccessorDeclaration | PropertyAssignment).name); + case SyntaxKind.PropertyDeclaration: + // static properties in classes introduce temporary variables + if (hasStaticModifier(node)) { + return !emitStandardClassFields; + } + return requiresScopeChangeWorker((node as PropertyDeclaration).name); + default: + // null coalesce and optional chain pre-es2020 produce temporary variables + if (isNullishCoalesce(node) || isOptionalChain(node)) { + return target < ScriptTarget.ES2020; + } + if (isBindingElement(node) && node.dotDotDotToken && isObjectBindingPattern(node.parent)) { + return target < ScriptTarget.ES2017; + } + if (isTypeNode(node)) return false; + return forEachChild(node, requiresScopeChangeWorker) || false; + } + } + } + + function resolveNameHelper( + location: Node | undefined, + name: __String, + meaning: SymbolFlags, + nameNotFoundMessage: DiagnosticMessage | undefined, + nameArg: __String | Identifier | undefined, + isUse: boolean, + excludeGlobals: boolean, + getSpellingSuggestions: boolean, + ): Symbol | undefined { + const originalLocation = location; // needed for did-you-mean error reporting, which gathers candidates starting from the original location + let result: Symbol | undefined; + let lastLocation: Node | undefined; + let lastSelfReferenceLocation: Declaration | undefined; + let propertyWithInvalidInitializer: PropertyDeclaration | undefined; + let associatedDeclarationForContainingInitializerOrBindingName: ParameterDeclaration | BindingElement | undefined; + let withinDeferredContext = false; + const errorLocation = location; + let grandparent: Node; + let isInExternalModule = false; + + loop: + while (location) { + if (name === "const" && isConstAssertion(location)) { + // `const` in an `as const` has no symbol, but issues no error because there is no *actual* lookup of the type + // (it refers to the constant type of the expression instead) + return undefined; + } + if (isModuleOrEnumDeclaration(location) && lastLocation && location.name === lastLocation) { + // If lastLocation is the name of a namespace or enum, skip the parent since it will have is own locals that could + // conflict. + lastLocation = location; + location = location.parent; + } + // Locals of a source file are not in scope (because they get merged into the global symbol table) + if (canHaveLocals(location) && location.locals && !isGlobalSourceFile(location)) { + if (result = lookup(location.locals, name, meaning)) { + let useResult = true; + if (isFunctionLike(location) && lastLocation && lastLocation !== (location as FunctionLikeDeclaration).body) { + // symbol lookup restrictions for function-like declarations + // - Type parameters of a function are in scope in the entire function declaration, including the parameter + // list and return type. However, local types are only in scope in the function body. + // - parameters are only in the scope of function body + // This restriction does not apply to JSDoc comment types because they are parented + // at a higher level than type parameters would normally be + if (meaning & result.flags & SymbolFlags.Type && lastLocation.kind !== SyntaxKind.JSDoc) { + useResult = result.flags & SymbolFlags.TypeParameter + // type parameters are visible in parameter list, return type and type parameter list + ? lastLocation === (location as FunctionLikeDeclaration).type || + lastLocation.kind === SyntaxKind.Parameter || + lastLocation.kind === SyntaxKind.JSDocParameterTag || + lastLocation.kind === SyntaxKind.JSDocReturnTag || + lastLocation.kind === SyntaxKind.TypeParameter + // local types not visible outside the function body + : false; + } + if (meaning & result.flags & SymbolFlags.Variable) { + // expression inside parameter will lookup as normal variable scope when targeting es2015+ + if (useOuterVariableScopeInParameter(result, location, lastLocation)) { + useResult = false; + } + else if (result.flags & SymbolFlags.FunctionScopedVariable) { + // parameters are visible only inside function body, parameter list and return type + // technically for parameter list case here we might mix parameters and variables declared in function, + // however it is detected separately when checking initializers of parameters + // to make sure that they reference no variables declared after them. + useResult = lastLocation.kind === SyntaxKind.Parameter || + ( + lastLocation === (location as FunctionLikeDeclaration).type && + !!findAncestor(result.valueDeclaration, isParameter) + ); + } + } + } + else if (location.kind === SyntaxKind.ConditionalType) { + // A type parameter declared using 'infer T' in a conditional type is visible only in + // the true branch of the conditional type. + useResult = lastLocation === location.trueType; + } + + if (useResult) { + break loop; + } + else { + result = undefined; + } + } + } + withinDeferredContext = withinDeferredContext || getIsDeferredContext(location, lastLocation); + switch (location.kind) { + case SyntaxKind.SourceFile: + if (!isExternalOrCommonJsModule(location as SourceFile)) break; + isInExternalModule = true; + // falls through + case SyntaxKind.ModuleDeclaration: + const moduleExports = getSymbolOfDeclaration(location as SourceFile | ModuleDeclaration)?.exports || emptySymbols; + if (location.kind === SyntaxKind.SourceFile || (isModuleDeclaration(location) && location.flags & NodeFlags.Ambient && !isGlobalScopeAugmentation(location))) { + // It's an external module. First see if the module has an export default and if the local + // name of that export default matches. + if (result = moduleExports.get(InternalSymbolName.Default)) { + const localSymbol = getLocalSymbolForExportDefault(result); + if (localSymbol && (result.flags & meaning) && localSymbol.escapedName === name) { + break loop; + } + result = undefined; + } + + // Because of module/namespace merging, a module's exports are in scope, + // yet we never want to treat an export specifier as putting a member in scope. + // Therefore, if the name we find is purely an export specifier, it is not actually considered in scope. + // Two things to note about this: + // 1. We have to check this without calling getSymbol. The problem with calling getSymbol + // on an export specifier is that it might find the export specifier itself, and try to + // resolve it as an alias. This will cause the checker to consider the export specifier + // a circular alias reference when it might not be. + // 2. We check === SymbolFlags.Alias in order to check that the symbol is *purely* + // an alias. If we used &, we'd be throwing out symbols that have non alias aspects, + // which is not the desired behavior. + const moduleExport = moduleExports.get(name); + if ( + moduleExport && + moduleExport.flags === SymbolFlags.Alias && + (getDeclarationOfKind(moduleExport, SyntaxKind.ExportSpecifier) || getDeclarationOfKind(moduleExport, SyntaxKind.NamespaceExport)) + ) { + break; + } + } + + // 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))) { + if (isSourceFile(location) && location.commonJsModuleIndicator && !result.declarations?.some(isJSDocTypeAlias)) { + result = undefined; + } + else { + break loop; + } + } + break; + case SyntaxKind.EnumDeclaration: + if (result = lookup(getSymbolOfDeclaration(location as EnumDeclaration)?.exports || emptySymbols, name, meaning & SymbolFlags.EnumMember)) { + if (nameNotFoundMessage && getIsolatedModules(compilerOptions) && !(location.flags & NodeFlags.Ambient) && getSourceFileOfNode(location) !== getSourceFileOfNode(result.valueDeclaration)) { + error( + errorLocation, + Diagnostics.Cannot_access_0_from_another_file_without_qualification_when_1_is_enabled_Use_2_instead, + unescapeLeadingUnderscores(name), + isolatedModulesLikeFlagName, + `${unescapeLeadingUnderscores(getSymbolOfDeclaration(location as EnumDeclaration)!.escapedName)}.${unescapeLeadingUnderscores(name)}`, + ); + } + break loop; + } + break; + case SyntaxKind.PropertyDeclaration: + // TypeScript 1.0 spec (April 2014): 8.4.1 + // Initializer expressions for instance member variables are evaluated in the scope + // of the class constructor body but are not permitted to reference parameters or + // local variables of the constructor. This effectively means that entities from outer scopes + // by the same name as a constructor parameter or local variable are inaccessible + // in initializer expressions for instance member variables. + if (!isStatic(location)) { + const ctor = findConstructorDeclaration(location.parent as ClassLikeDeclaration); + if (ctor && ctor.locals) { + if (lookup(ctor.locals, name, meaning & SymbolFlags.Value)) { + // Remember the property node, it will be used later to report appropriate error + Debug.assertNode(location, isPropertyDeclaration); + propertyWithInvalidInitializer = location; + } + } + } + break; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.InterfaceDeclaration: + // The below is used to lookup type parameters within a class or interface, as they are added to the class/interface locals + // These can never be latebound, so the symbol's raw members are sufficient. `getMembersOfNode` cannot be used, as it would + // trigger resolving late-bound names, which we may already be in the process of doing while we're here! + if (result = lookup(getSymbolOfDeclaration(location as ClassLikeDeclaration | InterfaceDeclaration).members || emptySymbols, name, meaning & SymbolFlags.Type)) { + if (!isTypeParameterSymbolDeclaredInContainer(result, location)) { + // ignore type parameters not declared in this container + result = undefined; + break; + } + if (lastLocation && isStatic(lastLocation)) { + // TypeScript 1.0 spec (April 2014): 3.4.1 + // The scope of a type parameter extends over the entire declaration with which the type + // parameter list is associated, with the exception of static member declarations in classes. + if (nameNotFoundMessage) { + error(errorLocation, Diagnostics.Static_members_cannot_reference_class_type_parameters); + } + return undefined; + } + break loop; + } + if (isClassExpression(location) && meaning & SymbolFlags.Class) { + const className = location.name; + if (className && name === className.escapedText) { + result = location.symbol; + break loop; + } + } + break; + case SyntaxKind.ExpressionWithTypeArguments: + // The type parameters of a class are not in scope in the base class expression. + if (lastLocation === (location as ExpressionWithTypeArguments).expression && (location.parent as HeritageClause).token === SyntaxKind.ExtendsKeyword) { + const container = location.parent.parent; + if (isClassLike(container) && (result = lookup(getSymbolOfDeclaration(container).members!, name, meaning & SymbolFlags.Type))) { + if (nameNotFoundMessage) { + error(errorLocation, Diagnostics.Base_class_expressions_cannot_reference_class_type_parameters); + } + return undefined; + } + } + break; + // It is not legal to reference a class's own type parameters from a computed property name that + // belongs to the class. For example: + // + // function foo() { return '' } + // class C { // <-- Class's own type parameter T + // [foo()]() { } // <-- Reference to T from class's own computed property + // } + // + case SyntaxKind.ComputedPropertyName: + grandparent = location.parent.parent; + if (isClassLike(grandparent) || grandparent.kind === SyntaxKind.InterfaceDeclaration) { + // A reference to this grandparent's type parameters would be an error + if (result = lookup(getSymbolOfDeclaration(grandparent as ClassLikeDeclaration | InterfaceDeclaration).members!, name, meaning & SymbolFlags.Type)) { + if (nameNotFoundMessage) { + error(errorLocation, Diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type); + } + return undefined; + } + } + break; + case SyntaxKind.ArrowFunction: + // when targeting ES6 or higher there is no 'arguments' in an arrow function + // for lower compile targets the resolved symbol is used to emit an error + if (getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015) { + break; + } + // falls through + case SyntaxKind.MethodDeclaration: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionDeclaration: + if (meaning & SymbolFlags.Variable && name === "arguments") { + result = argumentsSymbol; + break loop; + } + break; + case SyntaxKind.FunctionExpression: + if (meaning & SymbolFlags.Variable && name === "arguments") { + result = argumentsSymbol; + break loop; + } + + if (meaning & SymbolFlags.Function) { + const functionName = (location as FunctionExpression).name; + if (functionName && name === functionName.escapedText) { + result = (location as FunctionExpression).symbol; + break loop; + } + } + break; + case SyntaxKind.Decorator: + // Decorators are resolved at the class declaration. Resolving at the parameter + // or member would result in looking up locals in the method. + // + // function y() {} + // class C { + // method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter. + // } + // + if (location.parent && location.parent.kind === SyntaxKind.Parameter) { + location = location.parent; + } + // + // function y() {} + // class C { + // @y method(x, y) {} // <-- decorator y should be resolved at the class declaration, not the method. + // } + // + + // class Decorators are resolved outside of the class to avoid referencing type parameters of that class. + // + // type T = number; + // declare function y(x: T): any; + // @param(1 as T) // <-- T should resolve to the type alias outside of class C + // class C {} + if (location.parent && (isClassElement(location.parent) || location.parent.kind === SyntaxKind.ClassDeclaration)) { + location = location.parent; + } + break; + case SyntaxKind.JSDocTypedefTag: + case SyntaxKind.JSDocCallbackTag: + case SyntaxKind.JSDocEnumTag: + // js type aliases do not resolve names from their host, so skip past it + const root = getJSDocRoot(location); + if (root) { + location = root.parent; + } + break; + case SyntaxKind.Parameter: + if ( + lastLocation && ( + lastLocation === (location as ParameterDeclaration).initializer || + lastLocation === (location as ParameterDeclaration).name && isBindingPattern(lastLocation) + ) + ) { + if (!associatedDeclarationForContainingInitializerOrBindingName) { + associatedDeclarationForContainingInitializerOrBindingName = location as ParameterDeclaration; + } + } + break; + case SyntaxKind.BindingElement: + if ( + lastLocation && ( + lastLocation === (location as BindingElement).initializer || + lastLocation === (location as BindingElement).name && isBindingPattern(lastLocation) + ) + ) { + if (isParameterDeclaration(location as BindingElement) && !associatedDeclarationForContainingInitializerOrBindingName) { + associatedDeclarationForContainingInitializerOrBindingName = location as BindingElement; + } + } + break; + case SyntaxKind.InferType: + if (meaning & SymbolFlags.TypeParameter) { + const parameterName = (location as InferTypeNode).typeParameter.name; + if (parameterName && name === parameterName.escapedText) { + result = (location as InferTypeNode).typeParameter.symbol; + break loop; + } + } + break; + case SyntaxKind.ExportSpecifier: + // External module export bindings shouldn't be resolved to local symbols. + if ( + lastLocation && + lastLocation === (location as ExportSpecifier).propertyName && + (location as ExportSpecifier).parent.parent.moduleSpecifier + ) { + location = location.parent.parent.parent; + } + break; + } + if (isSelfReferenceLocation(location)) { + lastSelfReferenceLocation = location; + } + lastLocation = location; + location = isJSDocTemplateTag(location) ? getEffectiveContainerForJSDocTemplateTag(location) || location.parent : + isJSDocParameterTag(location) || isJSDocReturnTag(location) ? getHostSignatureFromJSDoc(location) || location.parent : + location.parent; + } + + // We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`. + // If `result === lastSelfReferenceLocation.symbol`, that means that we are somewhere inside `lastSelfReferenceLocation` looking up a name, and resolving to `lastLocation` itself. + // That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used. + if (isUse && result && (!lastSelfReferenceLocation || result !== lastSelfReferenceLocation.symbol)) { + result.isReferenced! |= meaning; + } + + if (!result) { + if (lastLocation) { + Debug.assertNode(lastLocation, isSourceFile); + if (lastLocation.commonJsModuleIndicator && name === "exports" && meaning & lastLocation.symbol.flags) { + return lastLocation.symbol; + } + } + + if (!excludeGlobals) { + result = lookup(globals, name, meaning); + } + } + if (!result) { + if (originalLocation && isInJSFile(originalLocation) && originalLocation.parent) { + if (isRequireCall(originalLocation.parent, /*requireStringLiteralLikeArgument*/ false)) { + return requireSymbol; + } + } + } + return extendedResolveErrorReporting( + result, + originalLocation, + name, + meaning, + nameNotFoundMessage, + nameArg, + getSpellingSuggestions, + lookup, + lastLocation, + errorLocation, + propertyWithInvalidInitializer, + associatedDeclarationForContainingInitializerOrBindingName, + withinDeferredContext, + isInExternalModule, + ); + } +} diff --git a/src/harness/harnessIO.ts b/src/harness/harnessIO.ts index 04816728569e0..7fb7013c9c850 100644 --- a/src/harness/harnessIO.ts +++ b/src/harness/harnessIO.ts @@ -651,32 +651,20 @@ export namespace Compiler { if (!file) { return; } - const assertSymbolValid = ts.Debug.assertSymbolValid; - ts.Debug.assertSymbolValid = symbol => { - assertSymbolValid(symbol); - if (symbol.name) { - ts.Debug.assert(symbol.name[1] === ":", "Symbol is not from DTE"); - } - }; - try { - const { - diagnostics: fileDiagnostics = [], - declaration, - declarationPath, - declarationMap, - declarationMapPath, - } = transpileDeclaration(file, transpileOptions); - // Ensure file will be rebound. - file.locals = undefined; - dts.set(declarationPath, new documents.TextDocument(declarationPath, options.emitBOM ? Utils.addUTF8ByteOrderMark(declaration) : declaration)); - if (declarationMapPath && declarationMap) { - dtsMap.set(declarationMapPath, new documents.TextDocument(declarationMapPath, declarationMap)); - } - diagnostics.push(...fileDiagnostics); - } - finally { - ts.Debug.assertSymbolValid = assertSymbolValid; + const { + diagnostics: fileDiagnostics = [], + declaration, + declarationPath, + declarationMap, + declarationMapPath, + } = transpileDeclaration(file, transpileOptions); + // Ensure file will be rebound. + file.locals = undefined; + dts.set(declarationPath, new documents.TextDocument(declarationPath, options.emitBOM ? Utils.addUTF8ByteOrderMark(declaration) : declaration)); + if (declarationMapPath && declarationMap) { + dtsMap.set(declarationMapPath, new documents.TextDocument(declarationMapPath, declarationMap)); } + diagnostics.push(...fileDiagnostics); }); return { dts, dtsMap, diagnostics }; } diff --git a/tests/baselines/reference/isolated-declarations/auto-fixed/diff/isolatedDeclarationErrorsClasses.d.ts.diff b/tests/baselines/reference/isolated-declarations/auto-fixed/diff/isolatedDeclarationErrorsClasses.d.ts.diff index e6fca408e428b..a1ba1c9c32509 100644 --- a/tests/baselines/reference/isolated-declarations/auto-fixed/diff/isolatedDeclarationErrorsClasses.d.ts.diff +++ b/tests/baselines/reference/isolated-declarations/auto-fixed/diff/isolatedDeclarationErrorsClasses.d.ts.diff @@ -5,7 +5,7 @@ =================================================================== --- TSC declarations +++ DTE declarations -@@ -17,15 +17,23 @@ +@@ -17,15 +17,21 @@ set getSetOk2(value: number); get getSetOk3(): number; set getSetOk3(value: number); @@ -18,8 +18,6 @@ + [missing]: number; [noAnnotationLiteralName](): void; [noParamAnnotationLiteralName](v: string): void; -+ [noAnnotationStringName](): void; -+ [noParamAnnotationStringName](v: invalid): void; + get [noAnnotationStringName](): number; + set [noParamAnnotationStringName](value: invalid); } @@ -29,12 +27,9 @@ } export {}; -@@ -33,16 +41,18 @@ - - isolatedDeclarationErrorsClasses.ts(36,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. +@@ -35,14 +41,15 @@ isolatedDeclarationErrorsClasses.ts(36,6): error TS2304: Cannot find name 'missing'. isolatedDeclarationErrorsClasses.ts(44,35): error TS7006: Parameter 'v' implicitly has an 'any' type. -+isolatedDeclarationErrorsClasses.ts(44,35): error TS9011: Parameter must have an explicit type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(48,9): error TS7032: Property '[noParamAnnotationStringName]' implicitly has type 'any', because its set accessor lacks a parameter type annotation. isolatedDeclarationErrorsClasses.ts(48,39): error TS7006: Parameter 'value' implicitly has an 'any' type. +isolatedDeclarationErrorsClasses.ts(48,39): error TS9009: At least one accessor must have an explicit return type annotation with --isolatedDeclarations. @@ -44,23 +39,12 @@ -==== isolatedDeclarationErrorsClasses.ts (8 errors) ==== -+==== isolatedDeclarationErrorsClasses.ts (10 errors) ==== ++==== isolatedDeclarationErrorsClasses.ts (9 errors) ==== export class Cls { field: number = 1 + 1; method(): void {} -@@ -91,16 +101,22 @@ - - [noParamAnnotationStringName](v): void { } - ~ - !!! error TS7006: Parameter 'v' implicitly has an 'any' type. -+ ~ -+!!! error TS9011: Parameter must have an explicit type annotation with --isolatedDeclarations. -+!!! related TS9028 isolatedDeclarationErrorsClasses.ts:44:35: Add a type annotation to the parameter v. - - get [noAnnotationStringName](): number { return 0;} - - set [noParamAnnotationStringName](value) { } +@@ -99,8 +106,11 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS7032: Property '[noParamAnnotationStringName]' implicitly has type 'any', because its set accessor lacks a parameter type annotation. ~~~~~ diff --git a/tests/baselines/reference/isolated-declarations/auto-fixed/diff/isolatedDeclarationErrorsExpandoFunctions.d.ts.diff b/tests/baselines/reference/isolated-declarations/auto-fixed/diff/isolatedDeclarationErrorsExpandoFunctions.d.ts.diff new file mode 100644 index 0000000000000..f677c51d38b54 --- /dev/null +++ b/tests/baselines/reference/isolated-declarations/auto-fixed/diff/isolatedDeclarationErrorsExpandoFunctions.d.ts.diff @@ -0,0 +1,55 @@ +// [[Reason: Expando function declarations are not fixed.]] //// + +//// [tests/cases/compiler/isolatedDeclarationErrorsExpandoFunctions.ts] //// + +=================================================================== +--- TSC declarations ++++ DTE declarations +@@ -1,12 +1,38 @@ + + + //// [isolatedDeclarationErrorsExpandoFunctions.d.ts] + export declare function foo(): void; +-export declare namespace foo { +- var apply: () => void; +- var call: () => void; +- var bind: () => void; +- var caller: () => void; +- var toString: () => void; +- var length: number; +-} ++ ++/// [Errors] //// ++ ++isolatedDeclarationErrorsExpandoFunctions.ts(3,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++isolatedDeclarationErrorsExpandoFunctions.ts(4,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++isolatedDeclarationErrorsExpandoFunctions.ts(5,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++isolatedDeclarationErrorsExpandoFunctions.ts(6,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++isolatedDeclarationErrorsExpandoFunctions.ts(7,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++isolatedDeclarationErrorsExpandoFunctions.ts(8,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++ ++ ++==== isolatedDeclarationErrorsExpandoFunctions.ts (6 errors) ==== ++ export function foo(): void {} ++ ++ foo.apply = () => {} ++ ~~~~~~~~~ ++!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++ foo.call = ()=> {} ++ ~~~~~~~~ ++!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++ foo.bind = ()=> {} ++ ~~~~~~~~ ++!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++ foo.caller = ()=> {} ++ ~~~~~~~~~~ ++!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++ foo.toString = ()=> {} ++ ~~~~~~~~~~~~ ++!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++ foo.length = 10 ++ ~~~~~~~~~~ ++!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. ++ foo.length = 10 ++ +\ No newline at end of file diff --git a/tests/baselines/reference/isolated-declarations/auto-fixed/diff/isolatedDeclarationLazySymbols.d.ts.diff b/tests/baselines/reference/isolated-declarations/auto-fixed/diff/isolatedDeclarationLazySymbols.d.ts.diff new file mode 100644 index 0000000000000..8a06b4b452bc8 --- /dev/null +++ b/tests/baselines/reference/isolated-declarations/auto-fixed/diff/isolatedDeclarationLazySymbols.d.ts.diff @@ -0,0 +1,45 @@ +// [[Reason: Expando function declarations are not fixed.]] //// + +//// [tests/cases/compiler/isolatedDeclarationLazySymbols.ts] //// + +=================================================================== +--- TSC declarations ++++ DTE declarations +@@ -1,11 +1,8 @@ + + + //// [isolatedDeclarationLazySymbols.d.ts] + export declare function foo(): void; +-export declare namespace foo { +- var b: string; +-} + declare const o: { + readonly "prop.inner": "a"; + readonly prop: { + readonly inner: "b"; +@@ -20,12 +17,13 @@ + export {}; + //# sourceMappingURL=isolatedDeclarationLazySymbols.d.ts.map + /// [Errors] //// + ++isolatedDeclarationLazySymbols.ts(13,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + isolatedDeclarationLazySymbols.ts(16,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. + + +-==== isolatedDeclarationLazySymbols.ts (1 errors) ==== ++==== isolatedDeclarationLazySymbols.ts (2 errors) ==== + export function foo(): void { + + } + +@@ -37,8 +35,10 @@ + } as const + + foo[o["prop.inner"]] ="A"; + foo[o.prop.inner] = "B"; ++ ~~~~~~~~~~~~~~~~~ ++!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + + export class Foo { + [o["prop.inner"]] ="A" + ~~~~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/isolated-declarations/auto-fixed/dte/isolatedDeclarationErrorsClasses.d.ts b/tests/baselines/reference/isolated-declarations/auto-fixed/dte/isolatedDeclarationErrorsClasses.d.ts index deea9e5fed88d..9775b1125a00d 100644 --- a/tests/baselines/reference/isolated-declarations/auto-fixed/dte/isolatedDeclarationErrorsClasses.d.ts +++ b/tests/baselines/reference/isolated-declarations/auto-fixed/dte/isolatedDeclarationErrorsClasses.d.ts @@ -89,8 +89,6 @@ export declare class C { [missing]: number; [noAnnotationLiteralName](): void; [noParamAnnotationLiteralName](v: string): void; - [noAnnotationStringName](): void; - [noParamAnnotationStringName](v: invalid): void; get [noAnnotationStringName](): number; set [noParamAnnotationStringName](value: invalid); } @@ -105,7 +103,6 @@ export {}; isolatedDeclarationErrorsClasses.ts(36,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. isolatedDeclarationErrorsClasses.ts(36,6): error TS2304: Cannot find name 'missing'. isolatedDeclarationErrorsClasses.ts(44,35): error TS7006: Parameter 'v' implicitly has an 'any' type. -isolatedDeclarationErrorsClasses.ts(44,35): error TS9011: Parameter must have an explicit type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(48,9): error TS7032: Property '[noParamAnnotationStringName]' implicitly has type 'any', because its set accessor lacks a parameter type annotation. isolatedDeclarationErrorsClasses.ts(48,39): error TS7006: Parameter 'value' implicitly has an 'any' type. isolatedDeclarationErrorsClasses.ts(48,39): error TS9009: At least one accessor must have an explicit return type annotation with --isolatedDeclarations. @@ -114,7 +111,7 @@ isolatedDeclarationErrorsClasses.ts(55,5): error TS1169: A computed property nam isolatedDeclarationErrorsClasses.ts(56,5): error TS7010: '[noAnnotationLiteralName]', which lacks return-type annotation, implicitly has an 'any' return type. -==== isolatedDeclarationErrorsClasses.ts (10 errors) ==== +==== isolatedDeclarationErrorsClasses.ts (9 errors) ==== export class Cls { field: number = 1 + 1; @@ -165,9 +162,6 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS7010: '[noAnnotationLiteralNa [noParamAnnotationStringName](v): void { } ~ !!! error TS7006: Parameter 'v' implicitly has an 'any' type. - ~ -!!! error TS9011: Parameter must have an explicit type annotation with --isolatedDeclarations. -!!! related TS9028 isolatedDeclarationErrorsClasses.ts:44:35: Add a type annotation to the parameter v. get [noAnnotationStringName](): number { return 0;} diff --git a/tests/baselines/reference/isolated-declarations/auto-fixed/dte/isolatedDeclarationErrorsExpandoFunctions.d.ts b/tests/baselines/reference/isolated-declarations/auto-fixed/dte/isolatedDeclarationErrorsExpandoFunctions.d.ts new file mode 100644 index 0000000000000..6e61f3422c646 --- /dev/null +++ b/tests/baselines/reference/isolated-declarations/auto-fixed/dte/isolatedDeclarationErrorsExpandoFunctions.d.ts @@ -0,0 +1,54 @@ +//// [tests/cases/compiler/isolatedDeclarationErrorsExpandoFunctions.ts] //// + +//// [isolatedDeclarationErrorsExpandoFunctions.ts] +export function foo(): void {} + +foo.apply = () => {} +foo.call = ()=> {} +foo.bind = ()=> {} +foo.caller = ()=> {} +foo.toString = ()=> {} +foo.length = 10 +foo.length = 10 + + +/// [Declarations] //// + + + +//// [isolatedDeclarationErrorsExpandoFunctions.d.ts] +export declare function foo(): void; + +/// [Errors] //// + +isolatedDeclarationErrorsExpandoFunctions.ts(3,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationErrorsExpandoFunctions.ts(4,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationErrorsExpandoFunctions.ts(5,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationErrorsExpandoFunctions.ts(6,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationErrorsExpandoFunctions.ts(7,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationErrorsExpandoFunctions.ts(8,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + + +==== isolatedDeclarationErrorsExpandoFunctions.ts (6 errors) ==== + export function foo(): void {} + + foo.apply = () => {} + ~~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.call = ()=> {} + ~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.bind = ()=> {} + ~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.caller = ()=> {} + ~~~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.toString = ()=> {} + ~~~~~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.length = 10 + ~~~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.length = 10 + \ No newline at end of file diff --git a/tests/baselines/reference/isolated-declarations/auto-fixed/dte/isolatedDeclarationLazySymbols.d.ts b/tests/baselines/reference/isolated-declarations/auto-fixed/dte/isolatedDeclarationLazySymbols.d.ts new file mode 100644 index 0000000000000..d6d0fe041e302 --- /dev/null +++ b/tests/baselines/reference/isolated-declarations/auto-fixed/dte/isolatedDeclarationLazySymbols.d.ts @@ -0,0 +1,87 @@ +//// [tests/cases/compiler/isolatedDeclarationLazySymbols.ts] //// + +//// [isolatedDeclarationLazySymbols.ts] +export function foo(): void { + +} + +const o = { + ["prop.inner"]: "a", + prop: { + inner: "b", + } +} as const + +foo[o["prop.inner"]] ="A"; +foo[o.prop.inner] = "B"; + +export class Foo { + [o["prop.inner"]] ="A" + [o.prop.inner] = "B" +} + +export let oo: { + a: string; + [o.prop.inner]: string; +} = { + [o['prop.inner']]:"A", + [o.prop.inner]: "B", +} + +/// [Declarations] //// + + + +//// [isolatedDeclarationLazySymbols.d.ts] +export declare function foo(): void; +declare const o: { + readonly "prop.inner": "a"; + readonly prop: { + readonly inner: "b"; + }; +}; +export declare class Foo { +} +export declare let oo: { + a: string; + [o.prop.inner]: string; +}; +export {}; +//# sourceMappingURL=isolatedDeclarationLazySymbols.d.ts.map +/// [Errors] //// + +isolatedDeclarationLazySymbols.ts(13,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationLazySymbols.ts(16,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. + + +==== isolatedDeclarationLazySymbols.ts (2 errors) ==== + export function foo(): void { + + } + + const o = { + ["prop.inner"]: "a", + prop: { + inner: "b", + } + } as const + + foo[o["prop.inner"]] ="A"; + foo[o.prop.inner] = "B"; + ~~~~~~~~~~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + + export class Foo { + [o["prop.inner"]] ="A" + ~~~~~~~~~~~~~~~~~ +!!! error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. + [o.prop.inner] = "B" + } + + export let oo: { + a: string; + [o.prop.inner]: string; + } = { + [o['prop.inner']]:"A", + [o.prop.inner]: "B", + } \ No newline at end of file diff --git a/tests/baselines/reference/isolated-declarations/auto-fixed/tsc/isolatedDeclarationErrorsExpandoFunctions.d.ts b/tests/baselines/reference/isolated-declarations/auto-fixed/tsc/isolatedDeclarationErrorsExpandoFunctions.d.ts new file mode 100644 index 0000000000000..96e5dcbf714fd --- /dev/null +++ b/tests/baselines/reference/isolated-declarations/auto-fixed/tsc/isolatedDeclarationErrorsExpandoFunctions.d.ts @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/isolatedDeclarationErrorsExpandoFunctions.ts] //// + +//// [isolatedDeclarationErrorsExpandoFunctions.ts] +export function foo(): void {} + +foo.apply = () => {} +foo.call = ()=> {} +foo.bind = ()=> {} +foo.caller = ()=> {} +foo.toString = ()=> {} +foo.length = 10 +foo.length = 10 + + +/// [Declarations] //// + + + +//// [isolatedDeclarationErrorsExpandoFunctions.d.ts] +export declare function foo(): void; +export declare namespace foo { + var apply: () => void; + var call: () => void; + var bind: () => void; + var caller: () => void; + var toString: () => void; + var length: number; +} diff --git a/tests/baselines/reference/isolated-declarations/auto-fixed/tsc/isolatedDeclarationLazySymbols.d.ts b/tests/baselines/reference/isolated-declarations/auto-fixed/tsc/isolatedDeclarationLazySymbols.d.ts new file mode 100644 index 0000000000000..69724d1fc0654 --- /dev/null +++ b/tests/baselines/reference/isolated-declarations/auto-fixed/tsc/isolatedDeclarationLazySymbols.d.ts @@ -0,0 +1,87 @@ +//// [tests/cases/compiler/isolatedDeclarationLazySymbols.ts] //// + +//// [isolatedDeclarationLazySymbols.ts] +export function foo(): void { + +} + +const o = { + ["prop.inner"]: "a", + prop: { + inner: "b", + } +} as const + +foo[o["prop.inner"]] ="A"; +foo[o.prop.inner] = "B"; + +export class Foo { + [o["prop.inner"]] ="A" + [o.prop.inner] = "B" +} + +export let oo: { + a: string; + [o.prop.inner]: string; +} = { + [o['prop.inner']]:"A", + [o.prop.inner]: "B", +} + +/// [Declarations] //// + + + +//// [isolatedDeclarationLazySymbols.d.ts] +export declare function foo(): void; +export declare namespace foo { + var b: string; +} +declare const o: { + readonly "prop.inner": "a"; + readonly prop: { + readonly inner: "b"; + }; +}; +export declare class Foo { +} +export declare let oo: { + a: string; + [o.prop.inner]: string; +}; +export {}; +//# sourceMappingURL=isolatedDeclarationLazySymbols.d.ts.map +/// [Errors] //// + +isolatedDeclarationLazySymbols.ts(16,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. + + +==== isolatedDeclarationLazySymbols.ts (1 errors) ==== + export function foo(): void { + + } + + const o = { + ["prop.inner"]: "a", + prop: { + inner: "b", + } + } as const + + foo[o["prop.inner"]] ="A"; + foo[o.prop.inner] = "B"; + + export class Foo { + [o["prop.inner"]] ="A" + ~~~~~~~~~~~~~~~~~ +!!! error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. + [o.prop.inner] = "B" + } + + export let oo: { + a: string; + [o.prop.inner]: string; + } = { + [o['prop.inner']]:"A", + [o.prop.inner]: "B", + } \ No newline at end of file diff --git a/tests/baselines/reference/isolated-declarations/original/diff/isolatedDeclarationErrorsClasses.d.ts.diff b/tests/baselines/reference/isolated-declarations/original/diff/isolatedDeclarationErrorsClasses.d.ts.diff index 2ef3cc8ae222f..ed1ea183d51f5 100644 --- a/tests/baselines/reference/isolated-declarations/original/diff/isolatedDeclarationErrorsClasses.d.ts.diff +++ b/tests/baselines/reference/isolated-declarations/original/diff/isolatedDeclarationErrorsClasses.d.ts.diff @@ -5,7 +5,7 @@ =================================================================== --- TSC declarations +++ DTE declarations -@@ -17,15 +17,23 @@ +@@ -17,15 +17,21 @@ set getSetOk2(value: number); get getSetOk3(): number; set getSetOk3(value: number); @@ -18,8 +18,6 @@ + [missing]: number; [noAnnotationLiteralName](): void; [noParamAnnotationLiteralName](v: string): void; -+ [noAnnotationStringName](): invalid; -+ [noParamAnnotationStringName](v: invalid): void; + get [noAnnotationStringName](): invalid; + set [noParamAnnotationStringName](value: invalid); } @@ -29,17 +27,15 @@ } export {}; -@@ -42,15 +50,15 @@ +@@ -42,21 +48,19 @@ isolatedDeclarationErrorsClasses.ts(12,17): error TS9009: At least one accessor must have an explicit return type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(14,9): error TS9009: At least one accessor must have an explicit return type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(36,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. isolatedDeclarationErrorsClasses.ts(36,6): error TS2304: Cannot find name 'missing'. -isolatedDeclarationErrorsClasses.ts(42,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations. -isolatedDeclarationErrorsClasses.ts(44,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations. -+isolatedDeclarationErrorsClasses.ts(42,5): error TS9008: Method must have an explicit return type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(44,35): error TS7006: Parameter 'v' implicitly has an 'any' type. -isolatedDeclarationErrorsClasses.ts(46,9): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations. -+isolatedDeclarationErrorsClasses.ts(44,35): error TS9011: Parameter must have an explicit type annotation with --isolatedDeclarations. +isolatedDeclarationErrorsClasses.ts(46,9): error TS9009: At least one accessor must have an explicit return type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(48,9): error TS7032: Property '[noParamAnnotationStringName]' implicitly has type 'any', because its set accessor lacks a parameter type annotation. -isolatedDeclarationErrorsClasses.ts(48,9): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations. @@ -49,23 +45,26 @@ isolatedDeclarationErrorsClasses.ts(55,5): error TS1169: A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type. isolatedDeclarationErrorsClasses.ts(56,5): error TS7010: '[noAnnotationLiteralName]', which lacks return-type annotation, implicitly has an 'any' return type. -@@ -130,27 +138,31 @@ + +-==== isolatedDeclarationErrorsClasses.ts (22 errors) ==== ++==== isolatedDeclarationErrorsClasses.ts (20 errors) ==== + export class Cls { + + field = 1 + 1; + ~~~~~ +@@ -129,28 +133,26 @@ + [noParamAnnotationLiteralName](v: string): void { } [noAnnotationStringName]() { } - ~~~~~~~~~~~~~~~~~~~~~~~~ +- ~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations. -+!!! error TS9008: Method must have an explicit return type annotation with --isolatedDeclarations. -+!!! related TS9034 isolatedDeclarationErrorsClasses.ts:42:5: Add a return type to the method [noParamAnnotationStringName](v): void { } - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations. ~ !!! error TS7006: Parameter 'v' implicitly has an 'any' type. -+ ~ -+!!! error TS9011: Parameter must have an explicit type annotation with --isolatedDeclarations. -+!!! related TS9028 isolatedDeclarationErrorsClasses.ts:44:35: Add a type annotation to the parameter v. get [noAnnotationStringName]() { return 0;} ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/isolated-declarations/original/dte/isolatedDeclarationErrorsClasses.d.ts b/tests/baselines/reference/isolated-declarations/original/dte/isolatedDeclarationErrorsClasses.d.ts index 44cf94c995b06..35277ad5bd69c 100644 --- a/tests/baselines/reference/isolated-declarations/original/dte/isolatedDeclarationErrorsClasses.d.ts +++ b/tests/baselines/reference/isolated-declarations/original/dte/isolatedDeclarationErrorsClasses.d.ts @@ -89,8 +89,6 @@ export declare class C { [missing]: number; [noAnnotationLiteralName](): void; [noParamAnnotationLiteralName](v: string): void; - [noAnnotationStringName](): invalid; - [noParamAnnotationStringName](v: invalid): void; get [noAnnotationStringName](): invalid; set [noParamAnnotationStringName](value: invalid); } @@ -114,9 +112,7 @@ isolatedDeclarationErrorsClasses.ts(12,17): error TS9009: At least one accessor isolatedDeclarationErrorsClasses.ts(14,9): error TS9009: At least one accessor must have an explicit return type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(36,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. isolatedDeclarationErrorsClasses.ts(36,6): error TS2304: Cannot find name 'missing'. -isolatedDeclarationErrorsClasses.ts(42,5): error TS9008: Method must have an explicit return type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(44,35): error TS7006: Parameter 'v' implicitly has an 'any' type. -isolatedDeclarationErrorsClasses.ts(44,35): error TS9011: Parameter must have an explicit type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(46,9): error TS9009: At least one accessor must have an explicit return type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(48,9): error TS7032: Property '[noParamAnnotationStringName]' implicitly has type 'any', because its set accessor lacks a parameter type annotation. isolatedDeclarationErrorsClasses.ts(48,39): error TS7006: Parameter 'value' implicitly has an 'any' type. @@ -126,7 +122,7 @@ isolatedDeclarationErrorsClasses.ts(55,5): error TS1169: A computed property nam isolatedDeclarationErrorsClasses.ts(56,5): error TS7010: '[noAnnotationLiteralName]', which lacks return-type annotation, implicitly has an 'any' return type. -==== isolatedDeclarationErrorsClasses.ts (22 errors) ==== +==== isolatedDeclarationErrorsClasses.ts (20 errors) ==== export class Cls { field = 1 + 1; @@ -201,16 +197,10 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS7010: '[noAnnotationLiteralNa [noParamAnnotationLiteralName](v: string): void { } [noAnnotationStringName]() { } - ~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS9008: Method must have an explicit return type annotation with --isolatedDeclarations. -!!! related TS9034 isolatedDeclarationErrorsClasses.ts:42:5: Add a return type to the method [noParamAnnotationStringName](v): void { } ~ !!! error TS7006: Parameter 'v' implicitly has an 'any' type. - ~ -!!! error TS9011: Parameter must have an explicit type annotation with --isolatedDeclarations. -!!! related TS9028 isolatedDeclarationErrorsClasses.ts:44:35: Add a type annotation to the parameter v. get [noAnnotationStringName]() { return 0;} ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.errors.txt b/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.errors.txt new file mode 100644 index 0000000000000..adc2ffbf0df9a --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.errors.txt @@ -0,0 +1,35 @@ +isolatedDeclarationErrorsExpandoFunctions.ts(1,17): error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +isolatedDeclarationErrorsExpandoFunctions.ts(3,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationErrorsExpandoFunctions.ts(4,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationErrorsExpandoFunctions.ts(5,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationErrorsExpandoFunctions.ts(6,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationErrorsExpandoFunctions.ts(7,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationErrorsExpandoFunctions.ts(8,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + + +==== isolatedDeclarationErrorsExpandoFunctions.ts (7 errors) ==== + export function foo() {} + ~~~ +!!! error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +!!! related TS9031 isolatedDeclarationErrorsExpandoFunctions.ts:1:17: Add a return type to the function declaration. + + foo.apply = () => {} + ~~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.call = ()=> {} + ~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.bind = ()=> {} + ~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.caller = ()=> {} + ~~~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.toString = ()=> {} + ~~~~~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.length = 10 + ~~~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + foo.length = 10 + \ No newline at end of file diff --git a/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.js b/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.js new file mode 100644 index 0000000000000..f62409ac37f85 --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.js @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/isolatedDeclarationErrorsExpandoFunctions.ts] //// + +//// [isolatedDeclarationErrorsExpandoFunctions.ts] +export function foo() {} + +foo.apply = () => {} +foo.call = ()=> {} +foo.bind = ()=> {} +foo.caller = ()=> {} +foo.toString = ()=> {} +foo.length = 10 +foo.length = 10 + + +//// [isolatedDeclarationErrorsExpandoFunctions.js] +export function foo() { } +foo.apply = () => { }; +foo.call = () => { }; +foo.bind = () => { }; +foo.caller = () => { }; +foo.toString = () => { }; +foo.length = 10; +foo.length = 10; diff --git a/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.symbols b/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.symbols new file mode 100644 index 0000000000000..bb2acb5f3865e --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.symbols @@ -0,0 +1,41 @@ +//// [tests/cases/compiler/isolatedDeclarationErrorsExpandoFunctions.ts] //// + +=== isolatedDeclarationErrorsExpandoFunctions.ts === +export function foo() {} +>foo : Symbol(foo, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 0), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 24), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 2, 20), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 3, 18), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 4, 18) ... and 3 more) + +foo.apply = () => {} +>foo.apply : Symbol(foo.apply, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 24)) +>foo : Symbol(foo, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 0), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 24), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 2, 20), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 3, 18), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 4, 18) ... and 3 more) +>apply : Symbol(foo.apply, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 24)) + +foo.call = ()=> {} +>foo.call : Symbol(foo.call, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 2, 20)) +>foo : Symbol(foo, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 0), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 24), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 2, 20), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 3, 18), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 4, 18) ... and 3 more) +>call : Symbol(foo.call, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 2, 20)) + +foo.bind = ()=> {} +>foo.bind : Symbol(foo.bind, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 3, 18)) +>foo : Symbol(foo, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 0), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 24), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 2, 20), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 3, 18), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 4, 18) ... and 3 more) +>bind : Symbol(foo.bind, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 3, 18)) + +foo.caller = ()=> {} +>foo.caller : Symbol(foo.caller, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 4, 18)) +>foo : Symbol(foo, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 0), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 24), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 2, 20), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 3, 18), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 4, 18) ... and 3 more) +>caller : Symbol(foo.caller, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 4, 18)) + +foo.toString = ()=> {} +>foo.toString : Symbol(foo.toString, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 5, 20)) +>foo : Symbol(foo, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 0), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 24), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 2, 20), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 3, 18), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 4, 18) ... and 3 more) +>toString : Symbol(foo.toString, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 5, 20)) + +foo.length = 10 +>foo.length : Symbol(foo.length, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 6, 22), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 7, 15)) +>foo : Symbol(foo, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 0), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 24), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 2, 20), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 3, 18), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 4, 18) ... and 3 more) +>length : Symbol(foo.length, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 6, 22), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 7, 15)) + +foo.length = 10 +>foo.length : Symbol(foo.length, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 6, 22), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 7, 15)) +>foo : Symbol(foo, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 0), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 0, 24), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 2, 20), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 3, 18), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 4, 18) ... and 3 more) +>length : Symbol(foo.length, Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 6, 22), Decl(isolatedDeclarationErrorsExpandoFunctions.ts, 7, 15)) + diff --git a/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.types b/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.types new file mode 100644 index 0000000000000..163b703b40c69 --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationErrorsExpandoFunctions.types @@ -0,0 +1,55 @@ +//// [tests/cases/compiler/isolatedDeclarationErrorsExpandoFunctions.ts] //// + +=== isolatedDeclarationErrorsExpandoFunctions.ts === +export function foo() {} +>foo : typeof foo + +foo.apply = () => {} +>foo.apply = () => {} : () => void +>foo.apply : () => void +>foo : typeof foo +>apply : () => void +>() => {} : () => void + +foo.call = ()=> {} +>foo.call = ()=> {} : () => void +>foo.call : () => void +>foo : typeof foo +>call : () => void +>()=> {} : () => void + +foo.bind = ()=> {} +>foo.bind = ()=> {} : () => void +>foo.bind : () => void +>foo : typeof foo +>bind : () => void +>()=> {} : () => void + +foo.caller = ()=> {} +>foo.caller = ()=> {} : () => void +>foo.caller : () => void +>foo : typeof foo +>caller : () => void +>()=> {} : () => void + +foo.toString = ()=> {} +>foo.toString = ()=> {} : () => void +>foo.toString : () => void +>foo : typeof foo +>toString : () => void +>()=> {} : () => void + +foo.length = 10 +>foo.length = 10 : 10 +>foo.length : number +>foo : typeof foo +>length : number +>10 : 10 + +foo.length = 10 +>foo.length = 10 : 10 +>foo.length : number +>foo : typeof foo +>length : number +>10 : 10 + diff --git a/tests/baselines/reference/isolatedDeclarationLazySymbols.errors.txt b/tests/baselines/reference/isolatedDeclarationLazySymbols.errors.txt new file mode 100644 index 0000000000000..bb46d672d1099 --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationLazySymbols.errors.txt @@ -0,0 +1,40 @@ +isolatedDeclarationLazySymbols.ts(1,17): error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +isolatedDeclarationLazySymbols.ts(13,1): error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. +isolatedDeclarationLazySymbols.ts(16,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. +isolatedDeclarationLazySymbols.ts(21,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations. + + +==== isolatedDeclarationLazySymbols.ts (4 errors) ==== + export function foo() { + ~~~ +!!! error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +!!! related TS9031 isolatedDeclarationLazySymbols.ts:1:17: Add a return type to the function declaration. + + } + + const o = { + ["prop.inner"]: "a", + prop: { + inner: "b", + } + } as const + + foo[o["prop.inner"]] ="A"; + foo[o.prop.inner] = "B"; + ~~~~~~~~~~~~~~~~~ +!!! error TS9023: Assigning properties to functions without declaring them is not supported with --isolatedDeclarations. Add an explicit declaration for the properties assigned to this function. + + export class Foo { + [o["prop.inner"]] ="A" + ~~~~~~~~~~~~~~~~~ +!!! error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. + [o.prop.inner] = "B" + } + + export let oo = { + [o['prop.inner']]:"A", + ~~~~~~~~~~~~~~~~~ +!!! error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations. +!!! related TS9027 isolatedDeclarationLazySymbols.ts:20:12: Add a type annotation to the variable oo. + [o.prop.inner]: "B", + } \ No newline at end of file diff --git a/tests/baselines/reference/isolatedDeclarationLazySymbols.js b/tests/baselines/reference/isolatedDeclarationLazySymbols.js new file mode 100644 index 0000000000000..fbcc574d35f63 --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationLazySymbols.js @@ -0,0 +1,45 @@ +//// [tests/cases/compiler/isolatedDeclarationLazySymbols.ts] //// + +//// [isolatedDeclarationLazySymbols.ts] +export function foo() { + +} + +const o = { + ["prop.inner"]: "a", + prop: { + inner: "b", + } +} as const + +foo[o["prop.inner"]] ="A"; +foo[o.prop.inner] = "B"; + +export class Foo { + [o["prop.inner"]] ="A" + [o.prop.inner] = "B" +} + +export let oo = { + [o['prop.inner']]:"A", + [o.prop.inner]: "B", +} + +//// [isolatedDeclarationLazySymbols.js] +export function foo() { +} +const o = { + ["prop.inner"]: "a", + prop: { + inner: "b", + } +}; +foo[o["prop.inner"]] = "A"; +foo[o.prop.inner] = "B"; +export class Foo { + [o["prop.inner"]] = "A"[o.prop.inner] = "B"; +} +export let oo = { + [o['prop.inner']]: "A", + [o.prop.inner]: "B", +}; diff --git a/tests/baselines/reference/isolatedDeclarationLazySymbols.symbols b/tests/baselines/reference/isolatedDeclarationLazySymbols.symbols new file mode 100644 index 0000000000000..f2df8038e2c75 --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationLazySymbols.symbols @@ -0,0 +1,69 @@ +//// [tests/cases/compiler/isolatedDeclarationLazySymbols.ts] //// + +=== isolatedDeclarationLazySymbols.ts === +export function foo() { +>foo : Symbol(foo, Decl(isolatedDeclarationLazySymbols.ts, 0, 0), Decl(isolatedDeclarationLazySymbols.ts, 9, 10), Decl(isolatedDeclarationLazySymbols.ts, 11, 26)) + +} + +const o = { +>o : Symbol(o, Decl(isolatedDeclarationLazySymbols.ts, 4, 5)) + + ["prop.inner"]: "a", +>["prop.inner"] : Symbol(["prop.inner"], Decl(isolatedDeclarationLazySymbols.ts, 4, 11)) +>"prop.inner" : Symbol(["prop.inner"], Decl(isolatedDeclarationLazySymbols.ts, 4, 11)) + + prop: { +>prop : Symbol(prop, Decl(isolatedDeclarationLazySymbols.ts, 5, 24)) + + inner: "b", +>inner : Symbol(inner, Decl(isolatedDeclarationLazySymbols.ts, 6, 11)) + } +} as const +>const : Symbol(const) + +foo[o["prop.inner"]] ="A"; +>foo : Symbol(foo, Decl(isolatedDeclarationLazySymbols.ts, 0, 0), Decl(isolatedDeclarationLazySymbols.ts, 9, 10), Decl(isolatedDeclarationLazySymbols.ts, 11, 26)) +>o : Symbol(o, Decl(isolatedDeclarationLazySymbols.ts, 4, 5)) +>"prop.inner" : Symbol(["prop.inner"], Decl(isolatedDeclarationLazySymbols.ts, 4, 11)) + +foo[o.prop.inner] = "B"; +>foo : Symbol(foo, Decl(isolatedDeclarationLazySymbols.ts, 0, 0), Decl(isolatedDeclarationLazySymbols.ts, 9, 10), Decl(isolatedDeclarationLazySymbols.ts, 11, 26)) +>o.prop.inner : Symbol(inner, Decl(isolatedDeclarationLazySymbols.ts, 6, 11)) +>o.prop : Symbol(prop, Decl(isolatedDeclarationLazySymbols.ts, 5, 24)) +>o : Symbol(o, Decl(isolatedDeclarationLazySymbols.ts, 4, 5)) +>prop : Symbol(prop, Decl(isolatedDeclarationLazySymbols.ts, 5, 24)) +>inner : Symbol(inner, Decl(isolatedDeclarationLazySymbols.ts, 6, 11)) + +export class Foo { +>Foo : Symbol(Foo, Decl(isolatedDeclarationLazySymbols.ts, 12, 24)) + + [o["prop.inner"]] ="A" +>[o["prop.inner"]] : Symbol(Foo[o["prop.inner"]], Decl(isolatedDeclarationLazySymbols.ts, 14, 18)) +>o : Symbol(o, Decl(isolatedDeclarationLazySymbols.ts, 4, 5)) +>"prop.inner" : Symbol(["prop.inner"], Decl(isolatedDeclarationLazySymbols.ts, 4, 11)) + + [o.prop.inner] = "B" +>o.prop.inner : Symbol(inner, Decl(isolatedDeclarationLazySymbols.ts, 6, 11)) +>o.prop : Symbol(prop, Decl(isolatedDeclarationLazySymbols.ts, 5, 24)) +>o : Symbol(o, Decl(isolatedDeclarationLazySymbols.ts, 4, 5)) +>prop : Symbol(prop, Decl(isolatedDeclarationLazySymbols.ts, 5, 24)) +>inner : Symbol(inner, Decl(isolatedDeclarationLazySymbols.ts, 6, 11)) +} + +export let oo = { +>oo : Symbol(oo, Decl(isolatedDeclarationLazySymbols.ts, 19, 10)) + + [o['prop.inner']]:"A", +>[o['prop.inner']] : Symbol([o['prop.inner']], Decl(isolatedDeclarationLazySymbols.ts, 19, 17)) +>o : Symbol(o, Decl(isolatedDeclarationLazySymbols.ts, 4, 5)) +>'prop.inner' : Symbol(["prop.inner"], Decl(isolatedDeclarationLazySymbols.ts, 4, 11)) + + [o.prop.inner]: "B", +>[o.prop.inner] : Symbol([o.prop.inner], Decl(isolatedDeclarationLazySymbols.ts, 20, 26)) +>o.prop.inner : Symbol(inner, Decl(isolatedDeclarationLazySymbols.ts, 6, 11)) +>o.prop : Symbol(prop, Decl(isolatedDeclarationLazySymbols.ts, 5, 24)) +>o : Symbol(o, Decl(isolatedDeclarationLazySymbols.ts, 4, 5)) +>prop : Symbol(prop, Decl(isolatedDeclarationLazySymbols.ts, 5, 24)) +>inner : Symbol(inner, Decl(isolatedDeclarationLazySymbols.ts, 6, 11)) +} diff --git a/tests/baselines/reference/isolatedDeclarationLazySymbols.types b/tests/baselines/reference/isolatedDeclarationLazySymbols.types new file mode 100644 index 0000000000000..10a376bec89d9 --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationLazySymbols.types @@ -0,0 +1,89 @@ +//// [tests/cases/compiler/isolatedDeclarationLazySymbols.ts] //// + +=== isolatedDeclarationLazySymbols.ts === +export function foo() { +>foo : typeof foo + +} + +const o = { +>o : { readonly "prop.inner": "a"; readonly prop: { readonly inner: "b"; }; } +>{ ["prop.inner"]: "a", prop: { inner: "b", }} as const : { readonly "prop.inner": "a"; readonly prop: { readonly inner: "b"; }; } +>{ ["prop.inner"]: "a", prop: { inner: "b", }} : { readonly "prop.inner": "a"; readonly prop: { readonly inner: "b"; }; } + + ["prop.inner"]: "a", +>["prop.inner"] : "a" +>"prop.inner" : "prop.inner" +>"a" : "a" + + prop: { +>prop : { readonly inner: "b"; } +>{ inner: "b", } : { readonly inner: "b"; } + + inner: "b", +>inner : "b" +>"b" : "b" + } +} as const + +foo[o["prop.inner"]] ="A"; +>foo[o["prop.inner"]] ="A" : "A" +>foo[o["prop.inner"]] : any +>foo : typeof foo +>o["prop.inner"] : "a" +>o : { readonly "prop.inner": "a"; readonly prop: { readonly inner: "b"; }; } +>"prop.inner" : "prop.inner" +>"A" : "A" + +foo[o.prop.inner] = "B"; +>foo[o.prop.inner] = "B" : "B" +>foo[o.prop.inner] : string +>foo : typeof foo +>o.prop.inner : "b" +>o.prop : { readonly inner: "b"; } +>o : { readonly "prop.inner": "a"; readonly prop: { readonly inner: "b"; }; } +>prop : { readonly inner: "b"; } +>inner : "b" +>"B" : "B" + +export class Foo { +>Foo : Foo + + [o["prop.inner"]] ="A" +>[o["prop.inner"]] : string +>o["prop.inner"] : "a" +>o : { readonly "prop.inner": "a"; readonly prop: { readonly inner: "b"; }; } +>"prop.inner" : "prop.inner" +>"A" [o.prop.inner] = "B" : "B" +>"A" [o.prop.inner] : any +>"A" : "A" + + [o.prop.inner] = "B" +>o.prop.inner : "b" +>o.prop : { readonly inner: "b"; } +>o : { readonly "prop.inner": "a"; readonly prop: { readonly inner: "b"; }; } +>prop : { readonly inner: "b"; } +>inner : "b" +>"B" : "B" +} + +export let oo = { +>oo : { a: string; b: string; } +>{ [o['prop.inner']]:"A", [o.prop.inner]: "B",} : { a: string; b: string; } + + [o['prop.inner']]:"A", +>[o['prop.inner']] : string +>o['prop.inner'] : "a" +>o : { readonly "prop.inner": "a"; readonly prop: { readonly inner: "b"; }; } +>'prop.inner' : "prop.inner" +>"A" : "A" + + [o.prop.inner]: "B", +>[o.prop.inner] : string +>o.prop.inner : "b" +>o.prop : { readonly inner: "b"; } +>o : { readonly "prop.inner": "a"; readonly prop: { readonly inner: "b"; }; } +>prop : { readonly inner: "b"; } +>inner : "b" +>"B" : "B" +} diff --git a/tests/cases/compiler/isolatedDeclarationErrorsExpandoFunctions.ts b/tests/cases/compiler/isolatedDeclarationErrorsExpandoFunctions.ts new file mode 100644 index 0000000000000..2afd232fdb232 --- /dev/null +++ b/tests/cases/compiler/isolatedDeclarationErrorsExpandoFunctions.ts @@ -0,0 +1,15 @@ +// @declaration: true +// @isolatedDeclarations: true +// @declarationMap: false +// @target: ESNext +// @isolatedDeclarationFixedDiffReason: Expando function declarations are not fixed. + +export function foo() {} + +foo.apply = () => {} +foo.call = ()=> {} +foo.bind = ()=> {} +foo.caller = ()=> {} +foo.toString = ()=> {} +foo.length = 10 +foo.length = 10 diff --git a/tests/cases/compiler/isolatedDeclarationLazySymbols.ts b/tests/cases/compiler/isolatedDeclarationLazySymbols.ts new file mode 100644 index 0000000000000..c8b1fbf602d24 --- /dev/null +++ b/tests/cases/compiler/isolatedDeclarationLazySymbols.ts @@ -0,0 +1,29 @@ +// @declaration: true +// @isolatedDeclarations: true +// @target: ESNext +// @isolatedDeclarationFixedDiffReason: Expando function declarations are not fixed. + + +export function foo() { + +} + +const o = { + ["prop.inner"]: "a", + prop: { + inner: "b", + } +} as const + +foo[o["prop.inner"]] ="A"; +foo[o.prop.inner] = "B"; + +export class Foo { + [o["prop.inner"]] ="A" + [o.prop.inner] = "B" +} + +export let oo = { + [o['prop.inner']]:"A", + [o.prop.inner]: "B", +} \ No newline at end of file diff --git a/tests/cases/conformance/es6/Symbols/symbolDeclarationEmit12.ts b/tests/cases/conformance/es6/Symbols/symbolDeclarationEmit12.ts index 80f6bc43bd006..8422b1ec016de 100644 --- a/tests/cases/conformance/es6/Symbols/symbolDeclarationEmit12.ts +++ b/tests/cases/conformance/es6/Symbols/symbolDeclarationEmit12.ts @@ -1,7 +1,5 @@ //@target: ES6 //@declaration: true -//@isolatedDeclarationDiffReason: Invalid computed property can only be detected by TSC -//@isolatedDeclarationFixedDiffReason: Can't fix computed properties module M { interface I { } export class C {