diff --git a/src/compiler/#checker.ts# b/src/compiler/#checker.ts#
deleted file mode 100644
index 2384341aa35..00000000000
--- a/src/compiler/#checker.ts#
+++ /dev/null
@@ -1,18412 +0,0 @@
-///
-
-/* @internal */
-namespace ts {
- let nextSymbolId = 1;
- let nextNodeId = 1;
- let nextMergeId = 1;
-
- export function getNodeId(node: Node): number {
- if (!node.id) {
- node.id = nextNodeId;
- nextNodeId++;
- }
- return node.id;
- }
-
- export let checkTime = 0;
-
- export function getSymbolId(symbol: Symbol): number {
- if (!symbol.id) {
- symbol.id = nextSymbolId;
- nextSymbolId++;
- }
-
- return symbol.id;
- }
-
- export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker {
- // Cancellation that controls whether or not we can cancel in the middle of type checking.
- // In general cancelling is *not* safe for the type checker. We might be in the middle of
- // computing something, and we will leave our internals in an inconsistent state. Callers
- // who set the cancellation token should catch if a cancellation exception occurs, and
- // should throw away and create a new TypeChecker.
- //
- // Currently we only support setting the cancellation token when getting diagnostics. This
- // is because diagnostics can be quite expensive, and we want to allow hosts to bail out if
- // they no longer need the information (for example, if the user started editing again).
- let cancellationToken: CancellationToken;
-
- const Symbol = objectAllocator.getSymbolConstructor();
- const Type = objectAllocator.getTypeConstructor();
- const Signature = objectAllocator.getSignatureConstructor();
-
- let typeCount = 0;
- let symbolCount = 0;
-
- const emptyArray: any[] = [];
- const emptySymbols: SymbolTable = {};
-
- const compilerOptions = host.getCompilerOptions();
- const languageVersion = compilerOptions.target || ScriptTarget.ES3;
- const modulekind = getEmitModuleKind(compilerOptions);
- const allowSyntheticDefaultImports = typeof compilerOptions.allowSyntheticDefaultImports !== "undefined" ? compilerOptions.allowSyntheticDefaultImports : modulekind === ModuleKind.System;
- const strictNullChecks = compilerOptions.strictNullChecks;
-
- const emitResolver = createResolver();
-
- const undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
- undefinedSymbol.declarations = [];
- const argumentsSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "arguments");
-
- const checker: TypeChecker = {
- getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"),
- getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
- getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount") + symbolCount,
- getTypeCount: () => typeCount,
- isUndefinedSymbol: symbol => symbol === undefinedSymbol,
- isArgumentsSymbol: symbol => symbol === argumentsSymbol,
- isUnknownSymbol: symbol => symbol === unknownSymbol,
- getDiagnostics,
- getGlobalDiagnostics,
- getTypeOfSymbolAtLocation,
- getSymbolsOfParameterPropertyDeclaration,
- getDeclaredTypeOfSymbol,
- getPropertiesOfType,
- getPropertyOfType,
- getSignaturesOfType,
- getIndexTypeOfType,
- getBaseTypes,
- getReturnTypeOfSignature,
- getSymbolsInScope,
- getSymbolAtLocation,
- getShorthandAssignmentValueSymbol,
- getExportSpecifierLocalTargetSymbol,
- getTypeAtLocation: getTypeOfNode,
- getPropertySymbolOfDestructuringAssignment,
- typeToString,
- getSymbolDisplayBuilder,
- symbolToString,
- getAugmentedPropertiesOfType,
- getRootSymbols,
- getContextualType,
- getFullyQualifiedName,
- getResolvedSignature,
- getConstantValue,
- isValidPropertyAccess,
- getSignatureFromDeclaration,
- isImplementationOfOverload,
- getAliasedSymbol: resolveAlias,
- getEmitResolver,
- getExportsOfModule: getExportsOfModuleAsArray,
-
- getJsxElementAttributesType,
- getJsxIntrinsicTagNames,
- isOptionalParameter
- };
-
- const unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown");
- const resolvingSymbol = createSymbol(SymbolFlags.Transient, "__resolving__");
-
- const nullableWideningFlags = strictNullChecks ? 0 : TypeFlags.ContainsUndefinedOrNull;
- const anyType = createIntrinsicType(TypeFlags.Any, "any");
- const stringType = createIntrinsicType(TypeFlags.String, "string");
- const numberType = createIntrinsicType(TypeFlags.Number, "number");
- const booleanType = createIntrinsicType(TypeFlags.Boolean, "boolean");
- const esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol");
- const voidType = createIntrinsicType(TypeFlags.Void, "void");
- const undefinedType = createIntrinsicType(TypeFlags.Undefined | nullableWideningFlags, "undefined");
- const nullType = createIntrinsicType(TypeFlags.Null | nullableWideningFlags, "null");
- const emptyArrayElementType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsUndefinedOrNull, "undefined");
- const unknownType = createIntrinsicType(TypeFlags.Any, "unknown");
-
- const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
- const emptyUnionType = emptyObjectType;
- const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
- emptyGenericType.instantiations = {};
-
- const anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
- // The anyFunctionType contains the anyFunctionType by definition. The flag is further propagated
- // in getPropagatingFlagsOfTypes, and it is checked in inferFromTypes.
- anyFunctionType.flags |= TypeFlags.ContainsAnyFunctionType;
-
- const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
-
- const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false);
- const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false);
-
- const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
-
- const globals: SymbolTable = {};
-
- let getGlobalESSymbolConstructorSymbol: () => Symbol;
-
- let getGlobalPromiseConstructorSymbol: () => Symbol;
-
- let globalObjectType: ObjectType;
- let globalFunctionType: ObjectType;
- let globalArrayType: GenericType;
- let globalReadonlyArrayType: GenericType;
- let globalStringType: ObjectType;
- let globalNumberType: ObjectType;
- let globalBooleanType: ObjectType;
- let globalRegExpType: ObjectType;
- let anyArrayType: Type;
- let anyReadonlyArrayType: Type;
-
- // The library files are only loaded when the feature is used.
- // This allows users to just specify library files they want to used through --lib
- // and they will not get an error from not having unrelated library files
- let getGlobalTemplateStringsArrayType: () => ObjectType;
-
- let getGlobalESSymbolType: () => ObjectType;
- let getGlobalIterableType: () => GenericType;
- let getGlobalIteratorType: () => GenericType;
- let getGlobalIterableIteratorType: () => GenericType;
-
- let getGlobalClassDecoratorType: () => ObjectType;
- let getGlobalParameterDecoratorType: () => ObjectType;
- let getGlobalPropertyDecoratorType: () => ObjectType;
- let getGlobalMethodDecoratorType: () => ObjectType;
- let getGlobalTypedPropertyDescriptorType: () => ObjectType;
- let getGlobalPromiseType: () => ObjectType;
- let tryGetGlobalPromiseType: () => ObjectType;
- let getGlobalPromiseLikeType: () => ObjectType;
- let getInstantiatedGlobalPromiseLikeType: () => ObjectType;
- let getGlobalPromiseConstructorLikeType: () => ObjectType;
- let getGlobalThenableType: () => ObjectType;
-
- let jsxElementClassType: Type;
-
- let deferredNodes: Node[];
-
- const tupleTypes: Map = {};
- const unionTypes: Map = {};
- const intersectionTypes: Map = {};
- const stringLiteralTypes: Map = {};
-
- const resolutionTargets: TypeSystemEntity[] = [];
- const resolutionResults: boolean[] = [];
- const resolutionPropertyNames: TypeSystemPropertyName[] = [];
-
- const mergedSymbols: Symbol[] = [];
- const symbolLinks: SymbolLinks[] = [];
- const nodeLinks: NodeLinks[] = [];
- const potentialThisCollisions: Node[] = [];
- const awaitedTypeStack: number[] = [];
-
- const diagnostics = createDiagnosticCollection();
-
- const primitiveTypeInfo: Map<{ type: Type; flags: TypeFlags }> = {
- "string": {
- type: stringType,
- flags: TypeFlags.StringLike
- },
- "number": {
- type: numberType,
- flags: TypeFlags.NumberLike
- },
- "boolean": {
- type: booleanType,
- flags: TypeFlags.Boolean
- },
- "symbol": {
- type: esSymbolType,
- flags: TypeFlags.ESSymbol
- },
- "undefined": {
- type: undefinedType,
- flags: TypeFlags.ContainsUndefinedOrNull
- }
- };
-
- let jsxElementType: ObjectType;
- /** Things we lazy load from the JSX namespace */
- const jsxTypes: Map = {};
- const JsxNames = {
- JSX: "JSX",
- IntrinsicElements: "IntrinsicElements",
- ElementClass: "ElementClass",
- ElementAttributesPropertyNameContainer: "ElementAttributesProperty",
- Element: "Element",
- IntrinsicAttributes: "IntrinsicAttributes",
- IntrinsicClassAttributes: "IntrinsicClassAttributes"
- };
-
- const subtypeRelation: Map = {};
- const assignableRelation: Map = {};
- const comparableRelation: Map = {};
- const identityRelation: Map = {};
-
- // This is for caching the result of getSymbolDisplayBuilder. Do not access directly.
- let _displayBuilder: SymbolDisplayBuilder;
-
- type TypeSystemEntity = Symbol | Type | Signature;
-
- const enum TypeSystemPropertyName {
- Type,
- ResolvedBaseConstructorType,
- DeclaredType,
- ResolvedReturnType
- }
-
- const builtinGlobals: SymbolTable = {
- [undefinedSymbol.name]: undefinedSymbol
- };
-
- initializeTypeChecker();
-
- return checker;
-
- function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) {
- // Ensure we have all the type information in place for this file so that all the
- // emitter questions of this resolver will return the right information.
- getDiagnostics(sourceFile, cancellationToken);
- return emitResolver;
- }
-
- function error(location: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void {
- const diagnostic = location
- ? createDiagnosticForNode(location, message, arg0, arg1, arg2)
- : createCompilerDiagnostic(message, arg0, arg1, arg2);
- diagnostics.add(diagnostic);
- }
-
- function createSymbol(flags: SymbolFlags, name: string): Symbol {
- symbolCount++;
- return new Symbol(flags, name);
- }
-
- function getExcludedSymbolFlags(flags: SymbolFlags): SymbolFlags {
- let result: SymbolFlags = 0;
- if (flags & SymbolFlags.BlockScopedVariable) result |= SymbolFlags.BlockScopedVariableExcludes;
- if (flags & SymbolFlags.FunctionScopedVariable) result |= SymbolFlags.FunctionScopedVariableExcludes;
- if (flags & SymbolFlags.Property) result |= SymbolFlags.PropertyExcludes;
- if (flags & SymbolFlags.EnumMember) result |= SymbolFlags.EnumMemberExcludes;
- if (flags & SymbolFlags.Function) result |= SymbolFlags.FunctionExcludes;
- if (flags & SymbolFlags.Class) result |= SymbolFlags.ClassExcludes;
- if (flags & SymbolFlags.Interface) result |= SymbolFlags.InterfaceExcludes;
- if (flags & SymbolFlags.RegularEnum) result |= SymbolFlags.RegularEnumExcludes;
- if (flags & SymbolFlags.ConstEnum) result |= SymbolFlags.ConstEnumExcludes;
- if (flags & SymbolFlags.ValueModule) result |= SymbolFlags.ValueModuleExcludes;
- if (flags & SymbolFlags.Method) result |= SymbolFlags.MethodExcludes;
- if (flags & SymbolFlags.GetAccessor) result |= SymbolFlags.GetAccessorExcludes;
- if (flags & SymbolFlags.SetAccessor) result |= SymbolFlags.SetAccessorExcludes;
- if (flags & SymbolFlags.TypeParameter) result |= SymbolFlags.TypeParameterExcludes;
- if (flags & SymbolFlags.TypeAlias) result |= SymbolFlags.TypeAliasExcludes;
- if (flags & SymbolFlags.Alias) result |= SymbolFlags.AliasExcludes;
- return result;
- }
-
- function recordMergedSymbol(target: Symbol, source: Symbol) {
- if (!source.mergeId) {
- source.mergeId = nextMergeId;
- nextMergeId++;
- }
- mergedSymbols[source.mergeId] = target;
- }
-
- function cloneSymbol(symbol: Symbol): Symbol {
- const result = createSymbol(symbol.flags | SymbolFlags.Merged, symbol.name);
- result.declarations = symbol.declarations.slice(0);
- result.parent = symbol.parent;
- if (symbol.valueDeclaration) result.valueDeclaration = symbol.valueDeclaration;
- if (symbol.constEnumOnlyModule) result.constEnumOnlyModule = true;
- if (symbol.members) result.members = cloneSymbolTable(symbol.members);
- if (symbol.exports) result.exports = cloneSymbolTable(symbol.exports);
- recordMergedSymbol(result, symbol);
- return result;
- }
-
- function mergeSymbol(target: Symbol, source: Symbol) {
- if (!(target.flags & getExcludedSymbolFlags(source.flags))) {
- if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) {
- // reset flag when merging instantiated module into value module that has only const enums
- target.constEnumOnlyModule = false;
- }
- target.flags |= source.flags;
- if (source.valueDeclaration &&
- (!target.valueDeclaration ||
- (target.valueDeclaration.kind === SyntaxKind.ModuleDeclaration && source.valueDeclaration.kind !== SyntaxKind.ModuleDeclaration))) {
- // other kinds of value declarations take precedence over modules
- target.valueDeclaration = source.valueDeclaration;
- }
- forEach(source.declarations, node => {
- target.declarations.push(node);
- });
- if (source.members) {
- if (!target.members) target.members = {};
- mergeSymbolTable(target.members, source.members);
- }
- if (source.exports) {
- if (!target.exports) target.exports = {};
- mergeSymbolTable(target.exports, source.exports);
- }
- recordMergedSymbol(target, source);
- }
- else {
- const message = target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable
- ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0;
- forEach(source.declarations, node => {
- error(node.name ? node.name : node, message, symbolToString(source));
- });
- forEach(target.declarations, node => {
- error(node.name ? node.name : node, message, symbolToString(source));
- });
- }
- }
-
- function cloneSymbolTable(symbolTable: SymbolTable): SymbolTable {
- const result: SymbolTable = {};
- for (const id in symbolTable) {
- if (hasProperty(symbolTable, id)) {
- result[id] = symbolTable[id];
- }
- }
- return result;
- }
-
- function mergeSymbolTable(target: SymbolTable, source: SymbolTable) {
- for (const id in source) {
- if (hasProperty(source, id)) {
- if (!hasProperty(target, id)) {
- target[id] = source[id];
- }
- else {
- let symbol = target[id];
- if (!(symbol.flags & SymbolFlags.Merged)) {
- target[id] = symbol = cloneSymbol(symbol);
- }
- mergeSymbol(symbol, source[id]);
- }
- }
- }
- }
-
- function mergeModuleAugmentation(moduleName: LiteralExpression): void {
- const moduleAugmentation = moduleName.parent;
- if (moduleAugmentation.symbol.declarations[0] !== moduleAugmentation) {
- // this is a combined symbol for multiple augmentations within the same file.
- // its symbol already has accumulated information for all declarations
- // so we need to add it just once - do the work only for first declaration
- Debug.assert(moduleAugmentation.symbol.declarations.length > 1);
- return;
- }
-
- if (isGlobalScopeAugmentation(moduleAugmentation)) {
- mergeSymbolTable(globals, moduleAugmentation.symbol.exports);
- }
- else {
- // find a module that about to be augmented
- let mainModule = resolveExternalModuleNameWorker(moduleName, moduleName, Diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found);
- if (!mainModule) {
- return;
- }
- // obtain item referenced by 'export='
- mainModule = resolveExternalModuleSymbol(mainModule);
- if (mainModule.flags & SymbolFlags.Namespace) {
- // if module symbol has already been merged - it is safe to use it.
- // otherwise clone it
- mainModule = mainModule.flags & SymbolFlags.Merged ? mainModule : cloneSymbol(mainModule);
- mergeSymbol(mainModule, moduleAugmentation.symbol);
- }
- else {
- error(moduleName, Diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, moduleName.text);
- }
- }
- }
-
- function addToSymbolTable(target: SymbolTable, source: SymbolTable, message: DiagnosticMessage) {
- for (const id in source) {
- if (hasProperty(source, id)) {
- if (hasProperty(target, id)) {
- // Error on redeclarations
- forEach(target[id].declarations, addDeclarationDiagnostic(id, message));
- }
- else {
- target[id] = source[id];
- }
- }
- }
-
- function addDeclarationDiagnostic(id: string, message: DiagnosticMessage) {
- return (declaration: Declaration) => diagnostics.add(createDiagnosticForNode(declaration, message, id));
- }
- }
-
- function getSymbolLinks(symbol: Symbol): SymbolLinks {
- if (symbol.flags & SymbolFlags.Transient) return symbol;
- const id = getSymbolId(symbol);
- return symbolLinks[id] || (symbolLinks[id] = {});
- }
-
- function getNodeLinks(node: Node): NodeLinks {
- const nodeId = getNodeId(node);
- return nodeLinks[nodeId] || (nodeLinks[nodeId] = {});
- }
-
- function isGlobalSourceFile(node: Node) {
- return node.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(node);
- }
-
- function getSymbol(symbols: SymbolTable, name: string, meaning: SymbolFlags): Symbol {
- if (meaning && hasProperty(symbols, name)) {
- const symbol = symbols[name];
- Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0, "Should never get an instantiated symbol here.");
- if (symbol.flags & meaning) {
- return symbol;
- }
- if (symbol.flags & SymbolFlags.Alias) {
- const target = resolveAlias(symbol);
- // Unknown symbol means an error occurred in alias resolution, treat it as positive answer to avoid cascading errors
- if (target === unknownSymbol || target.flags & meaning) {
- return symbol;
- }
- }
- }
- // return undefined if we can't find a symbol.
- }
-
- /**
- * Get symbols that represent parameter-property-declaration as parameter and as property declaration
- * @param parameter a parameterDeclaration node
- * @param parameterName a name of the parameter to get the symbols for.
- * @return a tuple of two symbols
- */
- function getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): [Symbol, Symbol] {
- const constructorDeclaration = parameter.parent;
- const classDeclaration = parameter.parent.parent;
-
- const parameterSymbol = getSymbol(constructorDeclaration.locals, parameterName, SymbolFlags.Value);
- const propertySymbol = getSymbol(classDeclaration.symbol.members, parameterName, SymbolFlags.Value);
-
- if (parameterSymbol && propertySymbol) {
- return [parameterSymbol, propertySymbol];
- }
-
- Debug.fail("There should exist two symbols, one as property declaration and one as parameter declaration");
- }
-
- function isBlockScopedNameDeclaredBeforeUse(declaration: Declaration, usage: Node): boolean {
- const declarationFile = getSourceFileOfNode(declaration);
- const useFile = getSourceFileOfNode(usage);
- if (declarationFile !== useFile) {
- if (modulekind || (!compilerOptions.outFile && !compilerOptions.out)) {
- // nodes are in different files and order cannot be determines
- return true;
- }
-
- const sourceFiles = host.getSourceFiles();
- return indexOf(sourceFiles, declarationFile) <= indexOf(sourceFiles, useFile);
- }
-
- if (declaration.pos <= usage.pos) {
- // declaration is before usage
- // still might be illegal if usage is in the initializer of the variable declaration
- return declaration.kind !== SyntaxKind.VariableDeclaration ||
- !isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration, usage);
- }
-
- // declaration is after usage
- // can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
- return isUsedInFunctionOrNonStaticProperty(declaration, usage);
-
- function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean {
- const container = getEnclosingBlockScopeContainer(declaration);
-
- if (declaration.parent.parent.kind === SyntaxKind.VariableStatement ||
- declaration.parent.parent.kind === SyntaxKind.ForStatement) {
- // variable statement/for statement case,
- // use site should not be inside variable declaration (initializer of declaration or binding element)
- return isSameScopeDescendentOf(usage, declaration, container);
- }
- else if (declaration.parent.parent.kind === SyntaxKind.ForOfStatement ||
- declaration.parent.parent.kind === SyntaxKind.ForInStatement) {
- // ForIn/ForOf case - use site should not be used in expression part
- const expression = (declaration.parent.parent).expression;
- return isSameScopeDescendentOf(usage, expression, container);
- }
- }
-
- function isUsedInFunctionOrNonStaticProperty(declaration: Declaration, usage: Node): boolean {
- const container = getEnclosingBlockScopeContainer(declaration);
- let current = usage;
- while (current) {
- if (current === container) {
- return false;
- }
-
- if (isFunctionLike(current)) {
- return true;
- }
-
- const initializerOfNonStaticProperty = current.parent &&
- current.parent.kind === SyntaxKind.PropertyDeclaration &&
- (getModifierFlags(current.parent) & ModifierFlags.Static) === 0 &&
- (current.parent).initializer === current;
-
- if (initializerOfNonStaticProperty) {
- return true;
- }
-
- current = current.parent;
- }
- return false;
- }
- }
-
- // 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
- // the given name can be found.
- function resolveName(location: Node, name: string, meaning: SymbolFlags, nameNotFoundMessage: DiagnosticMessage, nameArg: string | Identifier): Symbol {
- let result: Symbol;
- let lastLocation: Node;
- let propertyWithInvalidInitializer: Node;
- const errorLocation = location;
- let grandparent: Node;
-
- loop: while (location) {
- // Locals of a source file are not in scope (because they get merged into the global symbol table)
- if (location.locals && !isGlobalSourceFile(location)) {
- if (result = getSymbol(location.locals, name, meaning)) {
- let useResult = true;
- if (isFunctionLike(location) && lastLocation && lastLocation !== (location).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.JSDocComment) {
- useResult = result.flags & SymbolFlags.TypeParameter
- // type parameters are visible in parameter list, return type and type parameter list
- ? lastLocation === (location).type ||
- lastLocation.kind === SyntaxKind.Parameter ||
- lastLocation.kind === SyntaxKind.TypeParameter
- // local types not visible outside the function body
- : false;
- }
- if (meaning & SymbolFlags.Value && 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).type &&
- result.valueDeclaration.kind === SyntaxKind.Parameter
- );
- }
- }
-
- if (useResult) {
- break loop;
- }
- else {
- result = undefined;
- }
- }
- }
- switch (location.kind) {
- case SyntaxKind.SourceFile:
- if (!isExternalOrCommonJsModule(location)) break;
- case SyntaxKind.ModuleDeclaration:
- const moduleExports = getSymbolOfNode(location).exports;
- if (location.kind === SyntaxKind.SourceFile || isAmbientModule(location)) {
-
- // It's an external module. First see if the module has an export default and if the local
- // name of that export default matches.
- if (result = moduleExports["default"]) {
- const localSymbol = getLocalSymbolForExportDefault(result);
- if (localSymbol && (result.flags & meaning) && localSymbol.name === 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.
- if (hasProperty(moduleExports, name) &&
- moduleExports[name].flags === SymbolFlags.Alias &&
- getDeclarationOfKind(moduleExports[name], SyntaxKind.ExportSpecifier)) {
- break;
- }
- }
-
- if (result = getSymbol(moduleExports, name, meaning & SymbolFlags.ModuleMember)) {
- break loop;
- }
- break;
- case SyntaxKind.EnumDeclaration:
- if (result = getSymbol(getSymbolOfNode(location).exports, name, meaning & SymbolFlags.EnumMember)) {
- break loop;
- }
- break;
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.PropertySignature:
- // 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 (isClassLike(location.parent) && !(getModifierFlags(location) & ModifierFlags.Static)) {
- const ctor = findConstructorDeclaration(location.parent);
- if (ctor && ctor.locals) {
- if (getSymbol(ctor.locals, name, meaning & SymbolFlags.Value)) {
- // Remember the property node, it will be used later to report appropriate error
- propertyWithInvalidInitializer = location;
- }
- }
- }
- break;
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.ClassExpression:
- case SyntaxKind.InterfaceDeclaration:
- if (result = getSymbol(getSymbolOfNode(location).members, name, meaning & SymbolFlags.Type)) {
- if (lastLocation && getModifierFlags(lastLocation) & ModifierFlags.Static) {
- // 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.
- error(errorLocation, Diagnostics.Static_members_cannot_reference_class_type_parameters);
- return undefined;
- }
- break loop;
- }
- if (location.kind === SyntaxKind.ClassExpression && meaning & SymbolFlags.Class) {
- const className = (location).name;
- if (className && name === className.text) {
- result = location.symbol;
- break loop;
- }
- }
- 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 = getSymbol(getSymbolOfNode(grandparent).members, name, meaning & SymbolFlags.Type)) {
- error(errorLocation, Diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type);
- return undefined;
- }
- }
- break;
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- case SyntaxKind.Constructor:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.ArrowFunction:
- 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).name;
- if (functionName && name === functionName.text) {
- result = location.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.
- // }
- //
- if (location.parent && isClassElement(location.parent)) {
- location = location.parent;
- }
- break;
- }
- lastLocation = location;
- location = location.parent;
- }
-
- if (!result) {
- result = getSymbol(globals, name, meaning);
- }
-
- if (!result) {
- if (nameNotFoundMessage) {
- if (!checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg)) {
- error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg));
- }
- }
- return undefined;
- }
-
- // Perform extra checks only if error reporting was requested
- if (nameNotFoundMessage) {
- if (propertyWithInvalidInitializer) {
- // 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.
- const propertyName = (propertyWithInvalidInitializer).name;
- error(errorLocation, Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor,
- declarationNameToString(propertyName), typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg));
- return undefined;
- }
-
- // Only check for block-scoped variable if we are looking for the
- // name with variable meaning
- // For example,
- // declare module foo {
- // interface bar {}
- // }
- // const foo/*1*/: foo/*2*/.bar;
- // The foo at /*1*/ and /*2*/ will share same symbol with two meaning
- // block - scope variable and namespace module. However, only when we
- // try to resolve name in /*1*/ which is used in variable position,
- // we want to check for block- scoped
- if (meaning & SymbolFlags.BlockScopedVariable) {
- const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result);
- if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable) {
- checkResolvedBlockScopedVariable(exportOrLocalSymbol, errorLocation);
- }
- }
- }
- return result;
- }
-
- function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: string, nameArg: string | Identifier): boolean {
- if (!errorLocation || (errorLocation.kind === SyntaxKind.Identifier && (isTypeReferenceIdentifier(errorLocation)) || isInTypeQuery(errorLocation))) {
- return false;
- }
-
- const container = getThisContainer(errorLocation, /* includeArrowFunctions */ true);
- let location = container;
- while (location) {
- if (isClassLike(location.parent)) {
- const classSymbol = getSymbolOfNode(location.parent);
- if (!classSymbol) {
- break;
- }
-
- // Check to see if a static member exists.
- const constructorType = getTypeOfSymbol(classSymbol);
- if (getPropertyOfType(constructorType, name)) {
- error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg), symbolToString(classSymbol));
- return true;
- }
-
- // No static member is present.
- // Check if we're in an instance method and look for a relevant instance member.
- if (location === container && !(getModifierFlags(location) & ModifierFlags.Static)) {
- const instanceType = (getDeclaredTypeOfSymbol(classSymbol)).thisType;
- if (getPropertyOfType(instanceType, name)) {
- error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg));
- return true;
- }
- }
- }
-
- location = location.parent;
- }
- return false;
- }
-
- function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void {
- Debug.assert((result.flags & SymbolFlags.BlockScopedVariable) !== 0);
- // Block-scoped variables cannot be used before their definition
- const declaration = forEach(result.declarations, d => isBlockOrCatchScoped(d) ? d : undefined);
-
- Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined");
-
- if (!isBlockScopedNameDeclaredBeforeUse(getAncestor(declaration, SyntaxKind.VariableDeclaration), errorLocation)) {
- error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(declaration.name));
- }
- }
-
- /* Starting from 'initial' node walk up the parent chain until 'stopAt' node is reached.
- * If at any point current node is equal to 'parent' node - return true.
- * Return false if 'stopAt' node is reached or isFunctionLike(current) === true.
- */
- function isSameScopeDescendentOf(initial: Node, parent: Node, stopAt: Node): boolean {
- if (!parent) {
- return false;
- }
- for (let current = initial; current && current !== stopAt && !isFunctionLike(current); current = current.parent) {
- if (current === parent) {
- return true;
- }
- }
- return false;
- }
-
- function getAnyImportSyntax(node: Node): AnyImportSyntax {
- if (isAliasSymbolDeclaration(node)) {
- if (node.kind === SyntaxKind.ImportEqualsDeclaration) {
- return node;
- }
-
- while (node && node.kind !== SyntaxKind.ImportDeclaration) {
- node = node.parent;
- }
- return node;
- }
- }
-
- function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration {
- return forEach(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined);
- }
-
- function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol {
- if (node.moduleReference.kind === SyntaxKind.ExternalModuleReference) {
- return resolveExternalModuleSymbol(resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node)));
- }
- return getSymbolOfPartOfRightHandSideOfImportEquals(node.moduleReference, node);
- }
-
- function getTargetOfImportClause(node: ImportClause): Symbol {
- const moduleSymbol = resolveExternalModuleName(node, (node.parent).moduleSpecifier);
-
- if (moduleSymbol) {
- const exportDefaultSymbol = moduleSymbol.exports["export="] ?
- getPropertyOfType(getTypeOfSymbol(moduleSymbol.exports["export="]), "default") :
- resolveSymbol(moduleSymbol.exports["default"]);
-
- if (!exportDefaultSymbol && !allowSyntheticDefaultImports) {
- error(node.name, Diagnostics.Module_0_has_no_default_export, symbolToString(moduleSymbol));
- }
- else if (!exportDefaultSymbol && allowSyntheticDefaultImports) {
- return resolveExternalModuleSymbol(moduleSymbol) || resolveSymbol(moduleSymbol);
- }
- return exportDefaultSymbol;
- }
- }
-
- function getTargetOfNamespaceImport(node: NamespaceImport): Symbol {
- const moduleSpecifier = (node.parent.parent).moduleSpecifier;
- return resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier);
- }
-
- // This function creates a synthetic symbol that combines the value side of one symbol with the
- // type/namespace side of another symbol. Consider this example:
- //
- // declare module graphics {
- // interface Point {
- // x: number;
- // y: number;
- // }
- // }
- // declare var graphics: {
- // Point: new (x: number, y: number) => graphics.Point;
- // }
- // declare module "graphics" {
- // export = graphics;
- // }
- //
- // An 'import { Point } from "graphics"' needs to create a symbol that combines the value side 'Point'
- // property with the type/namespace side interface 'Point'.
- function combineValueAndTypeSymbols(valueSymbol: Symbol, typeSymbol: Symbol): Symbol {
- if (valueSymbol.flags & (SymbolFlags.Type | SymbolFlags.Namespace)) {
- return valueSymbol;
- }
- const result = createSymbol(valueSymbol.flags | typeSymbol.flags, valueSymbol.name);
- result.declarations = concatenate(valueSymbol.declarations, typeSymbol.declarations);
- result.parent = valueSymbol.parent || typeSymbol.parent;
- if (valueSymbol.valueDeclaration) result.valueDeclaration = valueSymbol.valueDeclaration;
- if (typeSymbol.members) result.members = typeSymbol.members;
- if (valueSymbol.exports) result.exports = valueSymbol.exports;
- return result;
- }
-
- function getExportOfModule(symbol: Symbol, name: string): Symbol {
- if (symbol.flags & SymbolFlags.Module) {
- const exports = getExportsOfSymbol(symbol);
- if (hasProperty(exports, name)) {
- return resolveSymbol(exports[name]);
- }
- }
- }
-
- function getPropertyOfVariable(symbol: Symbol, name: string): Symbol {
- if (symbol.flags & SymbolFlags.Variable) {
- const typeAnnotation = (symbol.valueDeclaration).type;
- if (typeAnnotation) {
- return resolveSymbol(getPropertyOfType(getTypeFromTypeNode(typeAnnotation), name));
- }
- }
- }
-
- function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration, specifier: ImportOrExportSpecifier): Symbol {
- const moduleSymbol = resolveExternalModuleName(node, node.moduleSpecifier);
- const targetSymbol = resolveESModuleSymbol(moduleSymbol, node.moduleSpecifier);
- if (targetSymbol) {
- const name = specifier.propertyName || specifier.name;
- if (name.text) {
- let symbolFromVariable: Symbol;
- // First check if module was specified with "export=". If so, get the member from the resolved type
- if (moduleSymbol && moduleSymbol.exports && moduleSymbol.exports["export="]) {
- symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), name.text);
- }
- else {
- symbolFromVariable = getPropertyOfVariable(targetSymbol, name.text);
- }
- const symbolFromModule = getExportOfModule(targetSymbol, name.text);
- const symbol = symbolFromModule && symbolFromVariable ?
- combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) :
- symbolFromModule || symbolFromVariable;
- if (!symbol) {
- error(name, Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(moduleSymbol), declarationNameToString(name));
- }
- return symbol;
- }
- }
- }
-
- function getTargetOfImportSpecifier(node: ImportSpecifier): Symbol {
- return getExternalModuleMember(node.parent.parent.parent, node);
- }
-
- function getTargetOfGlobalModuleExportDeclaration(node: GlobalModuleExportDeclaration): Symbol {
- return resolveExternalModuleSymbol(node.parent.symbol);
- }
-
- function getTargetOfExportSpecifier(node: ExportSpecifier): Symbol {
- return (node.parent.parent).moduleSpecifier ?
- getExternalModuleMember(node.parent.parent, node) :
- resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
- }
-
- function getTargetOfExportAssignment(node: ExportAssignment): Symbol {
- return resolveEntityName(node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
- }
-
- function getTargetOfAliasDeclaration(node: Declaration): Symbol {
- switch (node.kind) {
- case SyntaxKind.ImportEqualsDeclaration:
- return getTargetOfImportEqualsDeclaration(node);
- case SyntaxKind.ImportClause:
- return getTargetOfImportClause(node);
- case SyntaxKind.NamespaceImport:
- return getTargetOfNamespaceImport(node);
- case SyntaxKind.ImportSpecifier:
- return getTargetOfImportSpecifier(node);
- case SyntaxKind.ExportSpecifier:
- return getTargetOfExportSpecifier(node);
- case SyntaxKind.ExportAssignment:
- return getTargetOfExportAssignment(node);
- case SyntaxKind.GlobalModuleExportDeclaration:
- return getTargetOfGlobalModuleExportDeclaration(node);
- }
- }
-
- function resolveSymbol(symbol: Symbol): Symbol {
- return symbol && symbol.flags & SymbolFlags.Alias && !(symbol.flags & (SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace)) ? resolveAlias(symbol) : symbol;
- }
-
- function resolveAlias(symbol: Symbol): Symbol {
- Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here.");
- const links = getSymbolLinks(symbol);
- if (!links.target) {
- links.target = resolvingSymbol;
- const node = getDeclarationOfAliasSymbol(symbol);
- const target = getTargetOfAliasDeclaration(node);
- if (links.target === resolvingSymbol) {
- links.target = target || unknownSymbol;
- }
- else {
- error(node, Diagnostics.Circular_definition_of_import_alias_0, symbolToString(symbol));
- }
- }
- else if (links.target === resolvingSymbol) {
- links.target = unknownSymbol;
- }
- return links.target;
- }
-
- function markExportAsReferenced(node: ImportEqualsDeclaration | ExportAssignment | ExportSpecifier) {
- const symbol = getSymbolOfNode(node);
- const target = resolveAlias(symbol);
- if (target) {
- const markAlias =
- (target === unknownSymbol && compilerOptions.isolatedModules) ||
- (target !== unknownSymbol && (target.flags & SymbolFlags.Value) && !isConstEnumOrConstEnumOnlyModule(target));
-
- if (markAlias) {
- markAliasSymbolAsReferenced(symbol);
- }
- }
- }
-
- // When an alias symbol is referenced, we need to mark the entity it references as referenced and in turn repeat that until
- // we reach a non-alias or an exported entity (which is always considered referenced). We do this by checking the target of
- // the alias as an expression (which recursively takes us back here if the target references another alias).
- function markAliasSymbolAsReferenced(symbol: Symbol) {
- const links = getSymbolLinks(symbol);
- if (!links.referenced) {
- links.referenced = true;
- const node = getDeclarationOfAliasSymbol(symbol);
- if (node.kind === SyntaxKind.ExportAssignment) {
- // export default
- checkExpressionCached((node).expression);
- }
- else if (node.kind === SyntaxKind.ExportSpecifier) {
- // export { } or export { as foo }
- checkExpressionCached((node).propertyName || (node).name);
- }
- else if (isInternalModuleImportEqualsDeclaration(node)) {
- // import foo =
- checkExpressionCached((node).moduleReference);
- }
- }
- }
-
- // This function is only for imports with entity names
- function getSymbolOfPartOfRightHandSideOfImportEquals(entityName: EntityName, importDeclaration?: ImportEqualsDeclaration): Symbol {
- if (!importDeclaration) {
- importDeclaration = getAncestor(entityName, SyntaxKind.ImportEqualsDeclaration);
- Debug.assert(importDeclaration !== undefined);
- }
- // There are three things we might try to look for. In the following examples,
- // the search term is enclosed in |...|:
- //
- // import a = |b|; // Namespace
- // import a = |b.c|; // Value, type, namespace
- // import a = |b.c|.d; // Namespace
- if (entityName.kind === SyntaxKind.Identifier && isRightSideOfQualifiedNameOrPropertyAccess(entityName)) {
- entityName = entityName.parent;
- }
- // Check for case 1 and 3 in the above example
- if (entityName.kind === SyntaxKind.Identifier || entityName.parent.kind === SyntaxKind.QualifiedName) {
- return resolveEntityName(entityName, SymbolFlags.Namespace);
- }
- else {
- // Case 2 in above example
- // entityName.kind could be a QualifiedName or a Missing identifier
- Debug.assert(entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration);
- return resolveEntityName(entityName, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
- }
- }
-
- function getFullyQualifiedName(symbol: Symbol): string {
- return symbol.parent ? getFullyQualifiedName(symbol.parent) + "." + symbolToString(symbol) : symbolToString(symbol);
- }
-
- // Resolves a qualified name and any involved aliases
- function resolveEntityName(name: EntityName | Expression, meaning: SymbolFlags, ignoreErrors?: boolean, location?: Node): Symbol {
- if (nodeIsMissing(name)) {
- return undefined;
- }
-
- let symbol: Symbol;
- if (name.kind === SyntaxKind.Identifier) {
- const message = meaning === SymbolFlags.Namespace ? Diagnostics.Cannot_find_namespace_0 : Diagnostics.Cannot_find_name_0;
-
- symbol = resolveName(location || name, (name).text, meaning, ignoreErrors ? undefined : message, name);
- if (!symbol) {
- return undefined;
- }
- }
- else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) {
- const left = name.kind === SyntaxKind.QualifiedName ? (name).left : (name).expression;
- const right = name.kind === SyntaxKind.QualifiedName ? (name).right : (name).name;
-
- const namespace = resolveEntityName(left, SymbolFlags.Namespace, ignoreErrors, location);
- if (!namespace || namespace === unknownSymbol || nodeIsMissing(right)) {
- return undefined;
- }
- symbol = getSymbol(getExportsOfSymbol(namespace), right.text, meaning);
- if (!symbol) {
- if (!ignoreErrors) {
- error(right, Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(namespace), declarationNameToString(right));
- }
- return undefined;
- }
- }
- else {
- Debug.fail("Unknown entity name kind.");
- }
- Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0, "Should never get an instantiated symbol here.");
- return symbol.flags & meaning ? symbol : resolveAlias(symbol);
- }
-
- function resolveExternalModuleName(location: Node, moduleReferenceExpression: Expression): Symbol {
- return resolveExternalModuleNameWorker(location, moduleReferenceExpression, Diagnostics.Cannot_find_module_0);
- }
-
- function resolveExternalModuleNameWorker(location: Node, moduleReferenceExpression: Expression, moduleNotFoundError: DiagnosticMessage): Symbol {
- if (moduleReferenceExpression.kind !== SyntaxKind.StringLiteral) {
- return;
- }
-
- const moduleReferenceLiteral = moduleReferenceExpression;
-
- // Module names are escaped in our symbol table. However, string literal values aren't.
- // Escape the name in the "require(...)" clause to ensure we find the right symbol.
- const moduleName = escapeIdentifier(moduleReferenceLiteral.text);
-
- if (moduleName === undefined) {
- return;
- }
-
- const isRelative = isExternalModuleNameRelative(moduleName);
- if (!isRelative) {
- const symbol = getSymbol(globals, '"' + moduleName + '"', SymbolFlags.ValueModule);
- if (symbol) {
- // merged symbol is module declaration symbol combined with all augmentations
- return getMergedSymbol(symbol);
- }
- }
-
- const resolvedModule = getResolvedModule(getSourceFileOfNode(location), moduleReferenceLiteral.text);
- const sourceFile = resolvedModule && host.getSourceFile(resolvedModule.resolvedFileName);
- if (sourceFile) {
- if (sourceFile.symbol) {
- // merged symbol is module declaration symbol combined with all augmentations
- return getMergedSymbol(sourceFile.symbol);
- }
- if (moduleNotFoundError) {
- // report errors only if it was requested
- error(moduleReferenceLiteral, Diagnostics.File_0_is_not_a_module, sourceFile.fileName);
- }
- return undefined;
- }
- if (moduleNotFoundError) {
- // report errors only if it was requested
- error(moduleReferenceLiteral, moduleNotFoundError, moduleName);
- }
- return undefined;
- }
-
- // An external module with an 'export =' declaration resolves to the target of the 'export =' declaration,
- // and an external module with no 'export =' declaration resolves to the module itself.
- function resolveExternalModuleSymbol(moduleSymbol: Symbol): Symbol {
- return moduleSymbol && getMergedSymbol(resolveSymbol(moduleSymbol.exports["export="])) || moduleSymbol;
- }
-
- // An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export ='
- // references a symbol that is at least declared as a module or a variable. The target of the 'export =' may
- // combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable).
- function resolveESModuleSymbol(moduleSymbol: Symbol, moduleReferenceExpression: Expression): Symbol {
- let symbol = resolveExternalModuleSymbol(moduleSymbol);
- if (symbol && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable))) {
- error(moduleReferenceExpression, Diagnostics.Module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct, symbolToString(moduleSymbol));
- symbol = undefined;
- }
- return symbol;
- }
-
- function hasExportAssignmentSymbol(moduleSymbol: Symbol): boolean {
- return moduleSymbol.exports["export="] !== undefined;
- }
-
- function getExportsOfModuleAsArray(moduleSymbol: Symbol): Symbol[] {
- return symbolsToArray(getExportsOfModule(moduleSymbol));
- }
-
- function getExportsOfSymbol(symbol: Symbol): SymbolTable {
- return symbol.flags & SymbolFlags.Module ? getExportsOfModule(symbol) : symbol.exports || emptySymbols;
- }
-
- function getExportsOfModule(moduleSymbol: Symbol): SymbolTable {
- const links = getSymbolLinks(moduleSymbol);
- return links.resolvedExports || (links.resolvedExports = getExportsForModule(moduleSymbol));
- }
-
- interface ExportCollisionTracker {
- specifierText: string;
- exportsWithDuplicate: ExportDeclaration[];
- }
-
- /**
- * Extends one symbol table with another while collecting information on name collisions for error message generation into the `lookupTable` argument
- * Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables
- */
- function extendExportSymbols(target: SymbolTable, source: SymbolTable, lookupTable?: Map, exportNode?: ExportDeclaration) {
- for (const id in source) {
- if (id !== "default" && !hasProperty(target, id)) {
- target[id] = source[id];
- if (lookupTable && exportNode) {
- lookupTable[id] = {
- specifierText: getTextOfNode(exportNode.moduleSpecifier)
- } as ExportCollisionTracker;
- }
- }
- else if (lookupTable && exportNode && id !== "default" && hasProperty(target, id) && resolveSymbol(target[id]) !== resolveSymbol(source[id])) {
- if (!lookupTable[id].exportsWithDuplicate) {
- lookupTable[id].exportsWithDuplicate = [exportNode];
- }
- else {
- lookupTable[id].exportsWithDuplicate.push(exportNode);
- }
- }
- }
- }
-
- function getExportsForModule(moduleSymbol: Symbol): SymbolTable {
- const visitedSymbols: Symbol[] = [];
- return visit(moduleSymbol) || moduleSymbol.exports;
-
- // The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example,
- // module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error.
- function visit(symbol: Symbol): SymbolTable {
- if (!(symbol && symbol.flags & SymbolFlags.HasExports && !contains(visitedSymbols, symbol))) {
- return;
- }
- visitedSymbols.push(symbol);
- const symbols = cloneSymbolTable(symbol.exports);
- // All export * declarations are collected in an __export symbol by the binder
- const exportStars = symbol.exports["__export"];
- if (exportStars) {
- const nestedSymbols: SymbolTable = {};
- const lookupTable: Map = {};
- for (const node of exportStars.declarations) {
- const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier);
- const exportedSymbols = visit(resolvedModule);
- extendExportSymbols(
- nestedSymbols,
- exportedSymbols,
- lookupTable,
- node as ExportDeclaration
- );
- }
- for (const id in lookupTable) {
- const { exportsWithDuplicate } = lookupTable[id];
- // It's not an error if the file with multiple `export *`s with duplicate names exports a member with that name itself
- if (id === "export=" || !(exportsWithDuplicate && exportsWithDuplicate.length) || hasProperty(symbols, id)) {
- continue;
- }
- for (const node of exportsWithDuplicate) {
- diagnostics.add(createDiagnosticForNode(
- node,
- Diagnostics.Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity,
- lookupTable[id].specifierText,
- id
- ));
- }
- }
- extendExportSymbols(symbols, nestedSymbols);
- }
- return symbols;
- }
- }
-
- function getMergedSymbol(symbol: Symbol): Symbol {
- let merged: Symbol;
- return symbol && symbol.mergeId && (merged = mergedSymbols[symbol.mergeId]) ? merged : symbol;
- }
-
- function getSymbolOfNode(node: Node): Symbol {
- return getMergedSymbol(node.symbol);
- }
-
- function getParentOfSymbol(symbol: Symbol): Symbol {
- return getMergedSymbol(symbol.parent);
- }
-
- function getExportSymbolOfValueSymbolIfExported(symbol: Symbol): Symbol {
- return symbol && (symbol.flags & SymbolFlags.ExportValue) !== 0
- ? getMergedSymbol(symbol.exportSymbol)
- : symbol;
- }
-
- function symbolIsValue(symbol: Symbol): boolean {
- // If it is an instantiated symbol, then it is a value if the symbol it is an
- // instantiation of is a value.
- if (symbol.flags & SymbolFlags.Instantiated) {
- return symbolIsValue(getSymbolLinks(symbol).target);
- }
-
- // If the symbol has the value flag, it is trivially a value.
- if (symbol.flags & SymbolFlags.Value) {
- return true;
- }
-
- // If it is an alias, then it is a value if the symbol it resolves to is a value.
- if (symbol.flags & SymbolFlags.Alias) {
- return (resolveAlias(symbol).flags & SymbolFlags.Value) !== 0;
- }
-
- return false;
- }
-
- function findConstructorDeclaration(node: ClassLikeDeclaration): ConstructorDeclaration {
- const members = node.members;
- for (const member of members) {
- if (member.kind === SyntaxKind.Constructor && nodeIsPresent((member).body)) {
- return member;
- }
- }
- }
-
- function createType(flags: TypeFlags): Type {
- const result = new Type(checker, flags);
- result.id = typeCount;
- typeCount++;
- return result;
- }
-
- function createIntrinsicType(kind: TypeFlags, intrinsicName: string): IntrinsicType {
- const type = createType(kind);
- type.intrinsicName = intrinsicName;
- return type;
- }
-
- function createObjectType(kind: TypeFlags, symbol?: Symbol): ObjectType {
- const type = createType(kind);
- type.symbol = symbol;
- return type;
- }
-
- // A reserved member name starts with two underscores, but the third character cannot be an underscore
- // or the @ symbol. A third underscore indicates an escaped form of an identifer that started
- // with at least two underscores. The @ character indicates that the name is denoted by a well known ES
- // Symbol instance.
- function isReservedMemberName(name: string) {
- return name.charCodeAt(0) === CharacterCodes._ &&
- name.charCodeAt(1) === CharacterCodes._ &&
- name.charCodeAt(2) !== CharacterCodes._ &&
- name.charCodeAt(2) !== CharacterCodes.at;
- }
-
- function getNamedMembers(members: SymbolTable): Symbol[] {
- let result: Symbol[];
- for (const id in members) {
- if (hasProperty(members, id)) {
- if (!isReservedMemberName(id)) {
- if (!result) result = [];
- const symbol = members[id];
- if (symbolIsValue(symbol)) {
- result.push(symbol);
- }
- }
- }
- }
- return result || emptyArray;
- }
-
- function setObjectTypeMembers(type: ObjectType, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo): ResolvedType {
- (type).members = members;
- (type).properties = getNamedMembers(members);
- (type).callSignatures = callSignatures;
- (type).constructSignatures = constructSignatures;
- if (stringIndexInfo) (type).stringIndexInfo = stringIndexInfo;
- if (numberIndexInfo) (type).numberIndexInfo = numberIndexInfo;
- return type;
- }
-
- function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo): ResolvedType {
- return setObjectTypeMembers(createObjectType(TypeFlags.Anonymous, symbol),
- members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
- }
-
- function forEachSymbolTableInScope(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T {
- let result: T;
- for (let location = enclosingDeclaration; location; location = location.parent) {
- // Locals of a source file are not in scope (because they get merged into the global symbol table)
- if (location.locals && !isGlobalSourceFile(location)) {
- if (result = callback(location.locals)) {
- return result;
- }
- }
- switch (location.kind) {
- case SyntaxKind.SourceFile:
- if (!isExternalOrCommonJsModule(location)) {
- break;
- }
- case SyntaxKind.ModuleDeclaration:
- if (result = callback(getSymbolOfNode(location).exports)) {
- return result;
- }
- break;
- }
- }
-
- return callback(globals);
- }
-
- function getQualifiedLeftMeaning(rightMeaning: SymbolFlags) {
- // If we are looking in value space, the parent meaning is value, other wise it is namespace
- return rightMeaning === SymbolFlags.Value ? SymbolFlags.Value : SymbolFlags.Namespace;
- }
-
- function getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] {
- function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable): Symbol[] {
- function canQualifySymbol(symbolFromSymbolTable: Symbol, meaning: SymbolFlags) {
- // If the symbol is equivalent and doesn't need further qualification, this symbol is accessible
- if (!needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning)) {
- return true;
- }
-
- // If symbol needs qualification, make sure that parent is accessible, if it is then this symbol is accessible too
- const accessibleParent = getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing);
- return !!accessibleParent;
- }
-
- function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol) {
- if (symbol === (resolvedAliasSymbol || symbolFromSymbolTable)) {
- // if the symbolFromSymbolTable is not external module (it could be if it was determined as ambient external module and would be in globals table)
- // and if symbolFromSymbolTable or alias resolution matches the symbol,
- // check the symbol can be qualified, it is only then this symbol is accessible
- return !forEach(symbolFromSymbolTable.declarations, hasExternalModuleSymbol) &&
- canQualifySymbol(symbolFromSymbolTable, meaning);
- }
- }
-
- // If symbol is directly available by its name in the symbol table
- if (isAccessible(lookUp(symbols, symbol.name))) {
- return [symbol];
- }
-
- // Check if symbol is any of the alias
- return forEachValue(symbols, symbolFromSymbolTable => {
- if (symbolFromSymbolTable.flags & SymbolFlags.Alias
- && symbolFromSymbolTable.name !== "export="
- && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) {
- if (!useOnlyExternalAliasing || // We can use any type of alias to get the name
- // Is this external alias, then use it to name
- ts.forEach(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration)) {
-
- const resolvedImportedSymbol = resolveAlias(symbolFromSymbolTable);
- if (isAccessible(symbolFromSymbolTable, resolveAlias(symbolFromSymbolTable))) {
- return [symbolFromSymbolTable];
- }
-
- // Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain
- // but only if the symbolFromSymbolTable can be qualified
- const accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTable(resolvedImportedSymbol.exports) : undefined;
- if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) {
- return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports);
- }
- }
- }
- });
- }
-
- if (symbol) {
- if (!(isPropertyOrMethodDeclarationSymbol(symbol))) {
- return forEachSymbolTableInScope(enclosingDeclaration, getAccessibleSymbolChainFromSymbolTable);
- }
- }
- }
-
- function needsQualification(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) {
- let qualify = false;
- forEachSymbolTableInScope(enclosingDeclaration, symbolTable => {
- // If symbol of this name is not available in the symbol table we are ok
- if (!hasProperty(symbolTable, symbol.name)) {
- // Continue to the next symbol table
- return false;
- }
- // If the symbol with this name is present it should refer to the symbol
- let symbolFromSymbolTable = symbolTable[symbol.name];
- if (symbolFromSymbolTable === symbol) {
- // No need to qualify
- return true;
- }
-
- // Qualify if the symbol from symbol table has same meaning as expected
- symbolFromSymbolTable = (symbolFromSymbolTable.flags & SymbolFlags.Alias && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) ? resolveAlias(symbolFromSymbolTable) : symbolFromSymbolTable;
- if (symbolFromSymbolTable.flags & meaning) {
- qualify = true;
- return true;
- }
-
- // Continue to the next symbol table
- return false;
- });
-
- return qualify;
- }
-
- function isPropertyOrMethodDeclarationSymbol(symbol: Symbol) {
- if (symbol.declarations && symbol.declarations.length) {
- for (const declaration of symbol.declarations) {
- switch (declaration.kind) {
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- continue;
- default:
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessibilityResult {
- if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) {
- const initialSymbol = symbol;
- let meaningToLook = meaning;
- while (symbol) {
- // Symbol is accessible if it by itself is accessible
- const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook, /*useOnlyExternalAliasing*/ false);
- if (accessibleSymbolChain) {
- const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0]);
- if (!hasAccessibleDeclarations) {
- return {
- accessibility: SymbolAccessibility.NotAccessible,
- errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
- errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined,
- };
- }
- return hasAccessibleDeclarations;
- }
-
- // If we haven't got the accessible symbol, it doesn't mean the symbol is actually inaccessible.
- // It could be a qualified symbol and hence verify the path
- // e.g.:
- // module m {
- // export class c {
- // }
- // }
- // const x: typeof m.c
- // In the above example when we start with checking if typeof m.c symbol is accessible,
- // we are going to see if c can be accessed in scope directly.
- // But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible
- // It is accessible if the parent m is accessible because then m.c can be accessed through qualification
- meaningToLook = getQualifiedLeftMeaning(meaning);
- symbol = getParentOfSymbol(symbol);
- }
-
- // This could be a symbol that is not exported in the external module
- // or it could be a symbol from different external module that is not aliased and hence cannot be named
- const symbolExternalModule = forEach(initialSymbol.declarations, getExternalModuleContainer);
- if (symbolExternalModule) {
- const enclosingExternalModule = getExternalModuleContainer(enclosingDeclaration);
- if (symbolExternalModule !== enclosingExternalModule) {
- // name from different external module that is not visible
- return {
- accessibility: SymbolAccessibility.CannotBeNamed,
- errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
- errorModuleName: symbolToString(symbolExternalModule)
- };
- }
- }
-
- // Just a local name that is not accessible
- return {
- accessibility: SymbolAccessibility.NotAccessible,
- errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
- };
- }
-
- return { accessibility: SymbolAccessibility.Accessible };
-
- function getExternalModuleContainer(declaration: Node) {
- for (; declaration; declaration = declaration.parent) {
- if (hasExternalModuleSymbol(declaration)) {
- return getSymbolOfNode(declaration);
- }
- }
- }
- }
-
- function hasExternalModuleSymbol(declaration: Node) {
- return isAmbientModule(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration));
- }
-
- function hasVisibleDeclarations(symbol: Symbol): SymbolVisibilityResult {
- let aliasesToMakeVisible: AnyImportSyntax[];
- if (forEach(symbol.declarations, declaration => !getIsDeclarationVisible(declaration))) {
- return undefined;
- }
- return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible };
-
- function getIsDeclarationVisible(declaration: Declaration) {
- if (!isDeclarationVisible(declaration)) {
- // Mark the unexported alias as visible if its parent is visible
- // because these kind of aliases can be used to name types in declaration file
-
- const anyImportSyntax = getAnyImportSyntax(declaration);
- if (anyImportSyntax &&
- !(getModifierFlags(anyImportSyntax) & ModifierFlags.Export) && // import clause without export
- isDeclarationVisible(anyImportSyntax.parent)) {
- getNodeLinks(declaration).isVisible = true;
- if (aliasesToMakeVisible) {
- if (!contains(aliasesToMakeVisible, anyImportSyntax)) {
- aliasesToMakeVisible.push(anyImportSyntax);
- }
- }
- else {
- aliasesToMakeVisible = [anyImportSyntax];
- }
- return true;
- }
-
- // Declaration is not visible
- return false;
- }
-
- return true;
- }
- }
-
- function isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult {
- // get symbol of the first identifier of the entityName
- let meaning: SymbolFlags;
- if (entityName.parent.kind === SyntaxKind.TypeQuery || isExpressionWithTypeArgumentsInClassExtendsClause(entityName.parent)) {
- // Typeof value
- meaning = SymbolFlags.Value | SymbolFlags.ExportValue;
- }
- else if (entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccessExpression ||
- entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration) {
- // Left identifier from type reference or TypeAlias
- // Entity name of the import declaration
- meaning = SymbolFlags.Namespace;
- }
- else {
- // Type Reference or TypeAlias entity = Identifier
- meaning = SymbolFlags.Type;
- }
-
- const firstIdentifier = getFirstIdentifier(entityName);
- const symbol = resolveName(enclosingDeclaration, (firstIdentifier).text, meaning, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined);
-
- // Verify if the symbol is accessible
- return (symbol && hasVisibleDeclarations(symbol)) || {
- accessibility: SymbolAccessibility.NotAccessible,
- errorSymbolName: getTextOfNode(firstIdentifier),
- errorNode: firstIdentifier
- };
- }
-
- function writeKeyword(writer: SymbolWriter, kind: SyntaxKind) {
- writer.writeKeyword(tokenToString(kind));
- }
-
- function writePunctuation(writer: SymbolWriter, kind: SyntaxKind) {
- writer.writePunctuation(tokenToString(kind));
- }
-
- function writeSpace(writer: SymbolWriter) {
- writer.writeSpace(" ");
- }
-
- function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string {
- const writer = getSingleLineStringWriter();
- getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning);
- const result = writer.string();
- releaseStringWriter(writer);
-
- return result;
- }
-
- function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string {
- const writer = getSingleLineStringWriter();
- getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags, kind);
- const result = writer.string();
- releaseStringWriter(writer);
-
- return result;
- }
-
- function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string {
- const writer = getSingleLineStringWriter();
- getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
- let result = writer.string();
- releaseStringWriter(writer);
-
- const maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100;
- if (maxLength && result.length >= maxLength) {
- result = result.substr(0, maxLength - "...".length) + "...";
- }
- return result;
- }
-
- function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Declaration, flags?: TypeFormatFlags): string {
- const writer = getSingleLineStringWriter();
- getSymbolDisplayBuilder().buildTypePredicateDisplay(typePredicate, writer, enclosingDeclaration, flags);
- const result = writer.string();
- releaseStringWriter(writer);
-
- return result;
- }
-
- function visibilityToString(flags: ModifierFlags) {
- if (flags === ModifierFlags.Private) {
- return "private";
- }
- if (flags === ModifierFlags.Protected) {
- return "protected";
- }
- return "public";
- }
-
- function getTypeAliasForTypeLiteral(type: Type): Symbol {
- if (type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral) {
- let node = type.symbol.declarations[0].parent;
- while (node.kind === SyntaxKind.ParenthesizedType) {
- node = node.parent;
- }
- if (node.kind === SyntaxKind.TypeAliasDeclaration) {
- return getSymbolOfNode(node);
- }
- }
- return undefined;
- }
-
- function isTopLevelInExternalModuleAugmentation(node: Node): boolean {
- return node && node.parent &&
- node.parent.kind === SyntaxKind.ModuleBlock &&
- isExternalModuleAugmentation(node.parent.parent);
- }
-
- function getSymbolDisplayBuilder(): SymbolDisplayBuilder {
-
- function getNameOfSymbol(symbol: Symbol): string {
- if (symbol.declarations && symbol.declarations.length) {
- const declaration = symbol.declarations[0];
- if (declaration.name) {
- return declarationNameToString(declaration.name);
- }
- switch (declaration.kind) {
- case SyntaxKind.ClassExpression:
- return "(Anonymous class)";
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.ArrowFunction:
- return "(Anonymous function)";
- }
- }
- return symbol.name;
- }
-
- /**
- * Writes only the name of the symbol out to the writer. Uses the original source text
- * for the name of the symbol if it is available to match how the user inputted the name.
- */
- function appendSymbolNameOnly(symbol: Symbol, writer: SymbolWriter): void {
- writer.writeSymbol(getNameOfSymbol(symbol), symbol);
- }
-
- /**
- * Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope
- * Meaning needs to be specified if the enclosing declaration is given
- */
- function buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags, typeFlags?: TypeFormatFlags): void {
- let parentSymbol: Symbol;
- function appendParentTypeArgumentsAndSymbolName(symbol: Symbol): void {
- if (parentSymbol) {
- // Write type arguments of instantiated class/interface here
- if (flags & SymbolFormatFlags.WriteTypeParametersOrArguments) {
- if (symbol.flags & SymbolFlags.Instantiated) {
- buildDisplayForTypeArgumentsAndDelimiters(getTypeParametersOfClassOrInterface(parentSymbol),
- (symbol).mapper, writer, enclosingDeclaration);
- }
- else {
- buildTypeParameterDisplayFromSymbol(parentSymbol, writer, enclosingDeclaration);
- }
- }
- writePunctuation(writer, SyntaxKind.DotToken);
- }
- parentSymbol = symbol;
- appendSymbolNameOnly(symbol, writer);
- }
-
- // const the writer know we just wrote out a symbol. The declaration emitter writer uses
- // this to determine if an import it has previously seen (and not written out) needs
- // to be written to the file once the walk of the tree is complete.
- //
- // NOTE(cyrusn): This approach feels somewhat unfortunate. A simple pass over the tree
- // up front (for example, during checking) could determine if we need to emit the imports
- // and we could then access that data during declaration emit.
- writer.trackSymbol(symbol, enclosingDeclaration, meaning);
- function walkSymbol(symbol: Symbol, meaning: SymbolFlags): void {
- if (symbol) {
- const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, !!(flags & SymbolFormatFlags.UseOnlyExternalAliasing));
-
- if (!accessibleSymbolChain ||
- needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
-
- // Go up and add our parent.
- walkSymbol(
- getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol),
- getQualifiedLeftMeaning(meaning));
- }
-
- if (accessibleSymbolChain) {
- for (const accessibleSymbol of accessibleSymbolChain) {
- appendParentTypeArgumentsAndSymbolName(accessibleSymbol);
- }
- }
- else {
- // If we didn't find accessible symbol chain for this symbol, break if this is external module
- if (!parentSymbol && ts.forEach(symbol.declarations, hasExternalModuleSymbol)) {
- return;
- }
-
- // if this is anonymous type break
- if (symbol.flags & SymbolFlags.TypeLiteral || symbol.flags & SymbolFlags.ObjectLiteral) {
- return;
- }
-
- appendParentTypeArgumentsAndSymbolName(symbol);
- }
- }
- }
-
- // Get qualified name if the symbol is not a type parameter
- // and there is an enclosing declaration or we specifically
- // asked for it
- const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter;
- const typeFormatFlag = TypeFormatFlags.UseFullyQualifiedType & typeFlags;
- if (!isTypeParameter && (enclosingDeclaration || typeFormatFlag)) {
- walkSymbol(symbol, meaning);
- return;
- }
-
- return appendParentTypeArgumentsAndSymbolName(symbol);
- }
-
- function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]) {
- const globalFlagsToPass = globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike;
- let inObjectTypeLiteral = false;
- return writeType(type, globalFlags);
-
- function writeType(type: Type, flags: TypeFormatFlags) {
- // Write undefined/null type as any
- if (type.flags & TypeFlags.Intrinsic) {
- // Special handling for unknown / resolving types, they should show up as any and not unknown or __resolving
- writer.writeKeyword(!(globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike) && isTypeAny(type)
- ? "any"
- : (type).intrinsicName);
- }
- else if (type.flags & TypeFlags.ThisType) {
- if (inObjectTypeLiteral) {
- writer.reportInaccessibleThisError();
- }
- writer.writeKeyword("this");
- }
- else if (type.flags & TypeFlags.Reference) {
- writeTypeReference(type, flags);
- }
- else if (type.flags & (TypeFlags.Class | TypeFlags.Interface | TypeFlags.Enum | TypeFlags.TypeParameter)) {
- // The specified symbol flags need to be reinterpreted as type flags
- buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
- }
- else if (type.flags & TypeFlags.Tuple) {
- writeTupleType(type);
- }
- else if (type.flags & TypeFlags.UnionOrIntersection) {
- writeUnionOrIntersectionType(type, flags);
- }
- else if (type.flags & TypeFlags.Anonymous) {
- writeAnonymousType(type, flags);
- }
- else if (type.flags & TypeFlags.StringLiteral) {
- writer.writeStringLiteral(`"${escapeString((type).text)}"`);
- }
- else {
- // Should never get here
- // { ... }
- writePunctuation(writer, SyntaxKind.OpenBraceToken);
- writeSpace(writer);
- writePunctuation(writer, SyntaxKind.DotDotDotToken);
- writeSpace(writer);
- writePunctuation(writer, SyntaxKind.CloseBraceToken);
- }
- }
-
- function writeTypeList(types: Type[], delimiter: SyntaxKind) {
- for (let i = 0; i < types.length; i++) {
- if (i > 0) {
- if (delimiter !== SyntaxKind.CommaToken) {
- writeSpace(writer);
- }
- writePunctuation(writer, delimiter);
- writeSpace(writer);
- }
- writeType(types[i], delimiter === SyntaxKind.CommaToken ? TypeFormatFlags.None : TypeFormatFlags.InElementType);
- }
- }
-
- function writeSymbolTypeReference(symbol: Symbol, typeArguments: Type[], pos: number, end: number, flags: TypeFormatFlags) {
- // Unnamed function expressions and arrow functions have reserved names that we don't want to display
- if (symbol.flags & SymbolFlags.Class || !isReservedMemberName(symbol.name)) {
- buildSymbolDisplay(symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
- }
- if (pos < end) {
- writePunctuation(writer, SyntaxKind.LessThanToken);
- writeType(typeArguments[pos], TypeFormatFlags.None);
- pos++;
- while (pos < end) {
- writePunctuation(writer, SyntaxKind.CommaToken);
- writeSpace(writer);
- writeType(typeArguments[pos], TypeFormatFlags.None);
- pos++;
- }
- writePunctuation(writer, SyntaxKind.GreaterThanToken);
- }
- }
-
- function writeTypeReference(type: TypeReference, flags: TypeFormatFlags) {
- const typeArguments = type.typeArguments || emptyArray;
- if (type.target === globalArrayType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) {
- writeType(typeArguments[0], TypeFormatFlags.InElementType);
- writePunctuation(writer, SyntaxKind.OpenBracketToken);
- writePunctuation(writer, SyntaxKind.CloseBracketToken);
- }
- else {
- // Write the type reference in the format f.g.C where A and B are type arguments
- // for outer type parameters, and f and g are the respective declaring containers of those
- // type parameters.
- const outerTypeParameters = type.target.outerTypeParameters;
- let i = 0;
- if (outerTypeParameters) {
- const length = outerTypeParameters.length;
- while (i < length) {
- // Find group of type arguments for type parameters with the same declaring container.
- const start = i;
- const parent = getParentSymbolOfTypeParameter(outerTypeParameters[i]);
- do {
- i++;
- } while (i < length && getParentSymbolOfTypeParameter(outerTypeParameters[i]) === parent);
- // When type parameters are their own type arguments for the whole group (i.e. we have
- // the default outer type arguments), we don't show the group.
- if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
- writeSymbolTypeReference(parent, typeArguments, start, i, flags);
- writePunctuation(writer, SyntaxKind.DotToken);
- }
- }
- }
- const typeParameterCount = (type.target.typeParameters || emptyArray).length;
- writeSymbolTypeReference(type.symbol, typeArguments, i, typeParameterCount, flags);
- }
- }
-
- function writeTupleType(type: TupleType) {
- writePunctuation(writer, SyntaxKind.OpenBracketToken);
- writeTypeList(type.elementTypes, SyntaxKind.CommaToken);
- writePunctuation(writer, SyntaxKind.CloseBracketToken);
- }
-
- function writeUnionOrIntersectionType(type: UnionOrIntersectionType, flags: TypeFormatFlags) {
- if (flags & TypeFormatFlags.InElementType) {
- writePunctuation(writer, SyntaxKind.OpenParenToken);
- }
- writeTypeList(type.types, type.flags & TypeFlags.Union ? SyntaxKind.BarToken : SyntaxKind.AmpersandToken);
- if (flags & TypeFormatFlags.InElementType) {
- writePunctuation(writer, SyntaxKind.CloseParenToken);
- }
- }
-
- function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) {
- const symbol = type.symbol;
- if (symbol) {
- // Always use 'typeof T' for type of class, enum, and module objects
- if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
- writeTypeofSymbol(type, flags);
- }
- else if (shouldWriteTypeOfFunctionSymbol()) {
- writeTypeofSymbol(type, flags);
- }
- else if (contains(symbolStack, symbol)) {
- // If type is an anonymous type literal in a type alias declaration, use type alias name
- const typeAlias = getTypeAliasForTypeLiteral(type);
- if (typeAlias) {
- // The specified symbol flags need to be reinterpreted as type flags
- buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
- }
- else {
- // Recursive usage, use any
- writeKeyword(writer, SyntaxKind.AnyKeyword);
- }
- }
- else {
- // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead
- // of types allows us to catch circular references to instantiations of the same anonymous type
- if (!symbolStack) {
- symbolStack = [];
- }
- symbolStack.push(symbol);
- writeLiteralType(type, flags);
- symbolStack.pop();
- }
- }
- else {
- // Anonymous types with no symbol are never circular
- writeLiteralType(type, flags);
- }
-
- function shouldWriteTypeOfFunctionSymbol() {
- const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method && // typeof static method
- forEach(symbol.declarations, declaration => getModifierFlags(declaration) & ModifierFlags.Static));
- const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) &&
- (symbol.parent || // is exported function symbol
- forEach(symbol.declarations, declaration =>
- declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock));
- if (isStaticMethodSymbol || isNonLocalFunctionSymbol) {
- // typeof is allowed only for static/non local functions
- return !!(flags & TypeFormatFlags.UseTypeOfFunction) || // use typeof if format flags specify it
- (contains(symbolStack, symbol)); // it is type of the symbol uses itself recursively
- }
- }
- }
-
- function writeTypeofSymbol(type: ObjectType, typeFormatFlags?: TypeFormatFlags) {
- writeKeyword(writer, SyntaxKind.TypeOfKeyword);
- writeSpace(writer);
- buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value, SymbolFormatFlags.None, typeFormatFlags);
- }
-
- function writeIndexSignature(info: IndexInfo, keyword: SyntaxKind) {
- if (info) {
- if (info.isReadonly) {
- writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
- writeSpace(writer);
- }
- writePunctuation(writer, SyntaxKind.OpenBracketToken);
- writer.writeParameter(info.declaration ? declarationNameToString(info.declaration.parameters[0].name) : "x");
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
- writeKeyword(writer, keyword);
- writePunctuation(writer, SyntaxKind.CloseBracketToken);
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
- writeType(info.type, TypeFormatFlags.None);
- writePunctuation(writer, SyntaxKind.SemicolonToken);
- writer.writeLine();
- }
- }
-
- function writePropertyWithModifiers(prop: Symbol) {
- if (isReadonlySymbol(prop)) {
- writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
- writeSpace(writer);
- }
- buildSymbolDisplay(prop, writer);
- if (prop.flags & SymbolFlags.Optional) {
- writePunctuation(writer, SyntaxKind.QuestionToken);
- }
- }
-
- function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
- const resolved = resolveStructuredTypeMembers(type);
- if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
- if (!resolved.callSignatures.length && !resolved.constructSignatures.length) {
- writePunctuation(writer, SyntaxKind.OpenBraceToken);
- writePunctuation(writer, SyntaxKind.CloseBraceToken);
- return;
- }
-
- if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
- if (flags & TypeFormatFlags.InElementType) {
- writePunctuation(writer, SyntaxKind.OpenParenToken);
- }
- buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ undefined, symbolStack);
- if (flags & TypeFormatFlags.InElementType) {
- writePunctuation(writer, SyntaxKind.CloseParenToken);
- }
- return;
- }
- if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
- if (flags & TypeFormatFlags.InElementType) {
- writePunctuation(writer, SyntaxKind.OpenParenToken);
- }
- writeKeyword(writer, SyntaxKind.NewKeyword);
- writeSpace(writer);
- buildSignatureDisplay(resolved.constructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ undefined, symbolStack);
- if (flags & TypeFormatFlags.InElementType) {
- writePunctuation(writer, SyntaxKind.CloseParenToken);
- }
- return;
- }
- }
-
- const saveInObjectTypeLiteral = inObjectTypeLiteral;
- inObjectTypeLiteral = true;
- writePunctuation(writer, SyntaxKind.OpenBraceToken);
- writer.writeLine();
- writer.increaseIndent();
- for (const signature of resolved.callSignatures) {
- buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ undefined, symbolStack);
- writePunctuation(writer, SyntaxKind.SemicolonToken);
- writer.writeLine();
- }
- for (const signature of resolved.constructSignatures) {
- buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, SignatureKind.Construct, symbolStack);
- writePunctuation(writer, SyntaxKind.SemicolonToken);
- writer.writeLine();
- }
- writeIndexSignature(resolved.stringIndexInfo, SyntaxKind.StringKeyword);
- writeIndexSignature(resolved.numberIndexInfo, SyntaxKind.NumberKeyword);
- for (const p of resolved.properties) {
- const t = getTypeOfSymbol(p);
- if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(t).length) {
- const signatures = getSignaturesOfType(t, SignatureKind.Call);
- for (const signature of signatures) {
- writePropertyWithModifiers(p);
- buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ undefined, symbolStack);
- writePunctuation(writer, SyntaxKind.SemicolonToken);
- writer.writeLine();
- }
- }
- else {
- writePropertyWithModifiers(p);
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
- writeType(t, TypeFormatFlags.None);
- writePunctuation(writer, SyntaxKind.SemicolonToken);
- writer.writeLine();
- }
- }
- writer.decreaseIndent();
- writePunctuation(writer, SyntaxKind.CloseBraceToken);
- inObjectTypeLiteral = saveInObjectTypeLiteral;
- }
- }
-
- function buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) {
- const targetSymbol = getTargetSymbol(symbol);
- if (targetSymbol.flags & SymbolFlags.Class || targetSymbol.flags & SymbolFlags.Interface || targetSymbol.flags & SymbolFlags.TypeAlias) {
- buildDisplayForTypeParametersAndDelimiters(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol), writer, enclosingDeclaration, flags);
- }
- }
-
- function buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
- appendSymbolNameOnly(tp.symbol, writer);
- const constraint = getConstraintOfTypeParameter(tp);
- if (constraint) {
- writeSpace(writer);
- writeKeyword(writer, SyntaxKind.ExtendsKeyword);
- writeSpace(writer);
- buildTypeDisplay(constraint, writer, enclosingDeclaration, flags, symbolStack);
- }
- }
-
- function buildParameterDisplay(p: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
- const parameterNode = p.valueDeclaration;
- if (isRestParameter(parameterNode)) {
- writePunctuation(writer, SyntaxKind.DotDotDotToken);
- }
- if (isBindingPattern(parameterNode.name)) {
- buildBindingPatternDisplay(parameterNode.name, writer, enclosingDeclaration, flags, symbolStack);
- }
- else {
- appendSymbolNameOnly(p, writer);
- }
- if (isOptionalParameter(parameterNode)) {
- writePunctuation(writer, SyntaxKind.QuestionToken);
- }
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
-
- buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, symbolStack);
- }
-
- function buildBindingPatternDisplay(bindingPattern: BindingPattern, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
- // We have to explicitly emit square bracket and bracket because these tokens are not stored inside the node.
- if (bindingPattern.kind === SyntaxKind.ObjectBindingPattern) {
- writePunctuation(writer, SyntaxKind.OpenBraceToken);
- buildDisplayForCommaSeparatedList(bindingPattern.elements, writer, e => buildBindingElementDisplay(e, writer, enclosingDeclaration, flags, symbolStack));
- writePunctuation(writer, SyntaxKind.CloseBraceToken);
- }
- else if (bindingPattern.kind === SyntaxKind.ArrayBindingPattern) {
- writePunctuation(writer, SyntaxKind.OpenBracketToken);
- const elements = bindingPattern.elements;
- buildDisplayForCommaSeparatedList(elements, writer, e => buildBindingElementDisplay(e, writer, enclosingDeclaration, flags, symbolStack));
- if (elements && elements.hasTrailingComma) {
- writePunctuation(writer, SyntaxKind.CommaToken);
- }
- writePunctuation(writer, SyntaxKind.CloseBracketToken);
- }
- }
-
- function buildBindingElementDisplay(bindingElement: BindingElement, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
- if (bindingElement.kind === SyntaxKind.OmittedExpression) {
- return;
- }
- Debug.assert(bindingElement.kind === SyntaxKind.BindingElement);
- if (bindingElement.propertyName) {
- writer.writeSymbol(getTextOfNode(bindingElement.propertyName), bindingElement.symbol);
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
- }
- if (isBindingPattern(bindingElement.name)) {
- buildBindingPatternDisplay(bindingElement.name, writer, enclosingDeclaration, flags, symbolStack);
- }
- else {
- if (bindingElement.dotDotDotToken) {
- writePunctuation(writer, SyntaxKind.DotDotDotToken);
- }
- appendSymbolNameOnly(bindingElement.symbol, writer);
- }
- }
-
- function buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
- if (typeParameters && typeParameters.length) {
- writePunctuation(writer, SyntaxKind.LessThanToken);
- buildDisplayForCommaSeparatedList(typeParameters, writer, p => buildTypeParameterDisplay(p, writer, enclosingDeclaration, flags, symbolStack));
- writePunctuation(writer, SyntaxKind.GreaterThanToken);
- }
- }
-
- function buildDisplayForCommaSeparatedList(list: T[], writer: SymbolWriter, action: (item: T) => void) {
- for (let i = 0; i < list.length; i++) {
- if (i > 0) {
- writePunctuation(writer, SyntaxKind.CommaToken);
- writeSpace(writer);
- }
- action(list[i]);
- }
- }
-
- function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
- if (typeParameters && typeParameters.length) {
- writePunctuation(writer, SyntaxKind.LessThanToken);
- for (let i = 0; i < typeParameters.length; i++) {
- if (i > 0) {
- writePunctuation(writer, SyntaxKind.CommaToken);
- writeSpace(writer);
- }
- buildTypeDisplay(mapper(typeParameters[i]), writer, enclosingDeclaration, TypeFormatFlags.None);
- }
- writePunctuation(writer, SyntaxKind.GreaterThanToken);
- }
- }
-
- function buildDisplayForParametersAndDelimiters(thisType: Type, parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
- writePunctuation(writer, SyntaxKind.OpenParenToken);
- if (thisType) {
- writeKeyword(writer, SyntaxKind.ThisKeyword);
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
- buildTypeDisplay(thisType, writer, enclosingDeclaration, flags, symbolStack);
- }
- for (let i = 0; i < parameters.length; i++) {
- if (i > 0 || thisType) {
- writePunctuation(writer, SyntaxKind.CommaToken);
- writeSpace(writer);
- }
- buildParameterDisplay(parameters[i], writer, enclosingDeclaration, flags, symbolStack);
- }
- writePunctuation(writer, SyntaxKind.CloseParenToken);
- }
-
- function buildTypePredicateDisplay(predicate: TypePredicate, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]): void {
- if (isIdentifierTypePredicate(predicate)) {
- writer.writeParameter(predicate.parameterName);
- }
- else {
- writeKeyword(writer, SyntaxKind.ThisKeyword);
- }
- writeSpace(writer);
- writeKeyword(writer, SyntaxKind.IsKeyword);
- writeSpace(writer);
- buildTypeDisplay(predicate.type, writer, enclosingDeclaration, flags, symbolStack);
- }
-
- function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
- if (flags & TypeFormatFlags.WriteArrowStyleSignature) {
- writeSpace(writer);
- writePunctuation(writer, SyntaxKind.EqualsGreaterThanToken);
- }
- else {
- writePunctuation(writer, SyntaxKind.ColonToken);
- }
- writeSpace(writer);
-
- if (signature.typePredicate) {
- buildTypePredicateDisplay(signature.typePredicate, writer, enclosingDeclaration, flags, symbolStack);
- }
- else {
- const returnType = getReturnTypeOfSignature(signature);
- buildTypeDisplay(returnType, writer, enclosingDeclaration, flags, symbolStack);
- }
- }
-
- function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind, symbolStack?: Symbol[]) {
- if (kind === SignatureKind.Construct) {
- writeKeyword(writer, SyntaxKind.NewKeyword);
- writeSpace(writer);
- }
-
- if (signature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature)) {
- // Instantiated signature, write type arguments instead
- // This is achieved by passing in the mapper separately
- buildDisplayForTypeArgumentsAndDelimiters(signature.target.typeParameters, signature.mapper, writer, enclosingDeclaration);
- }
- else {
- buildDisplayForTypeParametersAndDelimiters(signature.typeParameters, writer, enclosingDeclaration, flags, symbolStack);
- }
-
- buildDisplayForParametersAndDelimiters(signature.thisType, signature.parameters, writer, enclosingDeclaration, flags, symbolStack);
-
- buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, symbolStack);
- }
-
- return _displayBuilder || (_displayBuilder = {
- buildSymbolDisplay,
- buildTypeDisplay,
- buildTypeParameterDisplay,
- buildTypePredicateDisplay,
- buildParameterDisplay,
- buildDisplayForParametersAndDelimiters,
- buildDisplayForTypeParametersAndDelimiters,
- buildTypeParameterDisplayFromSymbol,
- buildSignatureDisplay,
- buildReturnTypeDisplay
- });
- }
-
- function isDeclarationVisible(node: Declaration): boolean {
- if (node) {
- const links = getNodeLinks(node);
- if (links.isVisible === undefined) {
- links.isVisible = !!determineIfDeclarationIsVisible();
- }
- return links.isVisible;
- }
-
- return false;
-
- function determineIfDeclarationIsVisible() {
- switch (node.kind) {
- case SyntaxKind.BindingElement:
- return isDeclarationVisible(node.parent.parent);
- case SyntaxKind.VariableDeclaration:
- if (isBindingPattern(node.name) &&
- !(node.name).elements.length) {
- // If the binding pattern is empty, this variable declaration is not visible
- return false;
- }
- // Otherwise fall through
- case SyntaxKind.ModuleDeclaration:
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.InterfaceDeclaration:
- case SyntaxKind.TypeAliasDeclaration:
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.EnumDeclaration:
- case SyntaxKind.ImportEqualsDeclaration:
- // external module augmentation is always visible
- if (isExternalModuleAugmentation(node)) {
- return true;
- }
- const parent = getDeclarationContainer(node);
- // If the node is not exported or it is not ambient module element (except import declaration)
- if (!(getCombinedModifierFlags(node) & ModifierFlags.Export) &&
- !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && isInAmbientContext(parent))) {
- return isGlobalSourceFile(parent);
- }
- // Exported members/ambient module elements (exception import declaration) are visible if parent is visible
- return isDeclarationVisible(parent);
-
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.PropertySignature:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- if (getModifierFlags(node) & (ModifierFlags.Private | ModifierFlags.Protected)) {
- // Private/protected properties/methods are not visible
- return false;
- }
- // Public properties/methods are visible if its parents are visible, so const it fall into next case statement
-
- case SyntaxKind.Constructor:
- case SyntaxKind.ConstructSignature:
- case SyntaxKind.CallSignature:
- case SyntaxKind.IndexSignature:
- case SyntaxKind.Parameter:
- case SyntaxKind.ModuleBlock:
- case SyntaxKind.FunctionType:
- case SyntaxKind.ConstructorType:
- case SyntaxKind.TypeLiteral:
- case SyntaxKind.TypeReference:
- case SyntaxKind.ArrayType:
- case SyntaxKind.TupleType:
- case SyntaxKind.UnionType:
- case SyntaxKind.IntersectionType:
- case SyntaxKind.ParenthesizedType:
- return isDeclarationVisible(node.parent);
-
- // Default binding, import specifier and namespace import is visible
- // only on demand so by default it is not visible
- case SyntaxKind.ImportClause:
- case SyntaxKind.NamespaceImport:
- case SyntaxKind.ImportSpecifier:
- return false;
-
- // Type parameters are always visible
- case SyntaxKind.TypeParameter:
- // Source file is always visible
- case SyntaxKind.SourceFile:
- return true;
-
- // Export assignments do not create name bindings outside the module
- case SyntaxKind.ExportAssignment:
- return false;
-
- default:
- return false;
- }
- }
- }
-
- function collectLinkedAliases(node: Identifier): Node[] {
- let exportSymbol: Symbol;
- if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) {
- exportSymbol = resolveName(node.parent, node.text, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, Diagnostics.Cannot_find_name_0, node);
- }
- else if (node.parent.kind === SyntaxKind.ExportSpecifier) {
- const exportSpecifier = node.parent;
- exportSymbol = (exportSpecifier.parent.parent).moduleSpecifier ?
- getExternalModuleMember(exportSpecifier.parent.parent, exportSpecifier) :
- resolveEntityName(exportSpecifier.propertyName || exportSpecifier.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias);
- }
- const result: Node[] = [];
- if (exportSymbol) {
- buildVisibleNodeList(exportSymbol.declarations);
- }
- return result;
-
- function buildVisibleNodeList(declarations: Declaration[]) {
- forEach(declarations, declaration => {
- getNodeLinks(declaration).isVisible = true;
- const resultNode = getAnyImportSyntax(declaration) || declaration;
- if (!contains(result, resultNode)) {
- result.push(resultNode);
- }
-
- if (isInternalModuleImportEqualsDeclaration(declaration)) {
- // Add the referenced top container visible
- const internalModuleReference = (declaration).moduleReference;
- const firstIdentifier = getFirstIdentifier(internalModuleReference);
- const importSymbol = resolveName(declaration, firstIdentifier.text, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace,
- Diagnostics.Cannot_find_name_0, firstIdentifier);
- if (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.
- * In this case, the result values of the existing entry and all entries pushed after it are changed to false,
- * and the value false is returned. Otherwise, the new entry is just pushed onto the stack, and true is returned.
- * In order to see if the same query has already been done before, the target object and the propertyName both
- * must match the one passed in.
- *
- * @param target The symbol, type, or signature whose type is being queried
- * @param propertyName The property name that should be used to query the target for its type
- */
- function pushTypeResolution(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): boolean {
- const resolutionCycleStartIndex = findResolutionCycleStartIndex(target, propertyName);
- if (resolutionCycleStartIndex >= 0) {
- // A cycle was found
- const { length } = resolutionTargets;
- for (let i = resolutionCycleStartIndex; i < length; i++) {
- resolutionResults[i] = false;
- }
- return false;
- }
- resolutionTargets.push(target);
- resolutionResults.push(/*items*/ true);
- resolutionPropertyNames.push(propertyName);
- return true;
- }
-
- function findResolutionCycleStartIndex(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): number {
- for (let i = resolutionTargets.length - 1; i >= 0; i--) {
- if (hasType(resolutionTargets[i], resolutionPropertyNames[i])) {
- return -1;
- }
- if (resolutionTargets[i] === target && resolutionPropertyNames[i] === propertyName) {
- return i;
- }
- }
-
- return -1;
- }
-
- function hasType(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): Type {
- if (propertyName === TypeSystemPropertyName.Type) {
- return getSymbolLinks(target).type;
- }
- if (propertyName === TypeSystemPropertyName.DeclaredType) {
- return getSymbolLinks(target).declaredType;
- }
- if (propertyName === TypeSystemPropertyName.ResolvedBaseConstructorType) {
- Debug.assert(!!((target).flags & TypeFlags.Class));
- return (target).resolvedBaseConstructorType;
- }
- if (propertyName === TypeSystemPropertyName.ResolvedReturnType) {
- return (target).resolvedReturnType;
- }
-
- Debug.fail("Unhandled TypeSystemPropertyName " + propertyName);
- }
-
- // Pop an entry from the type resolution stack and return its associated result value. The result value will
- // be true if no circularities were detected, or false if a circularity was found.
- function popTypeResolution(): boolean {
- resolutionTargets.pop();
- resolutionPropertyNames.pop();
- return resolutionResults.pop();
- }
-
- function getDeclarationContainer(node: Node): Node {
- node = getRootDeclaration(node);
- while (node) {
- switch (node.kind) {
- case SyntaxKind.VariableDeclaration:
- case SyntaxKind.VariableDeclarationList:
- case SyntaxKind.ImportSpecifier:
- case SyntaxKind.NamedImports:
- case SyntaxKind.NamespaceImport:
- case SyntaxKind.ImportClause:
- node = node.parent;
- break;
-
- default:
- return node.parent;
- }
- }
- }
-
- function getTypeOfPrototypeProperty(prototype: Symbol): Type {
- // TypeScript 1.0 spec (April 2014): 8.4
- // Every class automatically contains a static property member named 'prototype',
- // the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter.
- // It is an error to explicitly declare a static property member with the name 'prototype'.
- const classType = getDeclaredTypeOfSymbol(getParentOfSymbol(prototype));
- return classType.typeParameters ? createTypeReference(classType, map(classType.typeParameters, _ => anyType)) : classType;
- }
-
- // Return the type of the given property in the given type, or undefined if no such property exists
- function getTypeOfPropertyOfType(type: Type, name: string): Type {
- const prop = getPropertyOfType(type, name);
- return prop ? getTypeOfSymbol(prop) : undefined;
- }
-
- function isTypeAny(type: Type) {
- return type && (type.flags & TypeFlags.Any) !== 0;
- }
-
- // Return the type of a binding element parent. We check SymbolLinks first to see if a type has been
- // assigned by contextual typing.
- function getTypeForBindingElementParent(node: VariableLikeDeclaration) {
- const symbol = getSymbolOfNode(node);
- return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node);
- }
-
- function getTextOfPropertyName(name: PropertyName): string {
- switch (name.kind) {
- case SyntaxKind.Identifier:
- return (name).text;
- case SyntaxKind.StringLiteral:
- case SyntaxKind.NumericLiteral:
- return (name).text;
- case SyntaxKind.ComputedPropertyName:
- if (isStringOrNumericLiteral((name).expression.kind)) {
- return ((name).expression).text;
- }
- }
-
- return undefined;
- }
-
- function isComputedNonLiteralName(name: PropertyName): boolean {
- return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteral((name).expression.kind);
- }
-
- /** Return the inferred type for a binding element */
- function getTypeForBindingElement(declaration: BindingElement): Type {
- const pattern = declaration.parent;
- const parentType = getTypeForBindingElementParent(pattern.parent);
- // If parent has the unknown (error) type, then so does this binding element
- if (parentType === unknownType) {
- return unknownType;
- }
- // If no type was specified or inferred for parent, or if the specified or inferred type is any,
- // infer from the initializer of the binding element if one is present. Otherwise, go with the
- // undefined or any type of the parent.
- if (!parentType || isTypeAny(parentType)) {
- if (declaration.initializer) {
- return checkExpressionCached(declaration.initializer);
- }
- return parentType;
- }
-
- let type: Type;
- if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
- // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
- const name = declaration.propertyName || declaration.name;
- if (isComputedNonLiteralName(name)) {
- // computed properties with non-literal names are treated as 'any'
- return anyType;
- }
- if (declaration.initializer) {
- getContextualType(declaration.initializer);
- }
-
- // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature,
- // or otherwise the type of the string index signature.
- const text = getTextOfPropertyName(name);
-
- type = getTypeOfPropertyOfType(parentType, text) ||
- isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
- getIndexTypeOfType(parentType, IndexKind.String);
- if (!type) {
- error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name));
- return unknownType;
- }
- }
- else {
- // This elementType will be used if the specific property corresponding to this index is not
- // present (aka the tuple element property). This call also checks that the parentType is in
- // fact an iterable or array (depending on target language).
- const elementType = checkIteratedTypeOrElementType(parentType, pattern, /*allowStringInput*/ false);
- if (!declaration.dotDotDotToken) {
- // Use specific property type when parent is a tuple or numeric index type when parent is an array
- const propName = "" + indexOf(pattern.elements, declaration);
- type = isTupleLikeType(parentType)
- ? getTypeOfPropertyOfType(parentType, propName)
- : elementType;
- if (!type) {
- if (isTupleType(parentType)) {
- error(declaration, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(parentType), (parentType).elementTypes.length, pattern.elements.length);
- }
- else {
- error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName);
- }
- return unknownType;
- }
- }
- else {
- // Rest element has an array type with the same element type as the parent type
- type = createArrayType(elementType);
- }
- }
- // In strict null checking mode, if a default value of a non-undefined type is specified, remove
- // undefined from the final type.
- if (strictNullChecks && declaration.initializer && !(getNullableKind(checkExpressionCached(declaration.initializer)) & TypeFlags.Undefined)) {
- type = removeNullableKind(type, TypeFlags.Undefined);
- }
- return type;
- }
-
- function getTypeForVariableLikeDeclarationFromJSDocComment(declaration: VariableLikeDeclaration) {
- const jsDocType = getJSDocTypeForVariableLikeDeclarationFromJSDocComment(declaration);
- if (jsDocType) {
- return getTypeFromTypeNode(jsDocType);
- }
- }
-
- function getJSDocTypeForVariableLikeDeclarationFromJSDocComment(declaration: VariableLikeDeclaration): JSDocType {
- // First, see if this node has an @type annotation on it directly.
- const typeTag = getJSDocTypeTag(declaration);
- if (typeTag && typeTag.typeExpression) {
- return typeTag.typeExpression.type;
- }
-
- if (declaration.kind === SyntaxKind.VariableDeclaration &&
- declaration.parent.kind === SyntaxKind.VariableDeclarationList &&
- declaration.parent.parent.kind === SyntaxKind.VariableStatement) {
-
- // @type annotation might have been on the variable statement, try that instead.
- const annotation = getJSDocTypeTag(declaration.parent.parent);
- if (annotation && annotation.typeExpression) {
- return annotation.typeExpression.type;
- }
- }
- else if (declaration.kind === SyntaxKind.Parameter) {
- // If it's a parameter, see if the parent has a jsdoc comment with an @param
- // annotation.
- const paramTag = getCorrespondingJSDocParameterTag(declaration);
- if (paramTag && paramTag.typeExpression) {
- return paramTag.typeExpression.type;
- }
- }
-
- return undefined;
- }
-
- // Return the inferred type for a variable, parameter, or property declaration
- function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type {
- if (declaration.flags & NodeFlags.JavaScriptFile) {
- // If this is a variable in a JavaScript file, then use the JSDoc type (if it has
- // one as its type), otherwise fallback to the below standard TS codepaths to
- // try to figure it out.
- const type = getTypeForVariableLikeDeclarationFromJSDocComment(declaration);
- if (type && type !== unknownType) {
- return type;
- }
- }
-
- // A variable declared in a for..in statement is always of type string
- if (declaration.parent.parent.kind === SyntaxKind.ForInStatement) {
- return stringType;
- }
-
- if (declaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
- // checkRightHandSideOfForOf will return undefined if the for-of expression type was
- // missing properties/signatures required to get its iteratedType (like
- // [Symbol.iterator] or next). This may be because we accessed properties from anyType,
- // or it may have led to an error inside getElementTypeOfIterable.
- return checkRightHandSideOfForOf((declaration.parent.parent).expression) || anyType;
- }
-
- if (isBindingPattern(declaration.parent)) {
- return getTypeForBindingElement(declaration);
- }
-
- // Use type from type annotation if one is present
- if (declaration.type) {
- const type = getTypeFromTypeNode(declaration.type);
- return strictNullChecks && declaration.questionToken ? addNullableKind(type, TypeFlags.Undefined) : type;
- }
-
- if (declaration.kind === SyntaxKind.Parameter) {
- const func = declaration.parent;
- // For a parameter of a set accessor, use the type of the get accessor if one is present
- if (func.kind === SyntaxKind.SetAccessor && !hasDynamicName(func)) {
- const getter = getDeclarationOfKind(declaration.parent.symbol, SyntaxKind.GetAccessor);
- if (getter) {
- return getReturnTypeOfSignature(getSignatureFromDeclaration(getter));
- }
- }
- // Use contextual parameter type if one is available
- const type = declaration.symbol.name === "this"
- ? getContextuallyTypedThisType(func)
- : getContextuallyTypedParameterType(declaration);
- if (type) {
- return strictNullChecks && declaration.questionToken ? addNullableKind(type, TypeFlags.Undefined) : type;
- }
- }
-
- // Use the type of the initializer expression if one is present
- if (declaration.initializer) {
- return checkExpressionCached(declaration.initializer);
- }
-
- // If it is a short-hand property assignment, use the type of the identifier
- if (declaration.kind === SyntaxKind.ShorthandPropertyAssignment) {
- return checkIdentifier(declaration.name);
- }
-
- // If the declaration specifies a binding pattern, use the type implied by the binding pattern
- if (isBindingPattern(declaration.name)) {
- return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ false);
- }
-
- // No type specified and nothing can be inferred
- return undefined;
- }
-
- // Return the type implied by a binding pattern element. This is the type of the initializer of the element if
- // one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding
- // pattern. Otherwise, it is the type any.
- function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean): Type {
- if (element.initializer) {
- const type = checkExpressionCached(element.initializer);
- reportErrorsFromWidening(element, type);
- return getWidenedType(type);
- }
- if (isBindingPattern(element.name)) {
- return getTypeFromBindingPattern(element.name, includePatternInType);
- }
- if (compilerOptions.noImplicitAny && !declarationBelongsToPrivateAmbientMember(element)) {
- reportImplicitAnyError(element, anyType);
- }
- return anyType;
- }
-
- // Return the type implied by an object binding pattern
- function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean): Type {
- const members: SymbolTable = {};
- let hasComputedProperties = false;
- forEach(pattern.elements, e => {
- const name = e.propertyName || e.name;
- if (isComputedNonLiteralName(name)) {
- // do not include computed properties in the implied type
- hasComputedProperties = true;
- return;
- }
-
- const text = getTextOfPropertyName(name);
- const flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0);
- const symbol = createSymbol(flags, text);
- symbol.type = getTypeFromBindingElement(e, includePatternInType);
- symbol.bindingElement = e;
- members[symbol.name] = symbol;
- });
- const result = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined);
- if (includePatternInType) {
- result.pattern = pattern;
- }
- if (hasComputedProperties) {
- result.flags |= TypeFlags.ObjectLiteralPatternWithComputedProperties;
- }
- return result;
- }
-
- // Return the type implied by an array binding pattern
- function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean): Type {
- const elements = pattern.elements;
- if (elements.length === 0 || elements[elements.length - 1].dotDotDotToken) {
- return languageVersion >= ScriptTarget.ES6 ? createIterableType(anyType) : anyArrayType;
- }
- // If the pattern has at least one element, and no rest element, then it should imply a tuple type.
- const elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e, includePatternInType));
- if (includePatternInType) {
- const result = createNewTupleType(elementTypes);
- result.pattern = pattern;
- return result;
- }
- return createTupleType(elementTypes);
- }
-
- // Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself
- // and without regard to its context (i.e. without regard any type annotation or initializer associated with the
- // declaration in which the binding pattern is contained). For example, the implied type of [x, y] is [any, any]
- // and the implied type of { x, y: z = 1 } is { x: any; y: number; }. The type implied by a binding pattern is
- // used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring
- // parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of
- // the parameter.
- function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType?: boolean): Type {
- return pattern.kind === SyntaxKind.ObjectBindingPattern
- ? getTypeFromObjectBindingPattern(pattern, includePatternInType)
- : getTypeFromArrayBindingPattern(pattern, includePatternInType);
- }
-
- // Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type
- // specified in a type annotation or inferred from an initializer. However, in the case of a destructuring declaration it
- // is a bit more involved. For example:
- //
- // var [x, s = ""] = [1, "one"];
- //
- // Here, the array literal [1, "one"] is contextually typed by the type [any, string], which is the implied type of the
- // binding pattern [x, s = ""]. Because the contextual type is a tuple type, the resulting type of [1, "one"] is the
- // tuple type [number, string]. Thus, the type inferred for 'x' is number and the type inferred for 's' is string.
- function getWidenedTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, reportErrors?: boolean): Type {
- let type = getTypeForVariableLikeDeclaration(declaration);
- if (type) {
- if (reportErrors) {
- reportErrorsFromWidening(declaration, type);
- }
- // During a normal type check we'll never get to here with a property assignment (the check of the containing
- // object literal uses a different path). We exclude widening only so that language services and type verification
- // tools see the actual type.
- if (declaration.kind === SyntaxKind.PropertyAssignment) {
- return type;
- }
- return getWidenedType(type);
- }
-
- // Rest parameters default to type any[], other parameters default to type any
- type = declaration.dotDotDotToken ? anyArrayType : anyType;
-
- // Report implicit any errors unless this is a private property within an ambient declaration
- if (reportErrors && compilerOptions.noImplicitAny) {
- if (!declarationBelongsToPrivateAmbientMember(declaration)) {
- reportImplicitAnyError(declaration, type);
- }
- }
- return type;
- }
-
- function declarationBelongsToPrivateAmbientMember(declaration: VariableLikeDeclaration) {
- const root = getRootDeclaration(declaration);
- const memberDeclaration = root.kind === SyntaxKind.Parameter ? root.parent : root;
- return isPrivateWithinAmbient(memberDeclaration);
- }
-
- function getTypeOfVariableOrParameterOrProperty(symbol: Symbol): Type {
- const links = getSymbolLinks(symbol);
- if (!links.type) {
- // Handle prototype property
- if (symbol.flags & SymbolFlags.Prototype) {
- return links.type = getTypeOfPrototypeProperty(symbol);
- }
- // Handle catch clause variables
- const declaration = symbol.valueDeclaration;
- if (declaration.parent.kind === SyntaxKind.CatchClause) {
- return links.type = anyType;
- }
- // Handle export default expressions
- if (declaration.kind === SyntaxKind.ExportAssignment) {
- return links.type = checkExpression((declaration).expression);
- }
- // Handle module.exports = expr
- if (declaration.kind === SyntaxKind.BinaryExpression) {
- return links.type = getUnionType(map(symbol.declarations, (decl: BinaryExpression) => checkExpressionCached(decl.right)));
- }
- if (declaration.kind === SyntaxKind.PropertyAccessExpression) {
- // Declarations only exist for property access expressions for certain
- // special assignment kinds
- if (declaration.parent.kind === SyntaxKind.BinaryExpression) {
- // Handle exports.p = expr or this.p = expr or className.prototype.method = expr
- return links.type = checkExpressionCached((declaration.parent).right);
- }
- }
- // Handle variable, parameter or property
- if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
- return unknownType;
- }
- let type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true);
- if (!popTypeResolution()) {
- if ((symbol.valueDeclaration).type) {
- // Variable has type annotation that circularly references the variable itself
- type = unknownType;
- error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation,
- symbolToString(symbol));
- }
- else {
- // Variable has initializer that circularly references the variable itself
- type = anyType;
- if (compilerOptions.noImplicitAny) {
- error(symbol.valueDeclaration, Diagnostics._0_implicitly_has_type_any_because_it_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer,
- symbolToString(symbol));
- }
- }
- }
- links.type = type;
- }
- return links.type;
- }
-
- function getAnnotatedAccessorType(accessor: AccessorDeclaration): Type {
- if (accessor) {
- if (accessor.kind === SyntaxKind.GetAccessor) {
- return accessor.type && getTypeFromTypeNode(accessor.type);
- }
- else {
- const setterTypeAnnotation = getSetAccessorTypeAnnotationNode(accessor);
- return setterTypeAnnotation && getTypeFromTypeNode(setterTypeAnnotation);
- }
- }
- return undefined;
- }
-
- function getTypeOfAccessors(symbol: Symbol): Type {
- const links = getSymbolLinks(symbol);
- if (!links.type) {
- const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
- const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor);
-
- if (getter && getter.flags & NodeFlags.JavaScriptFile) {
- const jsDocType = getTypeForVariableLikeDeclarationFromJSDocComment(getter);
- if (jsDocType) {
- return links.type = jsDocType;
- }
- }
-
- if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
- return unknownType;
- }
-
- let type: Type;
-
- // First try to see if the user specified a return type on the get-accessor.
- const getterReturnType = getAnnotatedAccessorType(getter);
- if (getterReturnType) {
- type = getterReturnType;
- }
- else {
- // If the user didn't specify a return type, try to use the set-accessor's parameter type.
- const setterParameterType = getAnnotatedAccessorType(setter);
- if (setterParameterType) {
- type = setterParameterType;
- }
- else {
- // If there are no specified types, try to infer it from the body of the get accessor if it exists.
- if (getter && getter.body) {
- type = getReturnTypeFromBody(getter);
- }
- // Otherwise, fall back to 'any'.
- else {
- if (compilerOptions.noImplicitAny) {
- error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbolToString(symbol));
- }
- type = anyType;
- }
- }
- }
- if (!popTypeResolution()) {
- type = anyType;
- if (compilerOptions.noImplicitAny) {
- const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
- error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol));
- }
- }
- links.type = type;
- }
- return links.type;
- }
-
- function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
- const links = getSymbolLinks(symbol);
- if (!links.type) {
- links.type = createObjectType(TypeFlags.Anonymous, symbol);
- }
- return links.type;
- }
-
- function getTypeOfEnumMember(symbol: Symbol): Type {
- const links = getSymbolLinks(symbol);
- if (!links.type) {
- links.type = getDeclaredTypeOfEnum(getParentOfSymbol(symbol));
- }
- return links.type;
- }
-
- function getTypeOfAlias(symbol: Symbol): Type {
- const links = getSymbolLinks(symbol);
- if (!links.type) {
- const targetSymbol = resolveAlias(symbol);
-
- // It only makes sense to get the type of a value symbol. If the result of resolving
- // the alias is not a value, then it has no type. To get the type associated with a
- // type symbol, call getDeclaredTypeOfSymbol.
- // This check is important because without it, a call to getTypeOfSymbol could end
- // up recursively calling getTypeOfAlias, causing a stack overflow.
- links.type = targetSymbol.flags & SymbolFlags.Value
- ? getTypeOfSymbol(targetSymbol)
- : unknownType;
- }
- return links.type;
- }
-
- function getTypeOfInstantiatedSymbol(symbol: Symbol): Type {
- const links = getSymbolLinks(symbol);
- if (!links.type) {
- links.type = instantiateType(getTypeOfSymbol(links.target), links.mapper);
- }
- return links.type;
- }
-
- function getTypeOfSymbol(symbol: Symbol): Type {
- if (symbol.flags & SymbolFlags.Instantiated) {
- return getTypeOfInstantiatedSymbol(symbol);
- }
- if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) {
- return getTypeOfVariableOrParameterOrProperty(symbol);
- }
- if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
- return getTypeOfFuncClassEnumModule(symbol);
- }
- if (symbol.flags & SymbolFlags.EnumMember) {
- return getTypeOfEnumMember(symbol);
- }
- if (symbol.flags & SymbolFlags.Accessor) {
- return getTypeOfAccessors(symbol);
- }
- if (symbol.flags & SymbolFlags.Alias) {
- return getTypeOfAlias(symbol);
- }
- return unknownType;
- }
-
- function getTargetType(type: ObjectType): Type {
- return type.flags & TypeFlags.Reference ? (type).target : type;
- }
-
- function hasBaseType(type: InterfaceType, checkBase: InterfaceType) {
- return check(type);
- function check(type: InterfaceType): boolean {
- const target = getTargetType(type);
- return target === checkBase || forEach(getBaseTypes(target), check);
- }
- }
-
- // Appends the type parameters given by a list of declarations to a set of type parameters and returns the resulting set.
- // The function allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set
- // in-place and returns the same array.
- function appendTypeParameters(typeParameters: TypeParameter[], declarations: TypeParameterDeclaration[]): TypeParameter[] {
- for (const declaration of declarations) {
- const tp = getDeclaredTypeOfTypeParameter(getSymbolOfNode(declaration));
- if (!typeParameters) {
- typeParameters = [tp];
- }
- else if (!contains(typeParameters, tp)) {
- typeParameters.push(tp);
- }
- }
- return typeParameters;
- }
-
- // Appends the outer type parameters of a node to a set of type parameters and returns the resulting set. The function
- // allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set in-place and
- // returns the same array.
- function appendOuterTypeParameters(typeParameters: TypeParameter[], node: Node): TypeParameter[] {
- while (true) {
- node = node.parent;
- if (!node) {
- return typeParameters;
- }
- if (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression ||
- node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression ||
- node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.ArrowFunction) {
- const declarations = (node).typeParameters;
- if (declarations) {
- return appendTypeParameters(appendOuterTypeParameters(typeParameters, node), declarations);
- }
- }
- }
- }
-
- // The outer type parameters are those defined by enclosing generic classes, methods, or functions.
- function getOuterTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] {
- const declaration = symbol.flags & SymbolFlags.Class ? symbol.valueDeclaration : getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration);
- return appendOuterTypeParameters(undefined, declaration);
- }
-
- // The local type parameters are the combined set of type parameters from all declarations of the class,
- // interface, or type alias.
- function getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): TypeParameter[] {
- let result: TypeParameter[];
- for (const node of symbol.declarations) {
- if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration ||
- node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.TypeAliasDeclaration) {
- const declaration = node;
- if (declaration.typeParameters) {
- result = appendTypeParameters(result, declaration.typeParameters);
- }
- }
- }
- return result;
- }
-
- // The full set of type parameters for a generic class or interface type consists of its outer type parameters plus
- // its locally declared type parameters.
- function getTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] {
- return concatenate(getOuterTypeParametersOfClassOrInterface(symbol), getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol));
- }
-
- function isConstructorType(type: Type): boolean {
- return type.flags & TypeFlags.ObjectType && getSignaturesOfType(type, SignatureKind.Construct).length > 0;
- }
-
- function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments {
- return getClassExtendsHeritageClauseElement(type.symbol.valueDeclaration);
- }
-
- function getConstructorsForTypeArguments(type: ObjectType, typeArgumentNodes: TypeNode[]): Signature[] {
- const typeArgCount = typeArgumentNodes ? typeArgumentNodes.length : 0;
- return filter(getSignaturesOfType(type, SignatureKind.Construct),
- sig => (sig.typeParameters ? sig.typeParameters.length : 0) === typeArgCount);
- }
-
- function getInstantiatedConstructorsForTypeArguments(type: ObjectType, typeArgumentNodes: TypeNode[]): Signature[] {
- let signatures = getConstructorsForTypeArguments(type, typeArgumentNodes);
- if (typeArgumentNodes) {
- const typeArguments = map(typeArgumentNodes, getTypeFromTypeNode);
- signatures = map(signatures, sig => getSignatureInstantiation(sig, typeArguments));
- }
- return signatures;
- }
-
- // The base constructor of a class can resolve to
- // undefinedType if the class has no extends clause,
- // unknownType if an error occurred during resolution of the extends expression,
- // nullType if the extends expression is the null value, or
- // an object type with at least one construct signature.
- function getBaseConstructorTypeOfClass(type: InterfaceType): ObjectType {
- if (!type.resolvedBaseConstructorType) {
- const baseTypeNode = getBaseTypeNodeOfClass(type);
- if (!baseTypeNode) {
- return type.resolvedBaseConstructorType = undefinedType;
- }
- if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseConstructorType)) {
- return unknownType;
- }
- const baseConstructorType = checkExpression(baseTypeNode.expression);
- if (baseConstructorType.flags & TypeFlags.ObjectType) {
- // Resolving the members of a class requires us to resolve the base class of that class.
- // We force resolution here such that we catch circularities now.
- resolveStructuredTypeMembers(baseConstructorType);
- }
- if (!popTypeResolution()) {
- error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, symbolToString(type.symbol));
- return type.resolvedBaseConstructorType = unknownType;
- }
- if (baseConstructorType !== unknownType && baseConstructorType !== nullType && !isConstructorType(baseConstructorType)) {
- error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, typeToString(baseConstructorType));
- return type.resolvedBaseConstructorType = unknownType;
- }
- type.resolvedBaseConstructorType = baseConstructorType;
- }
- return type.resolvedBaseConstructorType;
- }
-
- function getBaseTypes(type: InterfaceType): ObjectType[] {
- const isClass = type.symbol.flags & SymbolFlags.Class;
- const isInterface = type.symbol.flags & SymbolFlags.Interface;
- if (!type.resolvedBaseTypes) {
- if (!isClass && !isInterface) {
- Debug.fail("type must be class or interface");
- }
- if (isClass) {
- resolveBaseTypesOfClass(type);
- }
- if (isInterface) {
- resolveBaseTypesOfInterface(type);
- }
- }
- return type.resolvedBaseTypes;
- }
-
- function resolveBaseTypesOfClass(type: InterfaceType): void {
- type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
- const baseConstructorType = getBaseConstructorTypeOfClass(type);
- if (!(baseConstructorType.flags & TypeFlags.ObjectType)) {
- return;
- }
- const baseTypeNode = getBaseTypeNodeOfClass(type);
- let baseType: Type;
- const originalBaseType = baseConstructorType && baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) : undefined;
- if (baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class &&
- areAllOuterTypeParametersApplied(originalBaseType)) {
- // When base constructor type is a class with no captured type arguments we know that the constructors all have the same type parameters as the
- // class and all return the instance type of the class. There is no need for further checks and we can apply the
- // type arguments in the same manner as a type reference to get the same error reporting experience.
- baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol);
- }
- else {
- // The class derives from a "class-like" constructor function, check that we have at least one construct signature
- // with a matching number of type parameters and use the return type of the first instantiated signature. Elsewhere
- // we check that all instantiated signatures return the same type.
- const constructors = getInstantiatedConstructorsForTypeArguments(baseConstructorType, baseTypeNode.typeArguments);
- if (!constructors.length) {
- error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments);
- return;
- }
- baseType = getReturnTypeOfSignature(constructors[0]);
- }
- if (baseType === unknownType) {
- return;
- }
- if (!(getTargetType(baseType).flags & (TypeFlags.Class | TypeFlags.Interface))) {
- error(baseTypeNode.expression, Diagnostics.Base_constructor_return_type_0_is_not_a_class_or_interface_type, typeToString(baseType));
- return;
- }
- if (type === baseType || hasBaseType(baseType, type)) {
- error(type.symbol.valueDeclaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type,
- typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
- return;
- }
- if (type.resolvedBaseTypes === emptyArray) {
- type.resolvedBaseTypes = [baseType];
- }
- else {
- type.resolvedBaseTypes.push(baseType);
- }
- }
-
- function areAllOuterTypeParametersApplied(type: Type): boolean {
- // An unapplied type parameter has its symbol still the same as the matching argument symbol.
- // Since parameters are applied outer-to-inner, only the last outer parameter needs to be checked.
- const outerTypeParameters = (type).outerTypeParameters;
- if (outerTypeParameters) {
- const last = outerTypeParameters.length - 1;
- const typeArguments = (type).typeArguments;
- return outerTypeParameters[last].symbol !== typeArguments[last].symbol;
- }
- return true;
- }
-
- function resolveBaseTypesOfInterface(type: InterfaceType): void {
- type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
- for (const declaration of type.symbol.declarations) {
- if (declaration.kind === SyntaxKind.InterfaceDeclaration && getInterfaceBaseTypeNodes(declaration)) {
- for (const node of getInterfaceBaseTypeNodes(declaration)) {
- const baseType = getTypeFromTypeNode(node);
- if (baseType !== unknownType) {
- if (getTargetType(baseType).flags & (TypeFlags.Class | TypeFlags.Interface)) {
- if (type !== baseType && !hasBaseType(baseType, type)) {
- if (type.resolvedBaseTypes === emptyArray) {
- type.resolvedBaseTypes = [baseType];
- }
- else {
- type.resolvedBaseTypes.push(baseType);
- }
- }
- else {
- error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
- }
- }
- else {
- error(node, Diagnostics.An_interface_may_only_extend_a_class_or_another_interface);
- }
- }
- }
- }
- }
- }
-
- // Returns true if the interface given by the symbol is free of "this" references. Specifically, the result is
- // true if the interface itself contains no references to "this" in its body, if all base types are interfaces,
- // and if none of the base interfaces have a "this" type.
- function isIndependentInterface(symbol: Symbol): boolean {
- for (const declaration of symbol.declarations) {
- if (declaration.kind === SyntaxKind.InterfaceDeclaration) {
- if (declaration.flags & NodeFlags.ContainsThis) {
- return false;
- }
- const baseTypeNodes = getInterfaceBaseTypeNodes(declaration);
- if (baseTypeNodes) {
- for (const node of baseTypeNodes) {
- if (isSupportedExpressionWithTypeArguments(node)) {
- const baseSymbol = resolveEntityName(node.expression, SymbolFlags.Type, /*ignoreErrors*/ true);
- if (!baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) || getDeclaredTypeOfClassOrInterface(baseSymbol).thisType) {
- return false;
- }
- }
- }
- }
- }
- }
- return true;
- }
-
- function getDeclaredTypeOfClassOrInterface(symbol: Symbol): InterfaceType {
- const links = getSymbolLinks(symbol);
- if (!links.declaredType) {
- const kind = symbol.flags & SymbolFlags.Class ? TypeFlags.Class : TypeFlags.Interface;
- const type = links.declaredType = createObjectType(kind, symbol);
- const outerTypeParameters = getOuterTypeParametersOfClassOrInterface(symbol);
- const localTypeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
- // A class or interface is generic if it has type parameters or a "this" type. We always give classes a "this" type
- // because it is not feasible to analyze all members to determine if the "this" type escapes the class (in particular,
- // property types inferred from initializers and method return types inferred from return statements are very hard
- // to exhaustively analyze). We give interfaces a "this" type if we can't definitely determine that they are free of
- // "this" references.
- if (outerTypeParameters || localTypeParameters || kind === TypeFlags.Class || !isIndependentInterface(symbol)) {
- type.flags |= TypeFlags.Reference;
- type.typeParameters = concatenate(outerTypeParameters, localTypeParameters);
- type.outerTypeParameters = outerTypeParameters;
- type.localTypeParameters = localTypeParameters;
- (type).instantiations = {};
- (type).instantiations[getTypeListId(type.typeParameters)] = type;
- (type).target = type;
- (type).typeArguments = type.typeParameters;
- type.thisType = createType(TypeFlags.TypeParameter | TypeFlags.ThisType);
- type.thisType.symbol = symbol;
- type.thisType.constraint = type;
- }
- }
- return links.declaredType;
- }
-
- function getDeclaredTypeOfTypeAlias(symbol: Symbol): Type {
- const links = getSymbolLinks(symbol);
- if (!links.declaredType) {
- // Note that we use the links object as the target here because the symbol object is used as the unique
- // identity for resolution of the 'type' property in SymbolLinks.
- if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) {
- return unknownType;
- }
- const declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
- let type = getTypeFromTypeNode(declaration.type);
- if (popTypeResolution()) {
- links.typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
- if (links.typeParameters) {
- // Initialize the instantiation cache for generic type aliases. The declared type corresponds to
- // an instantiation of the type alias with the type parameters supplied as type arguments.
- links.instantiations = {};
- links.instantiations[getTypeListId(links.typeParameters)] = type;
- }
- }
- else {
- type = unknownType;
- error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol));
- }
- links.declaredType = type;
- }
- return links.declaredType;
- }
-
- function getDeclaredTypeOfEnum(symbol: Symbol): Type {
- const links = getSymbolLinks(symbol);
- if (!links.declaredType) {
- const type = createType(TypeFlags.Enum);
- type.symbol = symbol;
- links.declaredType = type;
- }
- return links.declaredType;
- }
-
- function getDeclaredTypeOfTypeParameter(symbol: Symbol): TypeParameter {
- const links = getSymbolLinks(symbol);
- if (!links.declaredType) {
- const type = createType(TypeFlags.TypeParameter);
- type.symbol = symbol;
- if (!(getDeclarationOfKind(symbol, SyntaxKind.TypeParameter)).constraint) {
- type.constraint = noConstraintType;
- }
- links.declaredType = type;
- }
- return links.declaredType;
- }
-
- function getDeclaredTypeOfAlias(symbol: Symbol): Type {
- const links = getSymbolLinks(symbol);
- if (!links.declaredType) {
- links.declaredType = getDeclaredTypeOfSymbol(resolveAlias(symbol));
- }
- return links.declaredType;
- }
-
- function getDeclaredTypeOfSymbol(symbol: Symbol): Type {
- Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0);
- if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
- return getDeclaredTypeOfClassOrInterface(symbol);
- }
- if (symbol.flags & SymbolFlags.TypeAlias) {
- return getDeclaredTypeOfTypeAlias(symbol);
- }
- if (symbol.flags & SymbolFlags.Enum) {
- return getDeclaredTypeOfEnum(symbol);
- }
- if (symbol.flags & SymbolFlags.TypeParameter) {
- return getDeclaredTypeOfTypeParameter(symbol);
- }
- if (symbol.flags & SymbolFlags.Alias) {
- return getDeclaredTypeOfAlias(symbol);
- }
- return unknownType;
- }
-
- // A type reference is considered independent if each type argument is considered independent.
- function isIndependentTypeReference(node: TypeReferenceNode): boolean {
- if (node.typeArguments) {
- for (const typeNode of node.typeArguments) {
- if (!isIndependentType(typeNode)) {
- return false;
- }
- }
- }
- return true;
- }
-
- // A type is considered independent if it the any, string, number, boolean, symbol, or void keyword, a string
- // literal type, an array with an element type that is considered independent, or a type reference that is
- // considered independent.
- function isIndependentType(node: TypeNode): boolean {
- switch (node.kind) {
- case SyntaxKind.AnyKeyword:
- case SyntaxKind.StringKeyword:
- case SyntaxKind.NumberKeyword:
- case SyntaxKind.BooleanKeyword:
- case SyntaxKind.SymbolKeyword:
- case SyntaxKind.VoidKeyword:
- case SyntaxKind.UndefinedKeyword:
- case SyntaxKind.NullKeyword:
- case SyntaxKind.StringLiteralType:
- return true;
- case SyntaxKind.ArrayType:
- return isIndependentType((node).elementType);
- case SyntaxKind.TypeReference:
- return isIndependentTypeReference(node);
- }
- return false;
- }
-
- // A variable-like declaration is considered independent (free of this references) if it has a type annotation
- // that specifies an independent type, or if it has no type annotation and no initializer (and thus of type any).
- function isIndependentVariableLikeDeclaration(node: VariableLikeDeclaration): boolean {
- return node.type && isIndependentType(node.type) || !node.type && !node.initializer;
- }
-
- // A function-like declaration is considered independent (free of this references) if it has a return type
- // annotation that is considered independent and if each parameter is considered independent.
- function isIndependentFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean {
- if (node.kind !== SyntaxKind.Constructor && (!node.type || !isIndependentType(node.type))) {
- return false;
- }
- for (const parameter of node.parameters) {
- if (!isIndependentVariableLikeDeclaration(parameter)) {
- return false;
- }
- }
- return true;
- }
-
- // Returns true if the class or interface member given by the symbol is free of "this" references. The
- // function may return false for symbols that are actually free of "this" references because it is not
- // feasible to perform a complete analysis in all cases. In particular, property members with types
- // inferred from their initializers and function members with inferred return types are conservatively
- // assumed not to be free of "this" references.
- function isIndependentMember(symbol: Symbol): boolean {
- if (symbol.declarations && symbol.declarations.length === 1) {
- const declaration = symbol.declarations[0];
- if (declaration) {
- switch (declaration.kind) {
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.PropertySignature:
- return isIndependentVariableLikeDeclaration(declaration);
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- case SyntaxKind.Constructor:
- return isIndependentFunctionLikeDeclaration(declaration);
- }
- }
- }
- return false;
- }
-
- function createSymbolTable(symbols: Symbol[]): SymbolTable {
- const result: SymbolTable = {};
- for (const symbol of symbols) {
- result[symbol.name] = symbol;
- }
- return result;
- }
-
- // The mappingThisOnly flag indicates that the only type parameter being mapped is "this". When the flag is true,
- // we check symbols to see if we can quickly conclude they are free of "this" references, thus needing no instantiation.
- function createInstantiatedSymbolTable(symbols: Symbol[], mapper: TypeMapper, mappingThisOnly: boolean): SymbolTable {
- const result: SymbolTable = {};
- for (const symbol of symbols) {
- result[symbol.name] = mappingThisOnly && isIndependentMember(symbol) ? symbol : instantiateSymbol(symbol, mapper);
- }
- return result;
- }
-
- function addInheritedMembers(symbols: SymbolTable, baseSymbols: Symbol[]) {
- for (const s of baseSymbols) {
- if (!hasProperty(symbols, s.name)) {
- symbols[s.name] = s;
- }
- }
- }
-
- function resolveDeclaredMembers(type: InterfaceType): InterfaceTypeWithDeclaredMembers {
- if (!(type).declaredProperties) {
- const symbol = type.symbol;
- (type).declaredProperties = getNamedMembers(symbol.members);
- (type).declaredCallSignatures = getSignaturesOfSymbol(symbol.members["__call"]);
- (type).declaredConstructSignatures = getSignaturesOfSymbol(symbol.members["__new"]);
- (type).declaredStringIndexInfo = getIndexInfoOfSymbol(symbol, IndexKind.String);
- (type).declaredNumberIndexInfo = getIndexInfoOfSymbol(symbol, IndexKind.Number);
- }
- return type;
- }
-
- function getTypeWithThisArgument(type: ObjectType, thisArgument?: Type) {
- if (type.flags & TypeFlags.Reference) {
- return createTypeReference((type).target,
- concatenate((type).typeArguments, [thisArgument || (type).target.thisType]));
- }
- return type;
- }
-
- function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: TypeParameter[], typeArguments: Type[]) {
- let mapper = identityMapper;
- let members = source.symbol.members;
- let callSignatures = source.declaredCallSignatures;
- let constructSignatures = source.declaredConstructSignatures;
- let stringIndexInfo = source.declaredStringIndexInfo;
- let numberIndexInfo = source.declaredNumberIndexInfo;
- if (!rangeEquals(typeParameters, typeArguments, 0, typeParameters.length)) {
- mapper = createTypeMapper(typeParameters, typeArguments);
- members = createInstantiatedSymbolTable(source.declaredProperties, mapper, /*mappingThisOnly*/ typeParameters.length === 1);
- callSignatures = instantiateList(source.declaredCallSignatures, mapper, instantiateSignature);
- constructSignatures = instantiateList(source.declaredConstructSignatures, mapper, instantiateSignature);
- stringIndexInfo = instantiateIndexInfo(source.declaredStringIndexInfo, mapper);
- numberIndexInfo = instantiateIndexInfo(source.declaredNumberIndexInfo, mapper);
- }
- const baseTypes = getBaseTypes(source);
- if (baseTypes.length) {
- if (members === source.symbol.members) {
- members = createSymbolTable(source.declaredProperties);
- }
- const thisArgument = lastOrUndefined(typeArguments);
- for (const baseType of baseTypes) {
- const instantiatedBaseType = thisArgument ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType;
- addInheritedMembers(members, getPropertiesOfObjectType(instantiatedBaseType));
- callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call));
- constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct));
- stringIndexInfo = stringIndexInfo || getIndexInfoOfType(instantiatedBaseType, IndexKind.String);
- numberIndexInfo = numberIndexInfo || getIndexInfoOfType(instantiatedBaseType, IndexKind.Number);
- }
- }
- setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
- }
-
- function resolveClassOrInterfaceMembers(type: InterfaceType): void {
- resolveObjectTypeMembers(type, resolveDeclaredMembers(type), emptyArray, emptyArray);
- }
-
- function resolveTypeReferenceMembers(type: TypeReference): void {
- const source = resolveDeclaredMembers(type.target);
- const typeParameters = concatenate(source.typeParameters, [source.thisType]);
- const typeArguments = type.typeArguments && type.typeArguments.length === typeParameters.length ?
- type.typeArguments : concatenate(type.typeArguments, [type]);
- resolveObjectTypeMembers(type, source, typeParameters, typeArguments);
- }
-
- function createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], thisType: Type, parameters: Symbol[],
- resolvedReturnType: Type, typePredicate: TypePredicate, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature {
- const sig = new Signature(checker);
- sig.declaration = declaration;
- sig.typeParameters = typeParameters;
- sig.parameters = parameters;
- sig.thisType = thisType;
- sig.resolvedReturnType = resolvedReturnType;
- sig.typePredicate = typePredicate;
- sig.minArgumentCount = minArgumentCount;
- sig.hasRestParameter = hasRestParameter;
- sig.hasStringLiterals = hasStringLiterals;
- return sig;
- }
-
- function cloneSignature(sig: Signature): Signature {
- return createSignature(sig.declaration, sig.typeParameters, sig.thisType, sig.parameters, sig.resolvedReturnType,
- sig.typePredicate, sig.minArgumentCount, sig.hasRestParameter, sig.hasStringLiterals);
- }
-
- function getDefaultConstructSignatures(classType: InterfaceType): Signature[] {
- const baseConstructorType = getBaseConstructorTypeOfClass(classType);
- const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct);
- if (baseSignatures.length === 0) {
- return [createSignature(undefined, classType.localTypeParameters, undefined, emptyArray, classType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)];
- }
- const baseTypeNode = getBaseTypeNodeOfClass(classType);
- const typeArguments = map(baseTypeNode.typeArguments, getTypeFromTypeNode);
- const typeArgCount = typeArguments ? typeArguments.length : 0;
- const result: Signature[] = [];
- for (const baseSig of baseSignatures) {
- const typeParamCount = baseSig.typeParameters ? baseSig.typeParameters.length : 0;
- if (typeParamCount === typeArgCount) {
- const sig = typeParamCount ? getSignatureInstantiation(baseSig, typeArguments) : cloneSignature(baseSig);
- sig.typeParameters = classType.localTypeParameters;
- sig.resolvedReturnType = classType;
- result.push(sig);
- }
- }
- return result;
- }
-
- function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable {
- const members: SymbolTable = {};
- for (let i = 0; i < memberTypes.length; i++) {
- const symbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "" + i);
- symbol.type = memberTypes[i];
- members[i] = symbol;
- }
- return members;
- }
-
- function resolveTupleTypeMembers(type: TupleType) {
- const arrayElementType = getUnionType(type.elementTypes, /*noSubtypeReduction*/ true);
- // Make the tuple type itself the 'this' type by including an extra type argument
- const arrayType = resolveStructuredTypeMembers(createTypeFromGenericGlobalType(globalArrayType, [arrayElementType, type]));
- const members = createTupleTypeMemberSymbols(type.elementTypes);
- addInheritedMembers(members, arrayType.properties);
- setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexInfo, arrayType.numberIndexInfo);
- }
-
- function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean): Signature {
- for (const s of signatureList) {
- if (compareSignaturesIdentical(s, signature, partialMatch, ignoreThisTypes, ignoreReturnTypes, compareTypesIdentical)) {
- return s;
- }
- }
- }
-
- function findMatchingSignatures(signatureLists: Signature[][], signature: Signature, listIndex: number): Signature[] {
- if (signature.typeParameters) {
- // We require an exact match for generic signatures, so we only return signatures from the first
- // signature list and only if they have exact matches in the other signature lists.
- if (listIndex > 0) {
- return undefined;
- }
- for (let i = 1; i < signatureLists.length; i++) {
- if (!findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false)) {
- return undefined;
- }
- }
- return [signature];
- }
- let result: Signature[] = undefined;
- for (let i = 0; i < signatureLists.length; i++) {
- // Allow matching non-generic signatures to have excess parameters and different return types
- const match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true);
- if (!match) {
- return undefined;
- }
- if (!contains(result, match)) {
- (result || (result = [])).push(match);
- }
- }
- return result;
- }
-
- // The signatures of a union type are those signatures that are present in each of the constituent types.
- // Generic signatures must match exactly, but non-generic signatures are allowed to have extra optional
- // parameters and may differ in return types. When signatures differ in return types, the resulting return
- // type is the union of the constituent return types.
- function getUnionSignatures(types: Type[], kind: SignatureKind): Signature[] {
- const signatureLists = map(types, t => getSignaturesOfType(t, kind));
- let result: Signature[] = undefined;
- for (let i = 0; i < signatureLists.length; i++) {
- for (const signature of signatureLists[i]) {
- // Only process signatures with parameter lists that aren't already in the result list
- if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true)) {
- const unionSignatures = findMatchingSignatures(signatureLists, signature, i);
- if (unionSignatures) {
- let s = signature;
- // Union the result types when more than one signature matches
- if (unionSignatures.length > 1) {
- s = cloneSignature(signature);
- if (forEach(unionSignatures, sig => sig.thisType)) {
- s.thisType = getUnionType(map(unionSignatures, sig => sig.thisType || anyType));
- }
- // Clear resolved return type we possibly got from cloneSignature
- s.resolvedReturnType = undefined;
- s.unionSignatures = unionSignatures;
- }
- (result || (result = [])).push(s);
- }
- }
- }
- }
- return result || emptyArray;
- }
-
- function getUnionIndexInfo(types: Type[], kind: IndexKind): IndexInfo {
- const indexTypes: Type[] = [];
- let isAnyReadonly = false;
- for (const type of types) {
- const indexInfo = getIndexInfoOfType(type, kind);
- if (!indexInfo) {
- return undefined;
- }
- indexTypes.push(indexInfo.type);
- isAnyReadonly = isAnyReadonly || indexInfo.isReadonly;
- }
- return createIndexInfo(getUnionType(indexTypes), isAnyReadonly);
- }
-
- function resolveUnionTypeMembers(type: UnionType) {
- // The members and properties collections are empty for union types. To get all properties of a union
- // type use getPropertiesOfType (only the language service uses this).
- const callSignatures = getUnionSignatures(type.types, SignatureKind.Call);
- const constructSignatures = getUnionSignatures(type.types, SignatureKind.Construct);
- const stringIndexInfo = getUnionIndexInfo(type.types, IndexKind.String);
- const numberIndexInfo = getUnionIndexInfo(type.types, IndexKind.Number);
- setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
- }
-
- function intersectTypes(type1: Type, type2: Type): Type {
- return !type1 ? type2 : !type2 ? type1 : getIntersectionType([type1, type2]);
- }
-
- function intersectIndexInfos(info1: IndexInfo, info2: IndexInfo): IndexInfo {
- return !info1 ? info2 : !info2 ? info1 : createIndexInfo(
- getIntersectionType([info1.type, info2.type]), info1.isReadonly && info2.isReadonly);
- }
-
- function resolveIntersectionTypeMembers(type: IntersectionType) {
- // The members and properties collections are empty for intersection types. To get all properties of an
- // intersection type use getPropertiesOfType (only the language service uses this).
- let callSignatures: Signature[] = emptyArray;
- let constructSignatures: Signature[] = emptyArray;
- let stringIndexInfo: IndexInfo = undefined;
- let numberIndexInfo: IndexInfo = undefined;
- for (const t of type.types) {
- callSignatures = concatenate(callSignatures, getSignaturesOfType(t, SignatureKind.Call));
- constructSignatures = concatenate(constructSignatures, getSignaturesOfType(t, SignatureKind.Construct));
- stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String));
- numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number));
- }
- setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
- }
-
- function resolveAnonymousTypeMembers(type: AnonymousType) {
- const symbol = type.symbol;
- if (type.target) {
- const members = createInstantiatedSymbolTable(getPropertiesOfObjectType(type.target), type.mapper, /*mappingThisOnly*/ false);
- const callSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper, instantiateSignature);
- const constructSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper, instantiateSignature);
- const stringIndexInfo = instantiateIndexInfo(getIndexInfoOfType(type.target, IndexKind.String), type.mapper);
- const numberIndexInfo = instantiateIndexInfo(getIndexInfoOfType(type.target, IndexKind.Number), type.mapper);
- setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
- }
- else if (symbol.flags & SymbolFlags.TypeLiteral) {
- const members = symbol.members;
- const callSignatures = getSignaturesOfSymbol(members["__call"]);
- const constructSignatures = getSignaturesOfSymbol(members["__new"]);
- const stringIndexInfo = getIndexInfoOfSymbol(symbol, IndexKind.String);
- const numberIndexInfo = getIndexInfoOfSymbol(symbol, IndexKind.Number);
- setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
- }
- else {
- // Combinations of function, class, enum and module
- let members = emptySymbols;
- let constructSignatures: Signature[] = emptyArray;
- if (symbol.flags & SymbolFlags.HasExports) {
- members = getExportsOfSymbol(symbol);
- }
- if (symbol.flags & SymbolFlags.Class) {
- const classType = getDeclaredTypeOfClassOrInterface(symbol);
- constructSignatures = getSignaturesOfSymbol(symbol.members["__constructor"]);
- if (!constructSignatures.length) {
- constructSignatures = getDefaultConstructSignatures(classType);
- }
- const baseConstructorType = getBaseConstructorTypeOfClass(classType);
- if (baseConstructorType.flags & TypeFlags.ObjectType) {
- members = createSymbolTable(getNamedMembers(members));
- addInheritedMembers(members, getPropertiesOfObjectType(baseConstructorType));
- }
- }
- const numberIndexInfo = symbol.flags & SymbolFlags.Enum ? enumNumberIndexInfo : undefined;
- setObjectTypeMembers(type, members, emptyArray, constructSignatures, undefined, numberIndexInfo);
- // We resolve the members before computing the signatures because a signature may use
- // typeof with a qualified name expression that circularly references the type we are
- // in the process of resolving (see issue #6072). The temporarily empty signature list
- // will never be observed because a qualified name can't reference signatures.
- if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) {
- (type).callSignatures = getSignaturesOfSymbol(symbol);
- }
- }
- }
-
- function resolveStructuredTypeMembers(type: ObjectType): ResolvedType {
- if (!(type).members) {
- if (type.flags & TypeFlags.Reference) {
- resolveTypeReferenceMembers(type);
- }
- else if (type.flags & (TypeFlags.Class | TypeFlags.Interface)) {
- resolveClassOrInterfaceMembers(type);
- }
- else if (type.flags & TypeFlags.Anonymous) {
- resolveAnonymousTypeMembers(type);
- }
- else if (type.flags & TypeFlags.Tuple) {
- resolveTupleTypeMembers(type);
- }
- else if (type.flags & TypeFlags.Union) {
- resolveUnionTypeMembers(type);
- }
- else if (type.flags & TypeFlags.Intersection) {
- resolveIntersectionTypeMembers(type);
- }
- }
- return type;
- }
-
- /** Return properties of an object type or an empty array for other types */
- function getPropertiesOfObjectType(type: Type): Symbol[] {
- if (type.flags & TypeFlags.ObjectType) {
- return resolveStructuredTypeMembers(type).properties;
- }
- return emptyArray;
- }
-
- /** If the given type is an object type and that type has a property by the given name,
- * return the symbol for that property. Otherwise return undefined. */
- function getPropertyOfObjectType(type: Type, name: string): Symbol {
- if (type.flags & TypeFlags.ObjectType) {
- const resolved = resolveStructuredTypeMembers(type);
- if (hasProperty(resolved.members, name)) {
- const symbol = resolved.members[name];
- if (symbolIsValue(symbol)) {
- return symbol;
- }
- }
- }
- }
-
- function getPropertiesOfUnionOrIntersectionType(type: UnionOrIntersectionType): Symbol[] {
- for (const current of type.types) {
- for (const prop of getPropertiesOfType(current)) {
- getPropertyOfUnionOrIntersectionType(type, prop.name);
- }
- // The properties of a union type are those that are present in all constituent types, so
- // we only need to check the properties of the first type
- if (type.flags & TypeFlags.Union) {
- break;
- }
- }
- return type.resolvedProperties ? symbolsToArray(type.resolvedProperties) : emptyArray;
- }
-
- function getPropertiesOfType(type: Type): Symbol[] {
- type = getApparentType(type);
- return type.flags & TypeFlags.UnionOrIntersection ? getPropertiesOfUnionOrIntersectionType(type) : getPropertiesOfObjectType(type);
- }
-
- /**
- * The apparent type of a type parameter is the base constraint instantiated with the type parameter
- * as the type argument for the 'this' type.
- */
- function getApparentTypeOfTypeParameter(type: TypeParameter) {
- if (!type.resolvedApparentType) {
- let constraintType = getConstraintOfTypeParameter(type);
- while (constraintType && constraintType.flags & TypeFlags.TypeParameter) {
- constraintType = getConstraintOfTypeParameter(constraintType);
- }
- type.resolvedApparentType = getTypeWithThisArgument(constraintType || emptyObjectType, type);
- }
- return type.resolvedApparentType;
- }
-
- /**
- * For a type parameter, return the base constraint of the type parameter. For the string, number,
- * boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
- * type itself. Note that the apparent type of a union type is the union type itself.
- */
- function getApparentType(type: Type): Type {
- if (type.flags & TypeFlags.TypeParameter) {
- type = getApparentTypeOfTypeParameter(type);
- }
- if (type.flags & TypeFlags.StringLike) {
- type = globalStringType;
- }
- else if (type.flags & TypeFlags.NumberLike) {
- type = globalNumberType;
- }
- else if (type.flags & TypeFlags.Boolean) {
- type = globalBooleanType;
- }
- else if (type.flags & TypeFlags.ESSymbol) {
- type = getGlobalESSymbolType();
- }
- return type;
- }
-
- function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol {
- const types = containingType.types;
- let props: Symbol[];
- // Flags we want to propagate to the result if they exist in all source symbols
- let commonFlags = (containingType.flags & TypeFlags.Intersection) ? SymbolFlags.Optional : SymbolFlags.None;
- for (const current of types) {
- const type = getApparentType(current);
- if (type !== unknownType) {
- const prop = getPropertyOfType(type, name);
- if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))) {
- commonFlags &= prop.flags;
- if (!props) {
- props = [prop];
- }
- else if (!contains(props, prop)) {
- props.push(prop);
- }
- }
- else if (containingType.flags & TypeFlags.Union) {
- // A union type requires the property to be present in all constituent types
- return undefined;
- }
- }
- }
- if (!props) {
- return undefined;
- }
- if (props.length === 1) {
- return props[0];
- }
- const propTypes: Type[] = [];
- const declarations: Declaration[] = [];
- for (const prop of props) {
- if (prop.declarations) {
- addRange(declarations, prop.declarations);
- }
- propTypes.push(getTypeOfSymbol(prop));
- }
- const result = createSymbol(
- SymbolFlags.Property |
- SymbolFlags.Transient |
- SymbolFlags.SyntheticProperty |
- commonFlags,
- name);
- result.containingType = containingType;
- result.declarations = declarations;
- result.type = containingType.flags & TypeFlags.Union ? getUnionType(propTypes) : getIntersectionType(propTypes);
- return result;
- }
-
- function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: string): Symbol {
- const properties = type.resolvedProperties || (type.resolvedProperties = {});
- if (hasProperty(properties, name)) {
- return properties[name];
- }
- const property = createUnionOrIntersectionProperty(type, name);
- if (property) {
- properties[name] = property;
- }
- return property;
- }
-
- // Return the symbol for the property with the given name in the given type. Creates synthetic union properties when
- // necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from
- // Object and Function as appropriate.
- function getPropertyOfType(type: Type, name: string): Symbol {
- type = getApparentType(type);
- if (type.flags & TypeFlags.ObjectType) {
- const resolved = resolveStructuredTypeMembers(type);
- if (hasProperty(resolved.members, name)) {
- const symbol = resolved.members[name];
- if (symbolIsValue(symbol)) {
- return symbol;
- }
- }
- if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
- const symbol = getPropertyOfObjectType(globalFunctionType, name);
- if (symbol) {
- return symbol;
- }
- }
- return getPropertyOfObjectType(globalObjectType, name);
- }
- if (type.flags & TypeFlags.UnionOrIntersection) {
- return getPropertyOfUnionOrIntersectionType(type, name);
- }
- return undefined;
- }
-
- function getSignaturesOfStructuredType(type: Type, kind: SignatureKind): Signature[] {
- if (type.flags & TypeFlags.StructuredType) {
- const resolved = resolveStructuredTypeMembers(type);
- return kind === SignatureKind.Call ? resolved.callSignatures : resolved.constructSignatures;
- }
- return emptyArray;
- }
-
- /**
- * Return the signatures of the given kind in the given type. Creates synthetic union signatures when necessary and
- * maps primitive types and type parameters are to their apparent types.
- */
- function getSignaturesOfType(type: Type, kind: SignatureKind): Signature[] {
- return getSignaturesOfStructuredType(getApparentType(type), kind);
- }
-
- function getIndexInfoOfStructuredType(type: Type, kind: IndexKind): IndexInfo {
- if (type.flags & TypeFlags.StructuredType) {
- const resolved = resolveStructuredTypeMembers(type);
- return kind === IndexKind.String ? resolved.stringIndexInfo : resolved.numberIndexInfo;
- }
- }
-
- function getIndexTypeOfStructuredType(type: Type, kind: IndexKind): Type {
- const info = getIndexInfoOfStructuredType(type, kind);
- return info && info.type;
- }
-
- // Return the indexing info of the given kind in the given type. Creates synthetic union index types when necessary and
- // maps primitive types and type parameters are to their apparent types.
- function getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo {
- return getIndexInfoOfStructuredType(getApparentType(type), kind);
- }
-
- // Return the index type of the given kind in the given type. Creates synthetic union index types when necessary and
- // maps primitive types and type parameters are to their apparent types.
- function getIndexTypeOfType(type: Type, kind: IndexKind): Type {
- return getIndexTypeOfStructuredType(getApparentType(type), kind);
- }
-
- function getImplicitIndexTypeOfType(type: Type, kind: IndexKind): Type {
- if (isObjectLiteralType(type)) {
- const propTypes: Type[] = [];
- for (const prop of getPropertiesOfType(type)) {
- if (kind === IndexKind.String || isNumericLiteralName(prop.name)) {
- propTypes.push(getTypeOfSymbol(prop));
- }
- }
- return getUnionType(propTypes);
- }
- return undefined;
- }
-
- function getTypeParametersFromJSDocTemplate(declaration: SignatureDeclaration): TypeParameter[] {
- if (declaration.flags & NodeFlags.JavaScriptFile) {
- const templateTag = getJSDocTemplateTag(declaration);
- if (templateTag) {
- return getTypeParametersFromDeclaration(templateTag.typeParameters);
- }
- }
-
- return undefined;
- }
-
- // Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual
- // type checking functions).
- function getTypeParametersFromDeclaration(typeParameterDeclarations: TypeParameterDeclaration[]): TypeParameter[] {
- const result: TypeParameter[] = [];
- forEach(typeParameterDeclarations, node => {
- const tp = getDeclaredTypeOfTypeParameter(node.symbol);
- if (!contains(result, tp)) {
- result.push(tp);
- }
- });
- return result;
- }
-
- function symbolsToArray(symbols: SymbolTable): Symbol[] {
- const result: Symbol[] = [];
- for (const id in symbols) {
- if (!isReservedMemberName(id)) {
- result.push(symbols[id]);
- }
- }
- return result;
- }
-
- function isOptionalParameter(node: ParameterDeclaration) {
- if (node.flags & NodeFlags.JavaScriptFile) {
- if (node.type && node.type.kind === SyntaxKind.JSDocOptionalType) {
- return true;
- }
-
- const paramTag = getCorrespondingJSDocParameterTag(node);
- if (paramTag) {
- if (paramTag.isBracketed) {
- return true;
- }
-
- if (paramTag.typeExpression) {
- return paramTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType;
- }
- }
- }
-
- if (hasQuestionToken(node)) {
- return true;
- }
-
- if (node.initializer) {
- const signatureDeclaration = node.parent;
- const signature = getSignatureFromDeclaration(signatureDeclaration);
- const parameterIndex = ts.indexOf(signatureDeclaration.parameters, node);
- Debug.assert(parameterIndex >= 0);
- return parameterIndex >= signature.minArgumentCount;
- }
-
- return false;
- }
-
- function createTypePredicateFromTypePredicateNode(node: TypePredicateNode): IdentifierTypePredicate | ThisTypePredicate {
- if (node.parameterName.kind === SyntaxKind.Identifier) {
- const parameterName = node.parameterName as Identifier;
- return {
- kind: TypePredicateKind.Identifier,
- parameterName: parameterName ? parameterName.text : undefined,
- parameterIndex: parameterName ? getTypePredicateParameterIndex((node.parent as SignatureDeclaration).parameters, parameterName) : undefined,
- type: getTypeFromTypeNode(node.type)
- } as IdentifierTypePredicate;
- }
- else {
- return {
- kind: TypePredicateKind.This,
- type: getTypeFromTypeNode(node.type)
- } as ThisTypePredicate;
- }
- }
-
- function getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature {
- const links = getNodeLinks(declaration);
- if (!links.resolvedSignature) {
- const classType = declaration.kind === SyntaxKind.Constructor ?
- getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent).symbol))
- : undefined;
- const typeParameters = classType ? classType.localTypeParameters :
- declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) :
- getTypeParametersFromJSDocTemplate(declaration);
- const parameters: Symbol[] = [];
- let hasStringLiterals = false;
- let minArgumentCount = -1;
- let thisType: Type = undefined;
- let hasThisParameter: boolean;
- const isJSConstructSignature = isJSDocConstructSignature(declaration);
- let returnType: Type = undefined;
- let typePredicate: TypePredicate = undefined;
-
- // If this is a JSDoc construct signature, then skip the first parameter in the
- // parameter list. The first parameter represents the return type of the construct
- // signature.
- for (let i = isJSConstructSignature ? 1 : 0, n = declaration.parameters.length; i < n; i++) {
- const param = declaration.parameters[i];
-
- let paramSymbol = param.symbol;
- // Include parameter symbol instead of property symbol in the signature
- if (paramSymbol && !!(paramSymbol.flags & SymbolFlags.Property) && !isBindingPattern(param.name)) {
- const resolvedSymbol = resolveName(param, paramSymbol.name, SymbolFlags.Value, undefined, undefined);
- paramSymbol = resolvedSymbol;
- }
- if (i === 0 && paramSymbol.name === "this") {
- hasThisParameter = true;
- thisType = param.type ? getTypeFromTypeNode(param.type) : unknownType;
- }
- else {
- parameters.push(paramSymbol);
- }
-
- if (param.type && param.type.kind === SyntaxKind.StringLiteralType) {
- hasStringLiterals = true;
- }
-
- if (param.initializer || param.questionToken || param.dotDotDotToken) {
- if (minArgumentCount < 0) {
- minArgumentCount = i - (hasThisParameter ? 1 : 0);
- }
- }
- else {
- // If we see any required parameters, it means the prior ones were not in fact optional.
- minArgumentCount = -1;
- }
- }
-
- if (minArgumentCount < 0) {
- minArgumentCount = declaration.parameters.length - (hasThisParameter ? 1 : 0);
- }
-
- if (isJSConstructSignature) {
- minArgumentCount--;
- returnType = getTypeFromTypeNode(declaration.parameters[0].type);
- }
- else if (classType) {
- returnType = classType;
- }
- else if (declaration.type) {
- returnType = getTypeFromTypeNode(declaration.type);
- if (declaration.type.kind === SyntaxKind.TypePredicate) {
- typePredicate = createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode);
- }
- }
- else {
- if (declaration.flags & NodeFlags.JavaScriptFile) {
- const type = getReturnTypeFromJSDocComment(declaration);
- if (type && type !== unknownType) {
- returnType = type;
- }
- }
-
- // TypeScript 1.0 spec (April 2014):
- // If only one accessor includes a type annotation, the other behaves as if it had the same type annotation.
- if (declaration.kind === SyntaxKind.GetAccessor && !hasDynamicName(declaration)) {
- const setter = getDeclarationOfKind(declaration.symbol, SyntaxKind.SetAccessor);
- returnType = getAnnotatedAccessorType(setter);
- }
-
- if (!returnType && nodeIsMissing((declaration).body)) {
- returnType = anyType;
- }
- }
-
- links.resolvedSignature = createSignature(declaration, typeParameters, thisType, parameters, returnType, typePredicate, minArgumentCount, hasRestParameter(declaration), hasStringLiterals);
- }
- return links.resolvedSignature;
- }
-
- function getSignaturesOfSymbol(symbol: Symbol): Signature[] {
- if (!symbol) return emptyArray;
- const result: Signature[] = [];
- for (let i = 0, len = symbol.declarations.length; i < len; i++) {
- const node = symbol.declarations[i];
- switch (node.kind) {
- case SyntaxKind.FunctionType:
- case SyntaxKind.ConstructorType:
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- case SyntaxKind.Constructor:
- case SyntaxKind.CallSignature:
- case SyntaxKind.ConstructSignature:
- case SyntaxKind.IndexSignature:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.ArrowFunction:
- case SyntaxKind.JSDocFunctionType:
- // 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).
- if (i > 0 && (node).body) {
- const previous = symbol.declarations[i - 1];
- if (node.parent === previous.parent && node.kind === previous.kind && node.pos === previous.end) {
- break;
- }
- }
- result.push(getSignatureFromDeclaration(node));
- }
- }
- return result;
- }
-
- function resolveExternalModuleTypeByLiteral(name: StringLiteral) {
- const moduleSym = resolveExternalModuleName(name, name);
- if (moduleSym) {
- const resolvedModuleSymbol = resolveExternalModuleSymbol(moduleSym);
- if (resolvedModuleSymbol) {
- return getTypeOfSymbol(resolvedModuleSymbol);
- }
- }
-
- return anyType;
- }
-
- function getReturnTypeOfSignature(signature: Signature): Type {
- if (!signature.resolvedReturnType) {
- if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) {
- return unknownType;
- }
- let type: Type;
- if (signature.target) {
- type = instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper);
- }
- else if (signature.unionSignatures) {
- type = getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature));
- }
- else {
- type = getReturnTypeFromBody(signature.declaration);
- }
- if (!popTypeResolution()) {
- type = anyType;
- if (compilerOptions.noImplicitAny) {
- const declaration = signature.declaration;
- if (declaration.name) {
- error(declaration.name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, declarationNameToString(declaration.name));
- }
- else {
- error(declaration, Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions);
- }
- }
- }
- signature.resolvedReturnType = type;
- }
- return signature.resolvedReturnType;
- }
-
- function getRestTypeOfSignature(signature: Signature): Type {
- if (signature.hasRestParameter) {
- const type = getTypeOfSymbol(lastOrUndefined(signature.parameters));
- if (type.flags & TypeFlags.Reference && (type).target === globalArrayType) {
- return (type).typeArguments[0];
- }
- }
- return anyType;
- }
-
- function getSignatureInstantiation(signature: Signature, typeArguments: Type[]): Signature {
- return instantiateSignature(signature, createTypeMapper(signature.typeParameters, typeArguments), /*eraseTypeParameters*/ true);
- }
-
- function getErasedSignature(signature: Signature): Signature {
- if (!signature.typeParameters) return signature;
- if (!signature.erasedSignatureCache) {
- if (signature.target) {
- signature.erasedSignatureCache = instantiateSignature(getErasedSignature(signature.target), signature.mapper);
- }
- else {
- signature.erasedSignatureCache = instantiateSignature(signature, createTypeEraser(signature.typeParameters), /*eraseTypeParameters*/ true);
- }
- }
- return signature.erasedSignatureCache;
- }
-
- function getOrCreateTypeFromSignature(signature: Signature): ObjectType {
- // There are two ways to declare a construct signature, one is by declaring a class constructor
- // using the constructor keyword, and the other is declaring a bare construct signature in an
- // object type literal or interface (using the new keyword). Each way of declaring a constructor
- // will result in a different declaration kind.
- if (!signature.isolatedSignatureType) {
- const isConstructor = signature.declaration.kind === SyntaxKind.Constructor || signature.declaration.kind === SyntaxKind.ConstructSignature;
- const type = createObjectType(TypeFlags.Anonymous | TypeFlags.FromSignature);
- type.members = emptySymbols;
- type.properties = emptyArray;
- type.callSignatures = !isConstructor ? [signature] : emptyArray;
- type.constructSignatures = isConstructor ? [signature] : emptyArray;
- signature.isolatedSignatureType = type;
- }
-
- return signature.isolatedSignatureType;
- }
-
- function getIndexSymbol(symbol: Symbol): Symbol {
- return symbol.members["__index"];
- }
-
- function getIndexDeclarationOfSymbol(symbol: Symbol, kind: IndexKind): SignatureDeclaration {
- const syntaxKind = kind === IndexKind.Number ? SyntaxKind.NumberKeyword : SyntaxKind.StringKeyword;
- const indexSymbol = getIndexSymbol(symbol);
- if (indexSymbol) {
- for (const decl of indexSymbol.declarations) {
- const node = decl;
- if (node.parameters.length === 1) {
- const parameter = node.parameters[0];
- if (parameter && parameter.type && parameter.type.kind === syntaxKind) {
- return node;
- }
- }
- }
- }
-
- return undefined;
- }
-
- function createIndexInfo(type: Type, isReadonly: boolean, declaration?: SignatureDeclaration): IndexInfo {
- return { type, isReadonly, declaration };
- }
-
- function getIndexInfoOfSymbol(symbol: Symbol, kind: IndexKind): IndexInfo {
- const declaration = getIndexDeclarationOfSymbol(symbol, kind);
- if (declaration) {
- return createIndexInfo(declaration.type ? getTypeFromTypeNode(declaration.type) : anyType,
- (getModifierFlags(declaration) & ModifierFlags.Readonly) !== 0, declaration);
- }
- return undefined;
- }
-
- function getConstraintDeclaration(type: TypeParameter) {
- return (getDeclarationOfKind(type.symbol, SyntaxKind.TypeParameter)).constraint;
- }
-
- function hasConstraintReferenceTo(type: Type, target: TypeParameter): boolean {
- let checked: Type[];
- while (type && !(type.flags & TypeFlags.ThisType) && type.flags & TypeFlags.TypeParameter && !contains(checked, type)) {
- if (type === target) {
- return true;
- }
- (checked || (checked = [])).push(type);
- const constraintDeclaration = getConstraintDeclaration(type);
- type = constraintDeclaration && getTypeFromTypeNode(constraintDeclaration);
- }
- return false;
- }
-
- function getConstraintOfTypeParameter(typeParameter: TypeParameter): Type {
- if (!typeParameter.constraint) {
- if (typeParameter.target) {
- const targetConstraint = getConstraintOfTypeParameter(typeParameter.target);
- typeParameter.constraint = targetConstraint ? instantiateType(targetConstraint, typeParameter.mapper) : noConstraintType;
- }
- else {
- const constraintDeclaration = getConstraintDeclaration(typeParameter);
- let constraint = getTypeFromTypeNode(constraintDeclaration);
- if (hasConstraintReferenceTo(constraint, typeParameter)) {
- error(constraintDeclaration, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(typeParameter));
- constraint = unknownType;
- }
- typeParameter.constraint = constraint;
- }
- }
- return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint;
- }
-
- function getParentSymbolOfTypeParameter(typeParameter: TypeParameter): Symbol {
- return getSymbolOfNode(getDeclarationOfKind(typeParameter.symbol, SyntaxKind.TypeParameter).parent);
- }
-
- function getTypeListId(types: Type[]) {
- if (types) {
- switch (types.length) {
- case 1:
- return "" + types[0].id;
- case 2:
- return types[0].id + "," + types[1].id;
- default:
- let result = "";
- for (let i = 0; i < types.length; i++) {
- if (i > 0) {
- result += ",";
- }
- result += types[i].id;
- }
- return result;
- }
- }
- return "";
- }
-
- // This function is used to propagate certain flags when creating new object type references and union types.
- // It is only necessary to do so if a constituent type might be the undefined type, the null type, the type
- // of an object literal or the anyFunctionType. This is because there are operations in the type checker
- // that care about the presence of such types at arbitrary depth in a containing type.
- function getPropagatingFlagsOfTypes(types: Type[], excludeKinds: TypeFlags): TypeFlags {
- let result: TypeFlags = 0;
- for (const type of types) {
- if (!(type.flags & excludeKinds)) {
- result |= type.flags;
- }
- }
- return result & TypeFlags.PropagatingFlags;
- }
-
- function createTypeReference(target: GenericType, typeArguments: Type[]): TypeReference {
- const id = getTypeListId(typeArguments);
- let type = target.instantiations[id];
- if (!type) {
- const propagatedFlags = typeArguments ? getPropagatingFlagsOfTypes(typeArguments, /*excludeKinds*/ 0) : 0;
- const flags = TypeFlags.Reference | propagatedFlags;
- type = target.instantiations[id] = createObjectType(flags, target.symbol);
- type.target = target;
- type.typeArguments = typeArguments;
- }
- return type;
- }
-
- // Get type from reference to class or interface
- function getTypeFromClassOrInterfaceReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol): Type {
- const type = getDeclaredTypeOfSymbol(getMergedSymbol(symbol));
- const typeParameters = type.localTypeParameters;
- if (typeParameters) {
- if (!node.typeArguments || node.typeArguments.length !== typeParameters.length) {
- error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length);
- return unknownType;
- }
- // In a type reference, the outer type parameters of the referenced class or interface are automatically
- // supplied as type arguments and the type reference only specifies arguments for the local type parameters
- // of the class or interface.
- return createTypeReference(type, concatenate(type.outerTypeParameters, map(node.typeArguments, getTypeFromTypeNode)));
- }
- if (node.typeArguments) {
- error(node, Diagnostics.Type_0_is_not_generic, typeToString(type));
- return unknownType;
- }
- return type;
- }
-
- // Get type from reference to type alias. When a type alias is generic, the declared type of the type alias may include
- // references to the type parameters of the alias. We replace those with the actual type arguments by instantiating the
- // declared type. Instantiations are cached using the type identities of the type arguments as the key.
- function getTypeFromTypeAliasReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol): Type {
- const type = getDeclaredTypeOfSymbol(symbol);
- const links = getSymbolLinks(symbol);
- const typeParameters = links.typeParameters;
- if (typeParameters) {
- if (!node.typeArguments || node.typeArguments.length !== typeParameters.length) {
- error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, symbolToString(symbol), typeParameters.length);
- return unknownType;
- }
- const typeArguments = map(node.typeArguments, getTypeFromTypeNode);
- const id = getTypeListId(typeArguments);
- return links.instantiations[id] || (links.instantiations[id] = instantiateType(type, createTypeMapper(typeParameters, typeArguments)));
- }
- if (node.typeArguments) {
- error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol));
- return unknownType;
- }
- return type;
- }
-
- // Get type from reference to named type that cannot be generic (enum or type parameter)
- function getTypeFromNonGenericTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol): Type {
- if (node.typeArguments) {
- error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol));
- return unknownType;
- }
- return getDeclaredTypeOfSymbol(symbol);
- }
-
- function getTypeReferenceName(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference): LeftHandSideExpression | EntityName {
- switch (node.kind) {
- case SyntaxKind.TypeReference:
- return (node).typeName;
- case SyntaxKind.JSDocTypeReference:
- return (node).name;
- case SyntaxKind.ExpressionWithTypeArguments:
- // We only support expressions that are simple qualified names. For other
- // expressions this produces undefined.
- if (isSupportedExpressionWithTypeArguments(node)) {
- return (node).expression;
- }
-
- // fall through;
- }
-
- return undefined;
- }
-
- function resolveTypeReferenceName(
- node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference,
- typeReferenceName: LeftHandSideExpression | EntityName) {
-
- if (!typeReferenceName) {
- return unknownSymbol;
- }
-
- return resolveEntityName(typeReferenceName, SymbolFlags.Type) || unknownSymbol;
- }
-
- function getTypeReferenceType(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol) {
- if (symbol === unknownSymbol) {
- return unknownType;
- }
-
- if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
- return getTypeFromClassOrInterfaceReference(node, symbol);
- }
-
- if (symbol.flags & SymbolFlags.TypeAlias) {
- return getTypeFromTypeAliasReference(node, symbol);
- }
-
- if (symbol.flags & SymbolFlags.Value && node.kind === SyntaxKind.JSDocTypeReference) {
- // A JSDocTypeReference may have resolved to a value (as opposed to a type). In
- // that case, the type of this reference is just the type of the value we resolved
- // to.
- return getTypeOfSymbol(symbol);
- }
-
- return getTypeFromNonGenericTypeReference(node, symbol);
- }
-
- function getTypeFromTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference): Type {
- const links = getNodeLinks(node);
- if (!links.resolvedType) {
- let symbol: Symbol;
- let type: Type;
- if (node.kind === SyntaxKind.JSDocTypeReference) {
- const typeReferenceName = getTypeReferenceName(node);
- symbol = resolveTypeReferenceName(node, typeReferenceName);
- type = getTypeReferenceType(node, symbol);
-
- links.resolvedSymbol = symbol;
- links.resolvedType = type;
- }
- else {
- // We only support expressions that are simple qualified names. For other expressions this produces undefined.
- const typeNameOrExpression = node.kind === SyntaxKind.TypeReference ? (node).typeName :
- isSupportedExpressionWithTypeArguments(node) ? (node).expression :
- undefined;
- symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol;
- type = symbol === unknownSymbol ? unknownType :
- symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? getTypeFromClassOrInterfaceReference(node, symbol) :
- symbol.flags & SymbolFlags.TypeAlias ? getTypeFromTypeAliasReference(node, symbol) :
- getTypeFromNonGenericTypeReference(node, symbol);
- }
- // Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the
- // type reference in checkTypeReferenceOrExpressionWithTypeArguments.
- links.resolvedSymbol = symbol;
- links.resolvedType = type;
- }
- return links.resolvedType;
- }
-
- function getTypeFromTypeQueryNode(node: TypeQueryNode): Type {
- const links = getNodeLinks(node);
- if (!links.resolvedType) {
- // TypeScript 1.0 spec (April 2014): 3.6.3
- // The expression is processed as an identifier expression (section 4.3)
- // or property access expression(section 4.10),
- // the widened type(section 3.9) of which becomes the result.
- links.resolvedType = getWidenedType(checkExpression(node.exprName));
- }
- return links.resolvedType;
- }
-
- function getTypeOfGlobalSymbol(symbol: Symbol, arity: number): ObjectType {
-
- function getTypeDeclaration(symbol: Symbol): Declaration {
- const declarations = symbol.declarations;
- for (const declaration of declarations) {
- switch (declaration.kind) {
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.InterfaceDeclaration:
- case SyntaxKind.EnumDeclaration:
- return declaration;
- }
- }
- }
-
- if (!symbol) {
- return arity ? emptyGenericType : emptyObjectType;
- }
- const type = getDeclaredTypeOfSymbol(symbol);
- if (!(type.flags & TypeFlags.ObjectType)) {
- error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_be_a_class_or_interface_type, symbol.name);
- return arity ? emptyGenericType : emptyObjectType;
- }
- if (((type).typeParameters ? (type).typeParameters.length : 0) !== arity) {
- error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbol.name, arity);
- return arity ? emptyGenericType : emptyObjectType;
- }
- return type;
- }
-
- function getGlobalValueSymbol(name: string): Symbol {
- return getGlobalSymbol(name, SymbolFlags.Value, Diagnostics.Cannot_find_global_value_0);
- }
-
- function getGlobalTypeSymbol(name: string): Symbol {
- return getGlobalSymbol(name, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0);
- }
-
- function getGlobalSymbol(name: string, meaning: SymbolFlags, diagnostic: DiagnosticMessage): Symbol {
- return resolveName(undefined, name, meaning, diagnostic, name);
- }
-
- function getGlobalType(name: string, arity = 0): ObjectType {
- return getTypeOfGlobalSymbol(getGlobalTypeSymbol(name), arity);
- }
-
- /**
- * Returns a type that is inside a namespace at the global scope, e.g.
- * getExportedTypeFromNamespace('JSX', 'Element') returns the JSX.Element type
- */
- function getExportedTypeFromNamespace(namespace: string, name: string): Type {
- const namespaceSymbol = getGlobalSymbol(namespace, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined);
- const typeSymbol = namespaceSymbol && getSymbol(namespaceSymbol.exports, name, SymbolFlags.Type);
- return typeSymbol && getDeclaredTypeOfSymbol(typeSymbol);
- }
-
- /**
- * Creates a TypeReference for a generic `TypedPropertyDescriptor`.
- */
- function createTypedPropertyDescriptorType(propertyType: Type): Type {
- const globalTypedPropertyDescriptorType = getGlobalTypedPropertyDescriptorType();
- return globalTypedPropertyDescriptorType !== emptyGenericType
- ? createTypeReference(globalTypedPropertyDescriptorType, [propertyType])
- : emptyObjectType;
- }
-
- /**
- * Instantiates a global type that is generic with some element type, and returns that instantiation.
- */
- function createTypeFromGenericGlobalType(genericGlobalType: GenericType, typeArguments: Type[]): Type {
- return genericGlobalType !== emptyGenericType ? createTypeReference(genericGlobalType, typeArguments) : emptyObjectType;
- }
-
- function createIterableType(elementType: Type): Type {
- return createTypeFromGenericGlobalType(getGlobalIterableType(), [elementType]);
- }
-
- function createIterableIteratorType(elementType: Type): Type {
- return createTypeFromGenericGlobalType(getGlobalIterableIteratorType(), [elementType]);
- }
-
- function createArrayType(elementType: Type): Type {
- return createTypeFromGenericGlobalType(globalArrayType, [elementType]);
- }
-
- function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type {
- const links = getNodeLinks(node);
- if (!links.resolvedType) {
- links.resolvedType = createArrayType(getTypeFromTypeNode(node.elementType));
- }
- return links.resolvedType;
- }
-
- function createTupleType(elementTypes: Type[]) {
- const id = getTypeListId(elementTypes);
- return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes));
- }
-
- function createNewTupleType(elementTypes: Type[]) {
- const propagatedFlags = getPropagatingFlagsOfTypes(elementTypes, /*excludeKinds*/ 0);
- const type = createObjectType(TypeFlags.Tuple | propagatedFlags);
- type.elementTypes = elementTypes;
- return type;
- }
-
- function getTypeFromTupleTypeNode(node: TupleTypeNode): Type {
- const links = getNodeLinks(node);
- if (!links.resolvedType) {
- links.resolvedType = createTupleType(map(node.elementTypes, getTypeFromTypeNode));
- }
- return links.resolvedType;
- }
-
- interface TypeSet extends Array {
- containsAny?: boolean;
- containsUndefined?: boolean;
- containsNull?: boolean;
- }
-
- function addTypeToSet(typeSet: TypeSet, type: Type, typeSetKind: TypeFlags) {
- if (type.flags & typeSetKind) {
- addTypesToSet(typeSet, (type).types, typeSetKind);
- }
- else if (type.flags & (TypeFlags.Any | TypeFlags.Undefined | TypeFlags.Null)) {
- if (type.flags & TypeFlags.Any) typeSet.containsAny = true;
- if (type.flags & TypeFlags.Undefined) typeSet.containsUndefined = true;
- if (type.flags & TypeFlags.Null) typeSet.containsNull = true;
- }
- else if (!contains(typeSet, type)) {
- typeSet.push(type);
- }
- }
-
- // Add the given types to the given type set. Order is preserved, duplicates are removed,
- // and nested types of the given kind are flattened into the set.
- function addTypesToSet(typeSet: TypeSet, types: Type[], typeSetKind: TypeFlags) {
- for (const type of types) {
- addTypeToSet(typeSet, type, typeSetKind);
- }
- }
-
- function isSubtypeOfAny(candidate: Type, types: Type[]): boolean {
- for (let i = 0, len = types.length; i < len; i++) {
- if (candidate !== types[i] && isTypeSubtypeOf(candidate, types[i])) {
- return true;
- }
- }
- return false;
- }
-
- function removeSubtypes(types: Type[]) {
- let i = types.length;
- while (i > 0) {
- i--;
- if (isSubtypeOfAny(types[i], types)) {
- types.splice(i, 1);
- }
- }
- }
-
- // We reduce the constituent type set to only include types that aren't subtypes of other types, unless
- // the noSubtypeReduction flag is specified, in which case we perform a simple deduplication based on
- // object identity. Subtype reduction is possible only when union types are known not to circularly
- // reference themselves (as is the case with union types created by expression constructs such as array
- // literals and the || and ?: operators). Named types can circularly reference themselves and therefore
- // cannot be deduplicated during their declaration. For example, "type Item = string | (() => Item" is
- // a named type that circularly references itself.
- function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type {
- if (types.length === 0) {
- return emptyUnionType;
- }
- const typeSet = [] as TypeSet;
- addTypesToSet(typeSet, types, TypeFlags.Union);
- if (typeSet.containsAny) {
- return anyType;
- }
- if (strictNullChecks) {
- if (typeSet.containsNull) typeSet.push(nullType);
- if (typeSet.containsUndefined) typeSet.push(undefinedType);
- }
- if (!noSubtypeReduction) {
- removeSubtypes(typeSet);
- }
- if (typeSet.length === 0) {
- return typeSet.containsNull ? nullType : undefinedType;
- }
- else if (typeSet.length === 1) {
- return typeSet[0];
- }
- const id = getTypeListId(typeSet);
- let type = unionTypes[id];
- if (!type) {
- const propagatedFlags = getPropagatingFlagsOfTypes(typeSet, /*excludeKinds*/ TypeFlags.Nullable);
- type = unionTypes[id] = createObjectType(TypeFlags.Union | propagatedFlags);
- type.types = typeSet;
- }
- return type;
- }
-
- function getTypeFromUnionTypeNode(node: UnionTypeNode): Type {
- const links = getNodeLinks(node);
- if (!links.resolvedType) {
- links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), /*noSubtypeReduction*/ true);
- }
- return links.resolvedType;
- }
-
- // We do not perform structural deduplication on intersection types. Intersection types are created only by the &
- // type operator and we can't reduce those because we want to support recursive intersection types. For example,
- // a type alias of the form "type List = T & { next: List }" cannot be reduced during its declaration.
- // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution
- // for intersections of types with signatures can be deterministic.
- function getIntersectionType(types: Type[]): Type {
- if (types.length === 0) {
- return emptyObjectType;
- }
- const typeSet = [] as TypeSet;
- addTypesToSet(typeSet, types, TypeFlags.Intersection);
- if (typeSet.containsAny) {
- return anyType;
- }
- if (strictNullChecks) {
- if (typeSet.containsNull) typeSet.push(nullType);
- if (typeSet.containsUndefined) typeSet.push(undefinedType);
- }
- if (typeSet.length === 1) {
- return typeSet[0];
- }
- const id = getTypeListId(typeSet);
- let type = intersectionTypes[id];
- if (!type) {
- const propagatedFlags = getPropagatingFlagsOfTypes(typeSet, /*excludeKinds*/ TypeFlags.Nullable);
- type = intersectionTypes[id] = createObjectType(TypeFlags.Intersection | propagatedFlags);
- type.types = typeSet;
- }
- return type;
- }
-
- function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type {
- const links = getNodeLinks(node);
- if (!links.resolvedType) {
- links.resolvedType = getIntersectionType(map(node.types, getTypeFromTypeNode));
- }
- return links.resolvedType;
- }
-
- function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node): Type {
- const links = getNodeLinks(node);
- if (!links.resolvedType) {
- // Deferred resolution of members is handled by resolveObjectTypeMembers
- links.resolvedType = createObjectType(TypeFlags.Anonymous, node.symbol);
- }
- return links.resolvedType;
- }
-
- function getStringLiteralTypeForText(text: string): StringLiteralType {
- if (hasProperty(stringLiteralTypes, text)) {
- return stringLiteralTypes[text];
- }
-
- const type = stringLiteralTypes[text] = createType(TypeFlags.StringLiteral);
- type.text = text;
- return type;
- }
-
- function getTypeFromStringLiteralTypeNode(node: StringLiteralTypeNode): Type {
- const links = getNodeLinks(node);
- if (!links.resolvedType) {
- links.resolvedType = getStringLiteralTypeForText(node.text);
- }
- return links.resolvedType;
- }
-
- function getTypeFromJSDocVariadicType(node: JSDocVariadicType): Type {
- const links = getNodeLinks(node);
- if (!links.resolvedType) {
- const type = getTypeFromTypeNode(node.type);
- links.resolvedType = type ? createArrayType(type) : unknownType;
- }
- return links.resolvedType;
- }
-
- function getTypeFromJSDocTupleType(node: JSDocTupleType): Type {
- const links = getNodeLinks(node);
- if (!links.resolvedType) {
- const types = map(node.types, getTypeFromTypeNode);
- links.resolvedType = createTupleType(types);
- }
- return links.resolvedType;
- }
-
- function getThisType(node: Node): Type {
- const container = getThisContainer(node, /*includeArrowFunctions*/ false);
- const parent = container && container.parent;
- if (parent && (isClassLike(parent) || parent.kind === SyntaxKind.InterfaceDeclaration)) {
- if (!(getModifierFlags(container) & ModifierFlags.Static) &&
- (container.kind !== SyntaxKind.Constructor || isNodeDescendantOf(node, (container).body))) {
- return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent)).thisType;
- }
- }
- error(node, Diagnostics.A_this_type_is_available_only_in_a_non_static_member_of_a_class_or_interface);
- return unknownType;
- }
-
- function getTypeFromThisTypeNode(node: TypeNode): Type {
- const links = getNodeLinks(node);
- if (!links.resolvedType) {
- links.resolvedType = getThisType(node);
- }
- return links.resolvedType;
- }
-
- function getTypeFromTypeNode(node: TypeNode): Type {
- switch (node.kind) {
- case SyntaxKind.AnyKeyword:
- case SyntaxKind.JSDocAllType:
- case SyntaxKind.JSDocUnknownType:
- return anyType;
- case SyntaxKind.StringKeyword:
- return stringType;
- case SyntaxKind.NumberKeyword:
- return numberType;
- case SyntaxKind.BooleanKeyword:
- return booleanType;
- case SyntaxKind.SymbolKeyword:
- return esSymbolType;
- case SyntaxKind.VoidKeyword:
- return voidType;
- case SyntaxKind.UndefinedKeyword:
- return undefinedType;
- case SyntaxKind.NullKeyword:
- return nullType;
- case SyntaxKind.ThisType:
- return getTypeFromThisTypeNode(node);
- case SyntaxKind.StringLiteralType:
- return getTypeFromStringLiteralTypeNode(node);
- case SyntaxKind.TypeReference:
- case SyntaxKind.JSDocTypeReference:
- return getTypeFromTypeReference(node);
- case SyntaxKind.TypePredicate:
- return booleanType;
- case SyntaxKind.ExpressionWithTypeArguments:
- return getTypeFromTypeReference(node);
- case SyntaxKind.TypeQuery:
- return getTypeFromTypeQueryNode(node);
- case SyntaxKind.ArrayType:
- case SyntaxKind.JSDocArrayType:
- return getTypeFromArrayTypeNode(node);
- case SyntaxKind.TupleType:
- return getTypeFromTupleTypeNode(node);
- case SyntaxKind.UnionType:
- case SyntaxKind.JSDocUnionType:
- return getTypeFromUnionTypeNode(node);
- case SyntaxKind.IntersectionType:
- return getTypeFromIntersectionTypeNode(node);
- case SyntaxKind.ParenthesizedType:
- case SyntaxKind.JSDocNullableType:
- case SyntaxKind.JSDocNonNullableType:
- case SyntaxKind.JSDocConstructorType:
- case SyntaxKind.JSDocThisType:
- case SyntaxKind.JSDocOptionalType:
- return getTypeFromTypeNode((node).type);
- case SyntaxKind.FunctionType:
- case SyntaxKind.ConstructorType:
- case SyntaxKind.TypeLiteral:
- case SyntaxKind.JSDocFunctionType:
- case SyntaxKind.JSDocRecordType:
- return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
- // This function assumes that an identifier or qualified name is a type expression
- // Callers should first ensure this by calling isPartOfTypeNode
- case SyntaxKind.Identifier:
- case SyntaxKind.QualifiedName:
- const symbol = getSymbolAtLocation(node);
- return symbol && getDeclaredTypeOfSymbol(symbol);
- case SyntaxKind.JSDocTupleType:
- return getTypeFromJSDocTupleType(node);
- case SyntaxKind.JSDocVariadicType:
- return getTypeFromJSDocVariadicType(node);
- default:
- return unknownType;
- }
- }
-
- function instantiateList(items: T[], mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): T[] {
- if (items && items.length) {
- const result: T[] = [];
- for (const v of items) {
- result.push(instantiator(v, mapper));
- }
- return result;
- }
- return items;
- }
-
- function createUnaryTypeMapper(source: Type, target: Type): TypeMapper {
- return t => t === source ? target : t;
- }
-
- function createBinaryTypeMapper(source1: Type, target1: Type, source2: Type, target2: Type): TypeMapper {
- return t => t === source1 ? target1 : t === source2 ? target2 : t;
- }
-
- function createArrayTypeMapper(sources: Type[], targets: Type[]): TypeMapper {
- return t => {
- for (let i = 0; i < sources.length; i++) {
- if (t === sources[i]) {
- return targets ? targets[i] : anyType;
- }
- }
- return t;
- };
- }
-
- function createTypeMapper(sources: Type[], targets: Type[]): TypeMapper {
- const count = sources.length;
- const mapper: TypeMapper =
- count == 1 ? createUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) :
- count == 2 ? createBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) :
- createArrayTypeMapper(sources, targets);
- mapper.mappedTypes = sources;
- return mapper;
- }
-
- function createTypeEraser(sources: Type[]): TypeMapper {
- return createTypeMapper(sources, undefined);
- }
-
- function getInferenceMapper(context: InferenceContext): TypeMapper {
- if (!context.mapper) {
- const mapper: TypeMapper = t => {
- const typeParameters = context.typeParameters;
- for (let i = 0; i < typeParameters.length; i++) {
- if (t === typeParameters[i]) {
- context.inferences[i].isFixed = true;
- return getInferredType(context, i);
- }
- }
- return t;
- };
- mapper.mappedTypes = context.typeParameters;
- mapper.context = context;
- context.mapper = mapper;
- }
- return context.mapper;
- }
-
- function identityMapper(type: Type): Type {
- return type;
- }
-
- function combineTypeMappers(mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper {
- const mapper: TypeMapper = t => instantiateType(mapper1(t), mapper2);
- mapper.mappedTypes = mapper1.mappedTypes;
- return mapper;
- }
-
- function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
- const result = createType(TypeFlags.TypeParameter);
- result.symbol = typeParameter.symbol;
- result.target = typeParameter;
- return result;
- }
-
- function cloneTypePredicate(predicate: TypePredicate, mapper: TypeMapper): ThisTypePredicate | IdentifierTypePredicate {
- if (isIdentifierTypePredicate(predicate)) {
- return {
- kind: TypePredicateKind.Identifier,
- parameterName: predicate.parameterName,
- parameterIndex: predicate.parameterIndex,
- type: instantiateType(predicate.type, mapper)
- } as IdentifierTypePredicate;
- }
- else {
- return {
- kind: TypePredicateKind.This,
- type: instantiateType(predicate.type, mapper)
- } as ThisTypePredicate;
- }
- }
-
- function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature {
- let freshTypeParameters: TypeParameter[];
- let freshTypePredicate: TypePredicate;
- if (signature.typeParameters && !eraseTypeParameters) {
- // First create a fresh set of type parameters, then include a mapping from the old to the
- // new type parameters in the mapper function. Finally store this mapper in the new type
- // parameters such that we can use it when instantiating constraints.
- freshTypeParameters = map(signature.typeParameters, cloneTypeParameter);
- mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper);
- for (const tp of freshTypeParameters) {
- tp.mapper = mapper;
- }
- }
- if (signature.typePredicate) {
- freshTypePredicate = cloneTypePredicate(signature.typePredicate, mapper);
- }
- const result = createSignature(signature.declaration, freshTypeParameters,
- signature.thisType && instantiateType(signature.thisType, mapper),
- instantiateList(signature.parameters, mapper, instantiateSymbol),
- instantiateType(signature.resolvedReturnType, mapper),
- freshTypePredicate,
- signature.minArgumentCount, signature.hasRestParameter, signature.hasStringLiterals);
- result.target = signature;
- result.mapper = mapper;
- return result;
- }
-
- function instantiateSymbol(symbol: Symbol, mapper: TypeMapper): Symbol {
- if (symbol.flags & SymbolFlags.Instantiated) {
- const links = getSymbolLinks(symbol);
- // If symbol being instantiated is itself a instantiation, fetch the original target and combine the
- // type mappers. This ensures that original type identities are properly preserved and that aliases
- // always reference a non-aliases.
- symbol = links.target;
- mapper = combineTypeMappers(links.mapper, mapper);
- }
-
- // Keep the flags from the symbol we're instantiating. Mark that is instantiated, and
- // also transient so that we can just store data on it directly.
- const result = createSymbol(SymbolFlags.Instantiated | SymbolFlags.Transient | symbol.flags, symbol.name);
- result.declarations = symbol.declarations;
- result.parent = symbol.parent;
- result.target = symbol;
- result.mapper = mapper;
- if (symbol.valueDeclaration) {
- result.valueDeclaration = symbol.valueDeclaration;
- }
-
- return result;
- }
-
- function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper): ObjectType {
- if (mapper.instantiations) {
- const cachedType = mapper.instantiations[type.id];
- if (cachedType) {
- return cachedType;
- }
- }
- else {
- mapper.instantiations = [];
- }
- // Mark the anonymous type as instantiated such that our infinite instantiation detection logic can recognize it
- const result =