diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 825570c2eb922..dc28ab3811258 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -1,9112 +1,9204 @@
-///
-///
-///
-///
-///
-///
-
-module ts {
- var nextSymbolId = 1;
- var nextNodeId = 1;
- var nextMergeId = 1;
-
- export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration {
- var declarations = symbol.declarations;
- for (var i = 0; i < declarations.length; i++) {
- var declaration = declarations[i];
- if (declaration.kind === kind) {
- return declaration;
- }
- }
-
- return undefined;
- }
-
- export interface StringSymbolWriter extends SymbolWriter {
- string(): string;
- }
-
- // Pool writers to avoid needing to allocate them for every symbol we write.
- var stringWriters: StringSymbolWriter[] = [];
- export function getSingleLineStringWriter(): StringSymbolWriter {
- if (stringWriters.length == 0) {
- var str = "";
-
- var writeText: (text: string) => void = text => str += text;
- return {
- string: () => str,
- writeKeyword: writeText,
- writeOperator: writeText,
- writePunctuation: writeText,
- writeSpace: writeText,
- writeStringLiteral: writeText,
- writeParameter: writeText,
- writeSymbol: writeText,
-
- // Completely ignore indentation for string writers. And map newlines to
- // a single space.
- writeLine: () => str += " ",
- increaseIndent: () => { },
- decreaseIndent: () => { },
- clear: () => str = "",
- trackSymbol: () => { }
- };
- }
-
- return stringWriters.pop();
- }
-
- /// fullTypeCheck denotes if this instance of the typechecker will be used to get semantic diagnostics.
- /// If fullTypeCheck === true, then the typechecker should do every possible check to produce all errors
- /// If fullTypeCheck === false, the typechecker can take shortcuts and skip checks that only produce errors.
- /// NOTE: checks that somehow affect decisions being made during typechecking should be executed in both cases.
- export function createTypeChecker(program: Program, fullTypeCheck: boolean): TypeChecker {
-
- var Symbol = objectAllocator.getSymbolConstructor();
- var Type = objectAllocator.getTypeConstructor();
- var Signature = objectAllocator.getSignatureConstructor();
-
- var typeCount = 0;
-
- var emptyArray: any[] = [];
- var emptySymbols: SymbolTable = {};
-
- var compilerOptions = program.getCompilerOptions();
-
- var checker: TypeChecker = {
- getProgram: () => program,
- getDiagnostics: getDiagnostics,
- getGlobalDiagnostics: getGlobalDiagnostics,
- getNodeCount: () => sum(program.getSourceFiles(), "nodeCount"),
- getIdentifierCount: () => sum(program.getSourceFiles(), "identifierCount"),
- getSymbolCount: () => sum(program.getSourceFiles(), "symbolCount"),
- getTypeCount: () => typeCount,
- checkProgram: checkProgram,
- emitFiles: invokeEmitter,
- getParentOfSymbol: getParentOfSymbol,
- getNarrowedTypeOfSymbol: getNarrowedTypeOfSymbol,
- getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol,
- getPropertiesOfType: getPropertiesOfType,
- getPropertyOfType: getPropertyOfType,
- getSignaturesOfType: getSignaturesOfType,
- getIndexTypeOfType: getIndexTypeOfType,
- getReturnTypeOfSignature: getReturnTypeOfSignature,
- getSymbolsInScope: getSymbolsInScope,
- getSymbolInfo: getSymbolInfo,
- getTypeOfNode: getTypeOfNode,
- typeToString: typeToString,
- getSymbolDisplayBuilder: getSymbolDisplayBuilder,
- symbolToString: symbolToString,
- getAugmentedPropertiesOfType: getAugmentedPropertiesOfType,
- getRootSymbols: getRootSymbols,
- getContextualType: getContextualType,
- getFullyQualifiedName: getFullyQualifiedName,
- getResolvedSignature: getResolvedSignature,
- getEnumMemberValue: getEnumMemberValue,
- isValidPropertyAccess: isValidPropertyAccess,
- getSignatureFromDeclaration: getSignatureFromDeclaration,
- isImplementationOfOverload: isImplementationOfOverload,
- getAliasedSymbol: resolveImport,
- isUndefinedSymbol: symbol => symbol === undefinedSymbol,
- isArgumentsSymbol: symbol => symbol === argumentsSymbol,
- hasEarlyErrors: hasEarlyErrors
- };
-
- var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
- var argumentsSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "arguments");
- var unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown");
- var resolvingSymbol = createSymbol(SymbolFlags.Transient, "__resolving__");
-
- var anyType = createIntrinsicType(TypeFlags.Any, "any");
- var stringType = createIntrinsicType(TypeFlags.String, "string");
- var numberType = createIntrinsicType(TypeFlags.Number, "number");
- var booleanType = createIntrinsicType(TypeFlags.Boolean, "boolean");
- var voidType = createIntrinsicType(TypeFlags.Void, "void");
- var undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
- var nullType = createIntrinsicType(TypeFlags.Null, "null");
- var unknownType = createIntrinsicType(TypeFlags.Any, "unknown");
- var resolvingType = createIntrinsicType(TypeFlags.Any, "__resolving__");
-
- var emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
- var anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
- var noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
- var inferenceFailureType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
-
- var anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, false, false);
- var unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, false, false);
-
- var globals: SymbolTable = {};
-
- var globalArraySymbol: Symbol;
-
- var globalObjectType: ObjectType;
- var globalFunctionType: ObjectType;
- var globalArrayType: ObjectType;
- var globalStringType: ObjectType;
- var globalNumberType: ObjectType;
- var globalBooleanType: ObjectType;
- var globalRegExpType: ObjectType;
- var globalTemplateStringsArrayType: ObjectType;
-
- var tupleTypes: Map = {};
- var unionTypes: Map = {};
- var stringLiteralTypes: Map = {};
- var emitExtends = false;
-
- var mergedSymbols: Symbol[] = [];
- var symbolLinks: SymbolLinks[] = [];
- var nodeLinks: NodeLinks[] = [];
- var potentialThisCollisions: Node[] = [];
-
- var diagnostics: Diagnostic[] = [];
- var diagnosticsModified: boolean = false;
-
- function addDiagnostic(diagnostic: Diagnostic) {
- diagnostics.push(diagnostic);
- diagnosticsModified = true;
- }
-
- function error(location: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void {
- var diagnostic = location
- ? createDiagnosticForNode(location, message, arg0, arg1, arg2)
- : createCompilerDiagnostic(message, arg0, arg1, arg2);
- addDiagnostic(diagnostic);
- }
-
- function createSymbol(flags: SymbolFlags, name: string): Symbol {
- return new Symbol(flags, name);
- }
-
- function getExcludedSymbolFlags(flags: SymbolFlags): SymbolFlags {
- var 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.Import) result |= SymbolFlags.ImportExcludes;
- return result;
- }
-
- function recordMergedSymbol(target: Symbol, source: Symbol) {
- if (!source.mergeId) source.mergeId = nextMergeId++;
- mergedSymbols[source.mergeId] = target;
- }
-
- function cloneSymbol(symbol: Symbol): Symbol {
- var 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 extendSymbol(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 (!target.valueDeclaration && source.valueDeclaration) target.valueDeclaration = source.valueDeclaration;
- forEach(source.declarations, node => {
- target.declarations.push(node);
- });
- if (source.members) {
- if (!target.members) target.members = {};
- extendSymbolTable(target.members, source.members);
- }
- if (source.exports) {
- if (!target.exports) target.exports = {};
- extendSymbolTable(target.exports, source.exports);
- }
- recordMergedSymbol(target, source);
- }
- else {
- var 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 {
- var result: SymbolTable = {};
- for (var id in symbolTable) {
- if (hasProperty(symbolTable, id)) {
- result[id] = symbolTable[id];
- }
- }
- return result;
- }
-
- function extendSymbolTable(target: SymbolTable, source: SymbolTable) {
- for (var id in source) {
- if (hasProperty(source, id)) {
- if (!hasProperty(target, id)) {
- target[id] = source[id];
- }
- else {
- var symbol = target[id];
- if (!(symbol.flags & SymbolFlags.Merged)) {
- target[id] = symbol = cloneSymbol(symbol);
- }
- extendSymbol(symbol, source[id]);
- }
- }
- }
- }
-
- function getSymbolLinks(symbol: Symbol): SymbolLinks {
- if (symbol.flags & SymbolFlags.Transient) return symbol;
- if (!symbol.id) symbol.id = nextSymbolId++;
- return symbolLinks[symbol.id] || (symbolLinks[symbol.id] = {});
- }
-
- function getNodeLinks(node: Node): NodeLinks {
- if (!node.id) node.id = nextNodeId++;
- return nodeLinks[node.id] || (nodeLinks[node.id] = {});
- }
-
- function getSourceFile(node: Node): SourceFile {
- return getAncestor(node, SyntaxKind.SourceFile);
- }
-
- function isGlobalSourceFile(node: Node) {
- return node.kind === SyntaxKind.SourceFile && !isExternalModule(node);
- }
-
- function getSymbol(symbols: SymbolTable, name: string, meaning: SymbolFlags): Symbol {
- if (meaning && hasProperty(symbols, name)) {
- var 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.Import) {
- var target = resolveImport(symbol);
- // unknown symbol will mean that there were reported error during import 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.
- }
-
- /** Returns true if node1 is defined before node 2**/
- function isDefinedBefore(node1: Node, node2: Node): boolean {
- var file1 = getSourceFileOfNode(node1);
- var file2 = getSourceFileOfNode(node2);
- if (file1 === file2) {
- return node1.pos <= node2.pos;
- }
-
- if (!compilerOptions.out) {
- return true;
- }
-
- var sourceFiles = program.getSourceFiles();
- return sourceFiles.indexOf(file1) <= sourceFiles.indexOf(file2);
- }
-
- // 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 {
-
- var result: Symbol;
- var lastLocation: Node;
- var propertyWithInvalidInitializer: Node;
- var errorLocation = location;
-
- 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)) {
- break loop;
- }
- }
- switch (location.kind) {
- case SyntaxKind.SourceFile:
- if (!isExternalModule(location)) break;
- case SyntaxKind.ModuleDeclaration:
- if (result = getSymbol(getSymbolOfNode(location).exports, 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.Property:
- // 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 (location.parent.kind === SyntaxKind.ClassDeclaration && !(location.flags & NodeFlags.Static)) {
- var 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.InterfaceDeclaration:
- if (result = getSymbol(getSymbolOfNode(location).members, name, meaning & SymbolFlags.Type)) {
- if (lastLocation && lastLocation.flags & NodeFlags.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;
- }
- break;
- case SyntaxKind.Method:
- case SyntaxKind.Constructor:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.ArrowFunction:
- if (name === "arguments") {
- result = argumentsSymbol;
- break loop;
- }
- break;
- case SyntaxKind.FunctionExpression:
- if (name === "arguments") {
- result = argumentsSymbol;
- break loop;
- }
- var id = (location).name;
- if (id && name === id.text) {
- result = location.symbol;
- break loop;
- }
- break;
- case SyntaxKind.CatchBlock:
- var id = (location).variable;
- if (name === id.text) {
- result = location.symbol;
- break loop;
- }
- break;
- }
- lastLocation = location;
- location = location.parent;
- }
-
- if (!result) {
- result = getSymbol(globals, name, meaning);
- }
-
- if (!result) {
- if (nameNotFoundMessage) {
- 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.
- var 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;
- }
- if (result.flags & SymbolFlags.BlockScopedVariable) {
- // Block-scoped variables cannot be used before their definition
- var declaration = forEach(result.declarations, d => d.flags & NodeFlags.BlockScoped ? d : undefined);
- Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined");
- if (!isDefinedBefore(declaration, errorLocation)) {
- error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(declaration.name));
- }
- }
- }
- return result;
- }
-
- function resolveImport(symbol: Symbol): Symbol {
- Debug.assert((symbol.flags & SymbolFlags.Import) !== 0, "Should only get Imports here.");
- var links = getSymbolLinks(symbol);
- if (!links.target) {
- links.target = resolvingSymbol;
- var node = getDeclarationOfKind(symbol, SyntaxKind.ImportDeclaration);
- var target = node.externalModuleName ?
- resolveExternalModuleName(node, node.externalModuleName) :
- getSymbolOfPartOfRightHandSideOfImport(node.entityName, 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;
- }
-
- // This function is only for imports with entity names
- function getSymbolOfPartOfRightHandSideOfImport(entityName: EntityName, importDeclaration?: ImportDeclaration): Symbol {
- if (!importDeclaration) {
- importDeclaration = getAncestor(entityName, SyntaxKind.ImportDeclaration);
- 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(importDeclaration, 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.ImportDeclaration);
- return resolveEntityName(importDeclaration, 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 import aliases
- function resolveEntityName(location: Node, name: EntityName, meaning: SymbolFlags): Symbol {
- if (name.kind === SyntaxKind.Identifier) {
- var symbol = resolveName(location, (name).text, meaning, Diagnostics.Cannot_find_name_0, name);
- if (!symbol) {
- return;
- }
- }
- else if (name.kind === SyntaxKind.QualifiedName) {
- var namespace = resolveEntityName(location, (name).left, SymbolFlags.Namespace);
- if (!namespace || namespace === unknownSymbol || (name).right.kind === SyntaxKind.Missing) return;
- var symbol = getSymbol(namespace.exports, (name).right.text, meaning);
- if (!symbol) {
- error(location, Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(namespace),
- declarationNameToString((name).right));
- return;
- }
- }
- else {
- // Missing identifier
- return;
- }
- Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0, "Should never get an instantiated symbol here.");
- return symbol.flags & meaning ? symbol : resolveImport(symbol);
- }
-
- function isExternalModuleNameRelative(moduleName: string): boolean {
- // TypeScript 1.0 spec (April 2014): 11.2.1
- // An external module name is "relative" if the first term is "." or "..".
- return moduleName.substr(0, 2) === "./" || moduleName.substr(0, 3) === "../" || moduleName.substr(0, 2) === ".\\" || moduleName.substr(0, 3) === "..\\";
- }
-
- function resolveExternalModuleName(location: Node, moduleLiteral: LiteralExpression): Symbol {
- var searchPath = getDirectoryPath(getSourceFile(location).filename);
- var moduleName = moduleLiteral.text;
- if (!moduleName) return;
- var isRelative = isExternalModuleNameRelative(moduleName);
- if (!isRelative) {
- var symbol = getSymbol(globals, '"' + moduleName + '"', SymbolFlags.ValueModule);
- if (symbol) {
- return getResolvedExportSymbol(symbol);
- }
- }
- while (true) {
- var filename = normalizePath(combinePaths(searchPath, moduleName));
- var sourceFile = program.getSourceFile(filename + ".ts") || program.getSourceFile(filename + ".d.ts");
- if (sourceFile || isRelative) break;
- var parentPath = getDirectoryPath(searchPath);
- if (parentPath === searchPath) break;
- searchPath = parentPath;
- }
- if (sourceFile) {
- if (sourceFile.symbol) {
- return getResolvedExportSymbol(sourceFile.symbol);
- }
- error(moduleLiteral, Diagnostics.File_0_is_not_an_external_module, sourceFile.filename);
- return;
- }
- error(moduleLiteral, Diagnostics.Cannot_find_external_module_0, moduleName);
- }
-
- function getResolvedExportSymbol(moduleSymbol: Symbol): Symbol {
- var symbol = getExportAssignmentSymbol(moduleSymbol);
- if (symbol) {
- if (symbol.flags & (SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace)) {
- return symbol;
- }
- if (symbol.flags & SymbolFlags.Import) {
- return resolveImport(symbol);
- }
- }
- return moduleSymbol;
- }
-
- function getExportAssignmentSymbol(symbol: Symbol): Symbol {
- checkTypeOfExportAssignmentSymbol(symbol);
- var symbolLinks = getSymbolLinks(symbol);
- return symbolLinks.exportAssignSymbol === unknownSymbol ? undefined : symbolLinks.exportAssignSymbol;
- }
-
- function checkTypeOfExportAssignmentSymbol(containerSymbol: Symbol): void {
- var symbolLinks = getSymbolLinks(containerSymbol);
- if (!symbolLinks.exportAssignSymbol) {
- var exportInformation = collectExportInformationForSourceFileOrModule(containerSymbol);
- if (exportInformation.exportAssignments.length) {
- if (exportInformation.exportAssignments.length > 1) {
- // TypeScript 1.0 spec (April 2014): 11.2.4
- // It is an error for an external module to contain more than one export assignment.
- forEach(exportInformation.exportAssignments, node => error(node, Diagnostics.A_module_cannot_have_more_than_one_export_assignment));
- }
- var node = exportInformation.exportAssignments[0];
- if (exportInformation.hasExportedMember) {
- // TypeScript 1.0 spec (April 2014): 11.2.3
- // If an external module contains an export assignment it is an error
- // for the external module to also contain export declarations.
- // The two types of exports are mutually exclusive.
- error(node, Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements);
- }
- if (node.exportName.text) {
- var meaning = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace;
- var exportSymbol = resolveName(node, node.exportName.text, meaning, Diagnostics.Cannot_find_name_0, node.exportName);
- }
- }
- symbolLinks.exportAssignSymbol = exportSymbol || unknownSymbol;
- }
- }
-
- function collectExportInformationForSourceFileOrModule(symbol: Symbol) {
- var seenExportedMember = false;
- var result: ExportAssignment[] = [];
- forEach(symbol.declarations, declaration => {
- var block = (declaration.kind === SyntaxKind.SourceFile ? declaration : (declaration).body);
- forEach(block.statements, node => {
- if (node.kind === SyntaxKind.ExportAssignment) {
- result.push(node);
- }
- else {
- seenExportedMember = seenExportedMember || (node.flags & NodeFlags.Export) !== 0;
- }
- });
- });
- return {
- hasExportedMember: seenExportedMember,
- exportAssignments: result
- };
- }
-
- function getMergedSymbol(symbol: Symbol): Symbol {
- var 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 import, then it is a value if the symbol it resolves to is a value.
- if (symbol.flags & SymbolFlags.Import) {
- return (resolveImport(symbol).flags & SymbolFlags.Value) !== 0;
- }
-
- return false;
- }
-
- function findConstructorDeclaration(node: ClassDeclaration): ConstructorDeclaration {
- var members = node.members;
- for (var i = 0; i < members.length; i++) {
- var member = members[i];
- if (member.kind === SyntaxKind.Constructor && (member).body) {
- return member;
- }
- }
- }
-
- function createType(flags: TypeFlags): Type {
- var result = new Type(checker, flags);
- result.id = typeCount++;
- return result;
- }
-
- function createIntrinsicType(kind: TypeFlags, intrinsicName: string): IntrinsicType {
- var type = createType(kind);
- type.intrinsicName = intrinsicName;
- return type;
- }
-
- function createObjectType(kind: TypeFlags, symbol?: Symbol): ObjectType {
- var type = createType(kind);
- type.symbol = symbol;
- return type;
- }
-
- // A reserved member name starts with two underscores followed by a non-underscore
- function isReservedMemberName(name: string) {
- return name.charCodeAt(0) === CharacterCodes._ && name.charCodeAt(1) === CharacterCodes._ && name.charCodeAt(2) !== CharacterCodes._;
- }
-
- function getNamedMembers(members: SymbolTable): Symbol[] {
- var result: Symbol[];
- for (var id in members) {
- if (hasProperty(members, id)) {
- if (!isReservedMemberName(id)) {
- if (!result) result = [];
- var symbol = members[id];
- if (symbolIsValue(symbol)) {
- result.push(symbol);
- }
- }
- }
- }
- return result || emptyArray;
- }
-
- function setObjectTypeMembers(type: ObjectType, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexType: Type, numberIndexType: Type): ResolvedType {
- (type).members = members;
- (type).properties = getNamedMembers(members);
- (type).callSignatures = callSignatures;
- (type).constructSignatures = constructSignatures;
- if (stringIndexType) (type).stringIndexType = stringIndexType;
- if (numberIndexType) (type).numberIndexType = numberIndexType;
- return type;
- }
-
- function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexType: Type, numberIndexType: Type): ResolvedType {
- return setObjectTypeMembers(createObjectType(TypeFlags.Anonymous, symbol),
- members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
- }
-
- function isOptionalProperty(propertySymbol: Symbol): boolean {
- // class C {
- // constructor(public x?) { }
- // }
- //
- // x is an optional parameter, but it is a required property.
- return propertySymbol.valueDeclaration &&
- propertySymbol.valueDeclaration.flags & NodeFlags.QuestionMark &&
- propertySymbol.valueDeclaration.kind !== SyntaxKind.Parameter;
- }
-
- function forEachSymbolTableInScope(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T {
- var result: T;
- for (var 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 (!isExternalModule(location)) {
- break;
- }
- case SyntaxKind.ModuleDeclaration:
- if (result = callback(getSymbolOfNode(location).exports)) {
- return result;
- }
- break;
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.InterfaceDeclaration:
- if (result = callback(getSymbolOfNode(location).members)) {
- 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
- var 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 symbolfrom symbolTable or alias resolution matches the symbol,
- // check the symbol can be qualified, it is only then this symbol is accessible
- return !forEach(symbolFromSymbolTable.declarations, declaration => hasExternalModuleSymbol(declaration)) &&
- 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.Import) {
- 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, declaration =>
- declaration.kind === SyntaxKind.ImportDeclaration && (declaration).externalModuleName)) {
- var resolvedImportedSymbol = resolveImport(symbolFromSymbolTable);
- if (isAccessible(symbolFromSymbolTable, resolveImport(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
- var accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTable(resolvedImportedSymbol.exports) : undefined;
- if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) {
- return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports);
- }
- }
- }
- });
- }
-
- if (symbol) {
- return forEachSymbolTableInScope(enclosingDeclaration, getAccessibleSymbolChainFromSymbolTable);
- }
- }
-
- function needsQualification(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) {
- var 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
- var 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.Import) ? resolveImport(symbolFromSymbolTable) : symbolFromSymbolTable;
- if (symbolFromSymbolTable.flags & meaning) {
- qualify = true;
- return true;
- }
-
- // Continue to the next symbol table
- return false;
- });
-
- return qualify;
- }
-
- function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult {
- if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) {
- var initialSymbol = symbol;
- var meaningToLook = meaning;
- while (symbol) {
- // Symbol is accessible if it by itself is accessible
- var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook, /*useOnlyExternalAliasing*/ false);
- if (accessibleSymbolChain) {
- var 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 { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: hasAccessibleDeclarations.aliasesToMakeVisible };
- }
-
- // 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 {
- // }
- // }
- // var 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
- var symbolExternalModule = forEach(initialSymbol.declarations, declaration => getExternalModuleContainer(declaration));
- if (symbolExternalModule) {
- var 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: Declaration) {
- for (; declaration; declaration = declaration.parent) {
- if (hasExternalModuleSymbol(declaration)) {
- return getSymbolOfNode(declaration);
- }
- }
- }
- }
-
- function hasExternalModuleSymbol(declaration: Declaration) {
- return (declaration.kind === SyntaxKind.ModuleDeclaration && declaration.name.kind === SyntaxKind.StringLiteral) ||
- (declaration.kind === SyntaxKind.SourceFile && isExternalModule(declaration));
- }
-
- function hasVisibleDeclarations(symbol: Symbol): { aliasesToMakeVisible?: ImportDeclaration[]; } {
- var aliasesToMakeVisible: ImportDeclaration[];
- if (forEach(symbol.declarations, declaration => !getIsDeclarationVisible(declaration))) {
- return undefined;
- }
- return { aliasesToMakeVisible: 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
- if (declaration.kind === SyntaxKind.ImportDeclaration &&
- !(declaration.flags & NodeFlags.Export) &&
- isDeclarationVisible(declaration.parent)) {
- getNodeLinks(declaration).isVisible = true;
- if (aliasesToMakeVisible) {
- if (!contains(aliasesToMakeVisible, declaration)) {
- aliasesToMakeVisible.push(declaration);
- }
- }
- else {
- aliasesToMakeVisible = [declaration];
- }
- return true;
- }
-
- // Declaration is not visible
- return false;
- }
-
- return true;
- }
- }
-
- function isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult {
- var firstIdentifier = getFirstIdentifier(entityName);
- var symbolOfNameSpace = resolveName(entityName.parent, (firstIdentifier).text, SymbolFlags.Namespace, Diagnostics.Cannot_find_name_0, firstIdentifier);
- // Verify if the symbol is accessible
- var hasNamespaceDeclarationsVisibile = hasVisibleDeclarations(symbolOfNameSpace);
- return hasNamespaceDeclarationsVisibile ?
- { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: hasNamespaceDeclarationsVisibile.aliasesToMakeVisible } :
- { accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: declarationNameToString(firstIdentifier) };
- }
-
- function releaseStringWriter(writer: StringSymbolWriter) {
- writer.clear()
- stringWriters.push(writer);
- }
-
- function writeKeyword(writer: SymbolWriter, kind: SyntaxKind) {
- writer.writeKeyword(tokenToString(kind));
- }
-
- function writePunctuation(writer: SymbolWriter, kind: SyntaxKind) {
- writer.writePunctuation(tokenToString(kind));
- }
-
- function writeOperator(writer: SymbolWriter, kind: SyntaxKind) {
- writer.writeOperator(tokenToString(kind));
- }
-
- function writeSpace(writer: SymbolWriter) {
- writer.writeSpace(" ");
- }
-
- function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string {
- var writer = getSingleLineStringWriter();
- getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning);
-
- var result = writer.string();
- releaseStringWriter(writer);
-
- return result;
- }
-
- function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string {
- var writer = getSingleLineStringWriter();
- getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
-
- var result = writer.string();
- releaseStringWriter(writer);
-
- var maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100;
- if (maxLength && result.length >= maxLength) {
- result = result.substr(0, maxLength - "...".length) + "...";
- }
-
- return result;
- }
-
- function getTypeAliasForTypeLiteral(type: Type): Symbol {
- if (type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral) {
- var node = type.symbol.declarations[0].parent;
- while (node.kind === SyntaxKind.ParenType) {
- node = node.parent;
- }
- if (node.kind === SyntaxKind.TypeAliasDeclaration) {
- return getSymbolOfNode(node);
- }
- }
- return undefined;
- }
-
- // This is for caching the result of getSymbolDisplayBuilder. Do not access directly.
- var _displayBuilder: SymbolDisplayBuilder;
- function getSymbolDisplayBuilder(): SymbolDisplayBuilder {
- /**
- * 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 {
- if (symbol.declarations && symbol.declarations.length > 0) {
- var declaration = symbol.declarations[0];
- if (declaration.name) {
- writer.writeSymbol(declarationNameToString(declaration.name), symbol);
- return;
- }
- }
-
- writer.writeSymbol(symbol.name, 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): void {
- var 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);
- }
-
- // Let 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) {
- var 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 (var i = 0, n = accessibleSymbolChain.length; i < n; i++) {
- appendParentTypeArgumentsAndSymbolName(accessibleSymbolChain[i]);
- }
- }
- else {
- // If we didn't find accessible symbol chain for this symbol, break if this is external module
- if (!parentSymbol && ts.forEach(symbol.declarations, declaration => hasExternalModuleSymbol(declaration))) {
- return;
- }
-
- // if this is anonymous type break
- if (symbol.flags & SymbolFlags.TypeLiteral || symbol.flags & SymbolFlags.ObjectLiteral) {
- return;
- }
-
- appendParentTypeArgumentsAndSymbolName(symbol);
- }
- }
- }
-
- // Get qualified name
- if (enclosingDeclaration &&
- // TypeParameters do not need qualification
- !(symbol.flags & SymbolFlags.TypeParameter)) {
-
- walkSymbol(symbol, meaning);
- return;
- }
-
- return appendParentTypeArgumentsAndSymbolName(symbol);
- }
-
- function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, typeStack?: Type[]) {
- var globalFlagsToPass = globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike;
- 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) &&
- (type.flags & TypeFlags.Any) ? "any" : (type).intrinsicName);
- }
- else if (type.flags & TypeFlags.Reference) {
- writeTypeReference(type, flags);
- }
- else if (type.flags & (TypeFlags.Class | TypeFlags.Interface | TypeFlags.Enum | TypeFlags.TypeParameter)) {
- buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type);
- }
- else if (type.flags & TypeFlags.Tuple) {
- writeTupleType(type);
- }
- else if (type.flags & TypeFlags.Union) {
- writeUnionType(type, flags);
- }
- else if (type.flags & TypeFlags.Anonymous) {
- writeAnonymousType(type, flags);
- }
- else if (type.flags & TypeFlags.StringLiteral) {
- writer.writeStringLiteral((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[], union: boolean) {
- for (var i = 0; i < types.length; i++) {
- if (i > 0) {
- if (union) {
- writeSpace(writer);
- }
- writePunctuation(writer, union ? SyntaxKind.BarToken : SyntaxKind.CommaToken);
- writeSpace(writer);
- }
- writeType(types[i], union ? TypeFormatFlags.InElementType : TypeFormatFlags.None);
- }
- }
-
- function writeTypeReference(type: TypeReference, flags: TypeFormatFlags) {
- if (type.target === globalArrayType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) {
- writeType(type.typeArguments[0], TypeFormatFlags.InElementType);
- writePunctuation(writer, SyntaxKind.OpenBracketToken);
- writePunctuation(writer, SyntaxKind.CloseBracketToken);
- }
- else {
- buildSymbolDisplay(type.target.symbol, writer, enclosingDeclaration, SymbolFlags.Type);
- writePunctuation(writer, SyntaxKind.LessThanToken);
- writeTypeList(type.typeArguments, /*union*/ false);
- writePunctuation(writer, SyntaxKind.GreaterThanToken);
- }
- }
-
- function writeTupleType(type: TupleType) {
- writePunctuation(writer, SyntaxKind.OpenBracketToken);
- writeTypeList(type.elementTypes, /*union*/ false);
- writePunctuation(writer, SyntaxKind.CloseBracketToken);
- }
-
- function writeUnionType(type: UnionType, flags: TypeFormatFlags) {
- if (flags & TypeFormatFlags.InElementType) {
- writePunctuation(writer, SyntaxKind.OpenParenToken);
- }
- writeTypeList(type.types, /*union*/ true);
- if (flags & TypeFormatFlags.InElementType) {
- writePunctuation(writer, SyntaxKind.CloseParenToken);
- }
- }
-
- function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) {
- // Always use 'typeof T' for type of class, enum, and module objects
- if (type.symbol && type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
- writeTypeofSymbol(type);
- }
- // Use 'typeof T' for types of functions and methods that circularly reference themselves
- else if (shouldWriteTypeOfFunctionSymbol()) {
- writeTypeofSymbol(type);
- }
- else if (typeStack && contains(typeStack, type)) {
- // If type is an anonymous type literal in a type alias declaration, use type alias name
- var typeAlias = getTypeAliasForTypeLiteral(type);
- if (typeAlias) {
- buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type);
- }
- else {
- // Recursive usage, use any
- writeKeyword(writer, SyntaxKind.AnyKeyword);
- }
- }
- else {
- if (!typeStack) {
- typeStack = [];
- }
- typeStack.push(type);
- writeLiteralType(type, flags);
- typeStack.pop();
- }
-
- function shouldWriteTypeOfFunctionSymbol() {
- if (type.symbol) {
- var isStaticMethodSymbol = !!(type.symbol.flags & SymbolFlags.Method && // typeof static method
- ts.forEach(type.symbol.declarations, declaration => declaration.flags & NodeFlags.Static));
- var isNonLocalFunctionSymbol = !!(type.symbol.flags & SymbolFlags.Function) &&
- (type.symbol.parent || // is exported function symbol
- ts.forEach(type.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
- (typeStack && contains(typeStack, type)); // it is type of the symbol uses itself recursively
- }
- }
- }
- }
-
- function writeTypeofSymbol(type: ObjectType) {
- writeKeyword(writer, SyntaxKind.TypeOfKeyword);
- writeSpace(writer);
- buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value);
- }
-
- function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
- var resolved = resolveObjectOrUnionTypeMembers(type);
- if (!resolved.properties.length && !resolved.stringIndexType && !resolved.numberIndexType) {
- 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 , typeStack);
- 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, typeStack);
- if (flags & TypeFormatFlags.InElementType) {
- writePunctuation(writer, SyntaxKind.CloseParenToken);
- }
- return;
- }
- }
-
- writePunctuation(writer, SyntaxKind.OpenBraceToken);
- writer.writeLine();
- writer.increaseIndent();
- for (var i = 0; i < resolved.callSignatures.length; i++) {
- buildSignatureDisplay(resolved.callSignatures[i], writer, enclosingDeclaration, globalFlagsToPass, typeStack);
- writePunctuation(writer, SyntaxKind.SemicolonToken);
- writer.writeLine();
- }
- for (var i = 0; i < resolved.constructSignatures.length; i++) {
- writeKeyword(writer, SyntaxKind.NewKeyword);
- writeSpace(writer);
-
- buildSignatureDisplay(resolved.constructSignatures[i], writer, enclosingDeclaration, globalFlagsToPass, typeStack);
- writePunctuation(writer, SyntaxKind.SemicolonToken);
- writer.writeLine();
- }
- if (resolved.stringIndexType) {
- // [x: string]:
- writePunctuation(writer, SyntaxKind.OpenBracketToken);
- writer.writeParameter("x");
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
- writeKeyword(writer, SyntaxKind.StringKeyword);
- writePunctuation(writer, SyntaxKind.CloseBracketToken);
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
- writeType(resolved.stringIndexType, TypeFormatFlags.None);
- writePunctuation(writer, SyntaxKind.SemicolonToken);
- writer.writeLine();
- }
- if (resolved.numberIndexType) {
- // [x: number]:
- writePunctuation(writer, SyntaxKind.OpenBracketToken);
- writer.writeParameter("x");
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
- writeKeyword(writer, SyntaxKind.NumberKeyword);
- writePunctuation(writer, SyntaxKind.CloseBracketToken);
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
- writeType(resolved.numberIndexType, TypeFormatFlags.None);
- writePunctuation(writer, SyntaxKind.SemicolonToken);
- writer.writeLine();
- }
- for (var i = 0; i < resolved.properties.length; i++) {
- var p = resolved.properties[i];
- var t = getTypeOfSymbol(p);
- if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(t).length) {
- var signatures = getSignaturesOfType(t, SignatureKind.Call);
- for (var j = 0; j < signatures.length; j++) {
- buildSymbolDisplay(p, writer);
- if (isOptionalProperty(p)) {
- writePunctuation(writer, SyntaxKind.QuestionToken);
- }
- buildSignatureDisplay(signatures[j], writer, enclosingDeclaration, globalFlagsToPass, typeStack);
- writePunctuation(writer, SyntaxKind.SemicolonToken);
- writer.writeLine();
- }
- }
- else {
- buildSymbolDisplay(p, writer);
- if (isOptionalProperty(p)) {
- writePunctuation(writer, SyntaxKind.QuestionToken);
- }
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
- writeType(t, TypeFormatFlags.None);
- writePunctuation(writer, SyntaxKind.SemicolonToken);
- writer.writeLine();
- }
- }
- writer.decreaseIndent();
- writePunctuation(writer, SyntaxKind.CloseBraceToken);
- }
- }
-
- function buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags) {
- var targetSymbol = getTargetSymbol(symbol);
- if (targetSymbol.flags & SymbolFlags.Class || targetSymbol.flags & SymbolFlags.Interface) {
- buildDisplayForTypeParametersAndDelimiters(getTypeParametersOfClassOrInterface(symbol), writer, enclosingDeclaraiton, flags);
- }
- }
-
- function buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
- appendSymbolNameOnly(tp.symbol, writer);
- var constraint = getConstraintOfTypeParameter(tp);
- if (constraint) {
- writeSpace(writer);
- writeKeyword(writer, SyntaxKind.ExtendsKeyword);
- writeSpace(writer);
- buildTypeDisplay(constraint, writer, enclosingDeclaration, flags, typeStack);
- }
- }
-
- function buildParameterDisplay(p: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
- if (getDeclarationFlagsFromSymbol(p) & NodeFlags.Rest) {
- writePunctuation(writer, SyntaxKind.DotDotDotToken);
- }
- appendSymbolNameOnly(p, writer);
- if (p.valueDeclaration.flags & NodeFlags.QuestionMark || (p.valueDeclaration).initializer) {
- writePunctuation(writer, SyntaxKind.QuestionToken);
- }
- writePunctuation(writer, SyntaxKind.ColonToken);
- writeSpace(writer);
-
- buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, typeStack);
- }
-
- function buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
- if (typeParameters && typeParameters.length) {
- writePunctuation(writer, SyntaxKind.LessThanToken);
- for (var i = 0; i < typeParameters.length; i++) {
- if (i > 0) {
- writePunctuation(writer, SyntaxKind.CommaToken);
- writeSpace(writer);
- }
- buildTypeParameterDisplay(typeParameters[i], writer, enclosingDeclaration, flags, typeStack);
- }
- writePunctuation(writer, SyntaxKind.GreaterThanToken);
- }
- }
-
- function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
- if (typeParameters && typeParameters.length) {
- writePunctuation(writer, SyntaxKind.LessThanToken);
- for (var 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(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
- writePunctuation(writer, SyntaxKind.OpenParenToken);
- for (var i = 0; i < parameters.length; i++) {
- if (i > 0) {
- writePunctuation(writer, SyntaxKind.CommaToken);
- writeSpace(writer);
- }
- buildParameterDisplay(parameters[i], writer, enclosingDeclaration, flags, typeStack);
- }
- writePunctuation(writer, SyntaxKind.CloseParenToken);
- }
-
- function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
- if (flags & TypeFormatFlags.WriteArrowStyleSignature) {
- writeSpace(writer);
- writePunctuation(writer, SyntaxKind.EqualsGreaterThanToken);
- }
- else {
- writePunctuation(writer, SyntaxKind.ColonToken);
- }
- writeSpace(writer);
- buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags, typeStack);
- }
-
- function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
- 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, typeStack);
- }
-
- buildDisplayForParametersAndDelimiters(signature.parameters, writer, enclosingDeclaration, flags, typeStack);
- buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, typeStack);
- }
-
- return _displayBuilder || (_displayBuilder = {
- symbolToString: symbolToString,
- typeToString: typeToString,
- buildSymbolDisplay: buildSymbolDisplay,
- buildTypeDisplay: buildTypeDisplay,
- buildTypeParameterDisplay: buildTypeParameterDisplay,
- buildParameterDisplay: buildParameterDisplay,
- buildDisplayForParametersAndDelimiters: buildDisplayForParametersAndDelimiters,
- buildDisplayForTypeParametersAndDelimiters: buildDisplayForTypeParametersAndDelimiters,
- buildDisplayForTypeArgumentsAndDelimiters: buildDisplayForTypeArgumentsAndDelimiters,
- buildTypeParameterDisplayFromSymbol: buildTypeParameterDisplayFromSymbol,
- buildSignatureDisplay: buildSignatureDisplay,
- buildReturnTypeDisplay: buildReturnTypeDisplay
- });
- }
-
- function isDeclarationVisible(node: Declaration): boolean {
- function getContainingExternalModule(node: Node) {
- for (; node; node = node.parent) {
- if (node.kind === SyntaxKind.ModuleDeclaration) {
- if ((node).name.kind === SyntaxKind.StringLiteral) {
- return node;
- }
- }
- else if (node.kind === SyntaxKind.SourceFile) {
- return isExternalModule(node) ? node : undefined;
- }
- }
- Debug.fail("getContainingModule cant reach here");
- }
-
- function isUsedInExportAssignment(node: Node) {
- // Get source File and see if it is external module and has export assigned symbol
- var externalModule = getContainingExternalModule(node);
- if (externalModule) {
- // This is export assigned symbol node
- var externalModuleSymbol = getSymbolOfNode(externalModule);
- var exportAssignmentSymbol = getExportAssignmentSymbol(externalModuleSymbol);
- var resolvedExportSymbol: Symbol;
- var symbolOfNode = getSymbolOfNode(node);
- if (isSymbolUsedInExportAssignment(symbolOfNode)) {
- return true;
- }
-
- // if symbolOfNode is import declaration, resolve the symbol declaration and check
- if (symbolOfNode.flags & SymbolFlags.Import) {
- return isSymbolUsedInExportAssignment(resolveImport(symbolOfNode));
- }
- }
-
- // Check if the symbol is used in export assignment
- function isSymbolUsedInExportAssignment(symbol: Symbol) {
- if (exportAssignmentSymbol === symbol) {
- return true;
- }
-
- if (exportAssignmentSymbol && !!(exportAssignmentSymbol.flags & SymbolFlags.Import)) {
- // if export assigned symbol is import declaration, resolve the import
- resolvedExportSymbol = resolvedExportSymbol || resolveImport(exportAssignmentSymbol);
- if (resolvedExportSymbol === symbol) {
- return true;
- }
-
- // Container of resolvedExportSymbol is visible
- return forEach(resolvedExportSymbol.declarations, declaration => {
- while (declaration) {
- if (declaration === node) {
- return true;
- }
- declaration = declaration.parent;
- }
- });
- }
- }
- }
-
- function determineIfDeclarationIsVisible() {
- switch (node.kind) {
- case SyntaxKind.VariableDeclaration:
- case SyntaxKind.ModuleDeclaration:
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.InterfaceDeclaration:
- case SyntaxKind.TypeAliasDeclaration:
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.EnumDeclaration:
- case SyntaxKind.ImportDeclaration:
- // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent
- var parent = node.kind === SyntaxKind.VariableDeclaration ? node.parent.parent : node.parent;
- // If the node is not exported or it is not ambient module element (except import declaration)
- if (!(node.flags & NodeFlags.Export) &&
- !(node.kind !== SyntaxKind.ImportDeclaration && parent.kind !== SyntaxKind.SourceFile && isInAmbientContext(parent))) {
- return isGlobalSourceFile(parent) || isUsedInExportAssignment(node);
- }
- // Exported members/ambient module elements (exception import declaration) are visible if parent is visible
- return isDeclarationVisible(parent);
-
- case SyntaxKind.Property:
- case SyntaxKind.Method:
- if (node.flags & (NodeFlags.Private | NodeFlags.Protected)) {
- // Private/protected properties/methods are not visible
- return false;
- }
- // Public properties/methods are visible if its parents are visible, so let it fall into next case statement
-
- case SyntaxKind.Constructor:
- case SyntaxKind.ConstructSignature:
- case SyntaxKind.CallSignature:
- case SyntaxKind.IndexSignature:
- case SyntaxKind.Parameter:
- case SyntaxKind.ModuleBlock:
- return isDeclarationVisible(node.parent);
-
- // Source file is always visible
- case SyntaxKind.SourceFile:
- return true;
-
- default:
- Debug.fail("isDeclarationVisible unknown: SyntaxKind: " + node.kind);
- }
- }
-
- if (node) {
- var links = getNodeLinks(node);
- if (links.isVisible === undefined) {
- links.isVisible = !!determineIfDeclarationIsVisible();
- }
- return links.isVisible;
- }
- }
-
- 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'.
- var classType = getDeclaredTypeOfSymbol(prototype.parent);
- return classType.typeParameters ? createTypeReference(classType, map(classType.typeParameters, _ => anyType)) : classType;
- }
-
- function getTypeOfVariableOrPropertyDeclaration(declaration: VariableDeclaration | PropertyDeclaration): Type {
- // A variable declared in a for..in statement is always of type any
- if (declaration.parent.kind === SyntaxKind.ForInStatement) {
- return anyType;
- }
- // Use type from type annotation if one is present
- if (declaration.type) {
- return getTypeFromTypeNode(declaration.type);
- }
- if (declaration.kind === SyntaxKind.Parameter) {
- var 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) {
- var getter = getDeclarationOfKind(declaration.parent.symbol, SyntaxKind.GetAccessor);
- if (getter) {
- return getReturnTypeOfSignature(getSignatureFromDeclaration(getter));
- }
- }
- // Use contextual parameter type if one is available
- var type = getContextuallyTypedParameterType(declaration);
- if (type) {
- return type;
- }
- }
- // Use the type of the initializer expression if one is present
- if (declaration.initializer) {
- var type = checkAndMarkExpression(declaration.initializer);
- // Widening of property assignments is handled by checkObjectLiteral, exclude them here
- if (declaration.kind !== SyntaxKind.PropertyAssignment) {
- var unwidenedType = type;
- type = getWidenedType(type);
- if (type !== unwidenedType) {
- checkImplicitAny(type);
- }
- }
- return type;
- }
- // Rest parameters default to type any[], other parameters default to type any
- var type = declaration.flags & NodeFlags.Rest ? createArrayType(anyType) : anyType;
- checkImplicitAny(type);
- return type;
-
- function checkImplicitAny(type: Type) {
- if (!fullTypeCheck || !compilerOptions.noImplicitAny) {
- return;
- }
- // We need to have ended up with 'any', 'any[]', 'any[][]', etc.
- if (getInnermostTypeOfNestedArrayTypes(type) !== anyType) {
- return;
- }
- // Ignore privates within ambient contexts; they exist purely for documentative purposes to avoid name clashing.
- // (e.g. privates within .d.ts files do not expose type information)
- if (isPrivateWithinAmbient(declaration) || (declaration.kind === SyntaxKind.Parameter && isPrivateWithinAmbient(declaration.parent))) {
- return;
- }
- switch (declaration.kind) {
- case SyntaxKind.Property:
- var diagnostic = Diagnostics.Member_0_implicitly_has_an_1_type;
- break;
- case SyntaxKind.Parameter:
- var diagnostic = declaration.flags & NodeFlags.Rest ?
- Diagnostics.Rest_parameter_0_implicitly_has_an_any_type :
- Diagnostics.Parameter_0_implicitly_has_an_1_type;
- break;
- default:
- var diagnostic = Diagnostics.Variable_0_implicitly_has_an_1_type;
- }
- error(declaration, diagnostic, declarationNameToString(declaration.name), typeToString(type));
- }
- }
-
- function getTypeOfVariableOrParameterOrProperty(symbol: Symbol): Type {
- var links = getSymbolLinks(symbol);
- if (!links.type) {
- // Handle prototype property
- if (symbol.flags & SymbolFlags.Prototype) {
- return links.type = getTypeOfPrototypeProperty(symbol);
- }
- // Handle catch clause variables
- var declaration = symbol.valueDeclaration;
- if (declaration.kind === SyntaxKind.CatchBlock) {
- return links.type = anyType;
- }
- // Handle variable, parameter or property
- links.type = resolvingType;
- var type = getTypeOfVariableOrPropertyDeclaration(declaration);
- if (links.type === resolvingType) {
- links.type = type;
- }
- }
- else if (links.type === resolvingType) {
- links.type = anyType;
- if (compilerOptions.noImplicitAny) {
- var diagnostic = (symbol.valueDeclaration).type ?
- Diagnostics._0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation :
- Diagnostics._0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer;
- error(symbol.valueDeclaration, diagnostic, symbolToString(symbol));
- }
- }
- return links.type;
- }
-
- function getSetAccessorTypeAnnotationNode(accessor: AccessorDeclaration): TypeNode {
- return accessor && accessor.parameters.length > 0 && accessor.parameters[0].type;
- }
-
- function getAnnotatedAccessorType(accessor: AccessorDeclaration): Type {
- if (accessor) {
- if (accessor.kind === SyntaxKind.GetAccessor) {
- return accessor.type && getTypeFromTypeNode(accessor.type);
- }
- else {
- var setterTypeAnnotation = getSetAccessorTypeAnnotationNode(accessor);
- return setterTypeAnnotation && getTypeFromTypeNode(setterTypeAnnotation);
- }
- }
- return undefined;
- }
-
- function getTypeOfAccessors(symbol: Symbol): Type {
- var links = getSymbolLinks(symbol);
- checkAndStoreTypeOfAccessors(symbol, links);
- return links.type;
- }
-
- function checkAndStoreTypeOfAccessors(symbol: Symbol, links?: SymbolLinks) {
- links = links || getSymbolLinks(symbol);
- if (!links.type) {
- links.type = resolvingType;
- var getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
- var setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor);
-
- var type: Type;
-
- // First try to see if the user specified a return type on the get-accessor.
- var 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.
- var 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) {
- 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 (links.type === resolvingType) {
- links.type = type;
- }
- }
- else if (links.type === resolvingType) {
- links.type = anyType;
- if (compilerOptions.noImplicitAny) {
- var 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));
- }
- }
- }
-
- function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
- var links = getSymbolLinks(symbol);
- if (!links.type) {
- links.type = createObjectType(TypeFlags.Anonymous, symbol);
- }
- return links.type;
- }
-
- function getTypeOfEnumMember(symbol: Symbol): Type {
- var links = getSymbolLinks(symbol);
- if (!links.type) {
- links.type = getDeclaredTypeOfEnum(getParentOfSymbol(symbol));
- }
- return links.type;
- }
-
- function getTypeOfImport(symbol: Symbol): Type {
- var links = getSymbolLinks(symbol);
- if (!links.type) {
- links.type = getTypeOfSymbol(resolveImport(symbol));
- }
- return links.type;
- }
-
- function getTypeOfInstantiatedSymbol(symbol: Symbol): Type {
- var 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.Import) {
- return getTypeOfImport(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 {
- var target = getTargetType(type);
- return target === checkBase || forEach(target.baseTypes, check);
- }
- }
-
- // Return combined list of type parameters from all declarations of a class or interface. Elsewhere we check they're all
- // the same, but even if they're not we still need the complete list to ensure instantiations supply type arguments
- // for all type parameters.
- function getTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] {
- var result: TypeParameter[];
- forEach(symbol.declarations, node => {
- if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration) {
- var declaration = node;
- if (declaration.typeParameters && declaration.typeParameters.length) {
- forEach(declaration.typeParameters, node => {
- var tp = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node));
- if (!result) {
- result = [tp];
- }
- else if (!contains(result, tp)) {
- result.push(tp);
- }
- });
- }
- }
- });
- return result;
- }
-
- function getDeclaredTypeOfClass(symbol: Symbol): InterfaceType {
- var links = getSymbolLinks(symbol);
- if (!links.declaredType) {
- var type = links.declaredType = createObjectType(TypeFlags.Class, symbol);
- var typeParameters = getTypeParametersOfClassOrInterface(symbol);
- if (typeParameters) {
- type.flags |= TypeFlags.Reference;
- type.typeParameters = typeParameters;
- (type).instantiations = {};
- (type).instantiations[getTypeListId(type.typeParameters)] = type;
- (type).target = type;
- (type).typeArguments = type.typeParameters;
- }
- type.baseTypes = [];
- var declaration = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration);
- if (declaration.baseType) {
- var baseType = getTypeFromTypeReferenceNode(declaration.baseType);
- if (baseType !== unknownType) {
- if (getTargetType(baseType).flags & TypeFlags.Class) {
- if (type !== baseType && !hasBaseType(baseType, type)) {
- type.baseTypes.push(baseType);
- }
- else {
- error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
- }
- }
- else {
- error(declaration.baseType, Diagnostics.A_class_may_only_extend_another_class);
- }
- }
- }
- type.declaredProperties = getNamedMembers(symbol.members);
- type.declaredCallSignatures = emptyArray;
- type.declaredConstructSignatures = emptyArray;
- type.declaredStringIndexType = getIndexTypeOfSymbol(symbol, IndexKind.String);
- type.declaredNumberIndexType = getIndexTypeOfSymbol(symbol, IndexKind.Number);
- }
- return links.declaredType;
- }
-
- function getDeclaredTypeOfInterface(symbol: Symbol): InterfaceType {
- var links = getSymbolLinks(symbol);
- if (!links.declaredType) {
- var type = links.declaredType = createObjectType(TypeFlags.Interface, symbol);
- var typeParameters = getTypeParametersOfClassOrInterface(symbol);
- if (typeParameters) {
- type.flags |= TypeFlags.Reference;
- type.typeParameters = typeParameters;
- (type).instantiations = {};
- (type).instantiations[getTypeListId(type.typeParameters)] = type;
- (type).target = type;
- (type).typeArguments = type.typeParameters;
- }
- type.baseTypes = [];
- forEach(symbol.declarations, declaration => {
- if (declaration.kind === SyntaxKind.InterfaceDeclaration && (declaration).baseTypes) {
- forEach((declaration).baseTypes, node => {
- var baseType = getTypeFromTypeReferenceNode(node);
- if (baseType !== unknownType) {
- if (getTargetType(baseType).flags & (TypeFlags.Class | TypeFlags.Interface)) {
- if (type !== baseType && !hasBaseType(baseType, type)) {
- type.baseTypes.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);
- }
- }
- });
- }
- });
- type.declaredProperties = getNamedMembers(symbol.members);
- type.declaredCallSignatures = getSignaturesOfSymbol(symbol.members["__call"]);
- type.declaredConstructSignatures = getSignaturesOfSymbol(symbol.members["__new"]);
- type.declaredStringIndexType = getIndexTypeOfSymbol(symbol, IndexKind.String);
- type.declaredNumberIndexType = getIndexTypeOfSymbol(symbol, IndexKind.Number);
- }
- return links.declaredType;
- }
-
- function getDeclaredTypeOfTypeAlias(symbol: Symbol): Type {
- var links = getSymbolLinks(symbol);
- if (!links.declaredType) {
- links.declaredType = resolvingType;
- var declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
- var type = getTypeFromTypeNode(declaration.type);
- if (links.declaredType === resolvingType) {
- links.declaredType = type;
- }
- }
- else if (links.declaredType === resolvingType) {
- links.declaredType = unknownType;
- var declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
- error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol));
- }
- return links.declaredType;
- }
-
- function getDeclaredTypeOfEnum(symbol: Symbol): Type {
- var links = getSymbolLinks(symbol);
- if (!links.declaredType) {
- var type = createType(TypeFlags.Enum);
- type.symbol = symbol;
- links.declaredType = type;
- }
- return links.declaredType;
- }
-
- function getDeclaredTypeOfTypeParameter(symbol: Symbol): TypeParameter {
- var links = getSymbolLinks(symbol);
- if (!links.declaredType) {
- var type = createType(TypeFlags.TypeParameter);
- type.symbol = symbol;
- if (!(getDeclarationOfKind(symbol, SyntaxKind.TypeParameter)).constraint) {
- type.constraint = noConstraintType;
- }
- links.declaredType = type;
- }
- return links.declaredType;
- }
-
- function getDeclaredTypeOfImport(symbol: Symbol): Type {
- var links = getSymbolLinks(symbol);
- if (!links.declaredType) {
- links.declaredType = getDeclaredTypeOfSymbol(resolveImport(symbol));
- }
- return links.declaredType;
- }
-
- function getDeclaredTypeOfSymbol(symbol: Symbol): Type {
- Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0);
- if (symbol.flags & SymbolFlags.Class) {
- return getDeclaredTypeOfClass(symbol);
- }
- if (symbol.flags & SymbolFlags.Interface) {
- return getDeclaredTypeOfInterface(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.Import) {
- return getDeclaredTypeOfImport(symbol);
- }
- return unknownType;
- }
-
- function createSymbolTable(symbols: Symbol[]): SymbolTable {
- var result: SymbolTable = {};
- for (var i = 0; i < symbols.length; i++) {
- var symbol = symbols[i];
- result[symbol.name] = symbol;
- }
- return result;
- }
-
- function createInstantiatedSymbolTable(symbols: Symbol[], mapper: TypeMapper): SymbolTable {
- var result: SymbolTable = {};
- for (var i = 0; i < symbols.length; i++) {
- var symbol = symbols[i];
- result[symbol.name] = instantiateSymbol(symbol, mapper);
- }
- return result;
- }
-
- function addInheritedMembers(symbols: SymbolTable, baseSymbols: Symbol[]) {
- for (var i = 0; i < baseSymbols.length; i++) {
- var s = baseSymbols[i];
- if (!hasProperty(symbols, s.name)) {
- symbols[s.name] = s;
- }
- }
- }
-
- function addInheritedSignatures(signatures: Signature[], baseSignatures: Signature[]) {
- if (baseSignatures) {
- for (var i = 0; i < baseSignatures.length; i++) {
- signatures.push(baseSignatures[i]);
- }
- }
- }
-
- function resolveClassOrInterfaceMembers(type: InterfaceType): void {
- var members = type.symbol.members;
- var callSignatures = type.declaredCallSignatures;
- var constructSignatures = type.declaredConstructSignatures;
- var stringIndexType = type.declaredStringIndexType;
- var numberIndexType = type.declaredNumberIndexType;
- if (type.baseTypes.length) {
- members = createSymbolTable(type.declaredProperties);
- forEach(type.baseTypes, baseType => {
- addInheritedMembers(members, getPropertiesOfObjectType(baseType));
- callSignatures = concatenate(callSignatures, getSignaturesOfType(baseType, SignatureKind.Call));
- constructSignatures = concatenate(constructSignatures, getSignaturesOfType(baseType, SignatureKind.Construct));
- stringIndexType = stringIndexType || getIndexTypeOfType(baseType, IndexKind.String);
- numberIndexType = numberIndexType || getIndexTypeOfType(baseType, IndexKind.Number);
- });
- }
- setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
- }
-
- function resolveTypeReferenceMembers(type: TypeReference): void {
- var target = type.target;
- var mapper = createTypeMapper(target.typeParameters, type.typeArguments);
- var members = createInstantiatedSymbolTable(target.declaredProperties, mapper);
- var callSignatures = instantiateList(target.declaredCallSignatures, mapper, instantiateSignature);
- var constructSignatures = instantiateList(target.declaredConstructSignatures, mapper, instantiateSignature);
- var stringIndexType = target.declaredStringIndexType ? instantiateType(target.declaredStringIndexType, mapper) : undefined;
- var numberIndexType = target.declaredNumberIndexType ? instantiateType(target.declaredNumberIndexType, mapper) : undefined;
- forEach(target.baseTypes, baseType => {
- var instantiatedBaseType = instantiateType(baseType, mapper);
- addInheritedMembers(members, getPropertiesOfObjectType(instantiatedBaseType));
- callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call));
- constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct));
- stringIndexType = stringIndexType || getIndexTypeOfType(instantiatedBaseType, IndexKind.String);
- numberIndexType = numberIndexType || getIndexTypeOfType(instantiatedBaseType, IndexKind.Number);
- });
- setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
- }
-
- function createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], parameters: Symbol[],
- resolvedReturnType: Type, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature {
- var sig = new Signature(checker);
- sig.declaration = declaration;
- sig.typeParameters = typeParameters;
- sig.parameters = parameters;
- sig.resolvedReturnType = resolvedReturnType;
- sig.minArgumentCount = minArgumentCount;
- sig.hasRestParameter = hasRestParameter;
- sig.hasStringLiterals = hasStringLiterals;
- return sig;
- }
-
- function cloneSignature(sig: Signature): Signature {
- return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType,
- sig.minArgumentCount, sig.hasRestParameter, sig.hasStringLiterals);
- }
-
- function getDefaultConstructSignatures(classType: InterfaceType): Signature[] {
- if (classType.baseTypes.length) {
- var baseType = classType.baseTypes[0];
- var baseSignatures = getSignaturesOfType(getTypeOfSymbol(baseType.symbol), SignatureKind.Construct);
- return map(baseSignatures, baseSignature => {
- var signature = baseType.flags & TypeFlags.Reference ?
- getSignatureInstantiation(baseSignature, (baseType).typeArguments) : cloneSignature(baseSignature);
- signature.typeParameters = classType.typeParameters;
- signature.resolvedReturnType = classType;
- return signature;
- });
- }
- return [createSignature(undefined, classType.typeParameters, emptyArray, classType, 0, false, false)];
- }
-
- function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable {
- var members: SymbolTable = {};
- for (var i = 0; i < memberTypes.length; i++) {
- var symbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "" + i);
- symbol.type = memberTypes[i];
- members[i] = symbol;
- }
- return members;
- }
-
- function resolveTupleTypeMembers(type: TupleType) {
- var arrayType = resolveObjectOrUnionTypeMembers(createArrayType(getUnionType(type.elementTypes)));
- var members = createTupleTypeMemberSymbols(type.elementTypes);
- addInheritedMembers(members, arrayType.properties);
- setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexType, arrayType.numberIndexType);
- }
-
- function signatureListsIdentical(s: Signature[], t: Signature[]): boolean {
- if (s.length !== t.length) {
- return false;
- }
- for (var i = 0; i < s.length; i++) {
- if (!compareSignatures(s[i], t[i], /*compareReturnTypes*/ false, compareTypes)) {
- return false;
- }
- }
- return true;
- }
-
- // If the lists of call or construct signatures in the given types are all identical except for return types,
- // and if none of the signatures are generic, return a list of signatures that has substitutes a union of the
- // return types of the corresponding signatures in each resulting signature.
- function getUnionSignatures(types: Type[], kind: SignatureKind): Signature[] {
- var signatureLists = map(types, t => getSignaturesOfType(t, kind));
- var signatures = signatureLists[0];
- for (var i = 0; i < signatures.length; i++) {
- if (signatures[i].typeParameters) {
- return emptyArray;
- }
- }
- for (var i = 1; i < signatureLists.length; i++) {
- if (!signatureListsIdentical(signatures, signatureLists[i])) {
- return emptyArray;
- }
- }
- var result = map(signatures, cloneSignature);
- for (var i = 0; i < result.length; i++) {
- var s = result[i];
- // Clear resolved return type we possibly got from cloneSignature
- s.resolvedReturnType = undefined;
- s.unionSignatures = map(signatureLists, signatures => signatures[i]);
- }
- return result;
- }
-
- function getUnionIndexType(types: Type[], kind: IndexKind): Type {
- var indexTypes: Type[] = [];
- for (var i = 0; i < types.length; i++) {
- var indexType = getIndexTypeOfType(types[i], kind);
- if (!indexType) {
- return undefined;
- }
- indexTypes.push(indexType);
- }
- return getUnionType(indexTypes);
- }
-
- 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).
- var callSignatures = getUnionSignatures(type.types, SignatureKind.Call);
- var constructSignatures = getUnionSignatures(type.types, SignatureKind.Construct);
- var stringIndexType = getUnionIndexType(type.types, IndexKind.String);
- var numberIndexType = getUnionIndexType(type.types, IndexKind.Number);
- setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexType, numberIndexType);
- }
-
- function resolveAnonymousTypeMembers(type: ObjectType) {
- var symbol = type.symbol;
- if (symbol.flags & SymbolFlags.TypeLiteral) {
- var members = symbol.members;
- var callSignatures = getSignaturesOfSymbol(members["__call"]);
- var constructSignatures = getSignaturesOfSymbol(members["__new"]);
- var stringIndexType = getIndexTypeOfSymbol(symbol, IndexKind.String);
- var numberIndexType = getIndexTypeOfSymbol(symbol, IndexKind.Number);
- }
- else {
- // Combinations of function, class, enum and module
- var members = emptySymbols;
- var callSignatures: Signature[] = emptyArray;
- var constructSignatures: Signature[] = emptyArray;
- if (symbol.flags & SymbolFlags.HasExports) {
- members = symbol.exports;
- }
- if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) {
- callSignatures = getSignaturesOfSymbol(symbol);
- }
- if (symbol.flags & SymbolFlags.Class) {
- var classType = getDeclaredTypeOfClass(symbol);
- constructSignatures = getSignaturesOfSymbol(symbol.members["__constructor"]);
- if (!constructSignatures.length) {
- constructSignatures = getDefaultConstructSignatures(classType);
- }
- if (classType.baseTypes.length) {
- members = createSymbolTable(getNamedMembers(members));
- addInheritedMembers(members, getPropertiesOfObjectType(getTypeOfSymbol(classType.baseTypes[0].symbol)));
- }
- }
- var stringIndexType: Type = undefined;
- var numberIndexType: Type = (symbol.flags & SymbolFlags.Enum) ? stringType : undefined;
- }
- setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
- }
-
- function resolveObjectOrUnionTypeMembers(type: ObjectType): ResolvedType {
- if (!(type).members) {
- 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 {
- resolveTypeReferenceMembers(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 resolveObjectOrUnionTypeMembers(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) {
- var resolved = resolveObjectOrUnionTypeMembers(type);
- if (hasProperty(resolved.members, name)) {
- var symbol = resolved.members[name];
- if (symbolIsValue(symbol)) {
- return symbol;
- }
- }
- }
- }
-
- function getPropertiesOfUnionType(type: UnionType): Symbol[] {
- var result: Symbol[] = [];
- forEach(getPropertiesOfType(type.types[0]), prop => {
- var unionProp = getPropertyOfUnionType(type, prop.name);
- if (unionProp) {
- result.push(unionProp);
- }
- });
- return result;
- }
-
- function getPropertiesOfType(type: Type): Symbol[] {
- if (type.flags & TypeFlags.Union) {
- return getPropertiesOfUnionType(type);
- }
- return getPropertiesOfObjectType(getApparentType(type));
- }
-
- // For a type parameter, return the base constraint of the type parameter. For the string, number, and
- // boolean 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) {
- do {
- type = getConstraintOfTypeParameter(type);
- } while (type && type.flags & TypeFlags.TypeParameter);
- if (!type) {
- type = emptyObjectType;
- }
- }
- if (type.flags & TypeFlags.StringLike) {
- type = globalStringType;
- }
- else if (type.flags & TypeFlags.NumberLike) {
- type = globalNumberType;
- }
- else if (type.flags & TypeFlags.Boolean) {
- type = globalBooleanType;
- }
- return type;
- }
-
- function createUnionProperty(unionType: UnionType, name: string): Symbol {
- var types = unionType.types;
- var props: Symbol[];
- for (var i = 0; i < types.length; i++) {
- var type = getApparentType(types[i]);
- if (type !== unknownType) {
- var prop = getPropertyOfType(type, name);
- if (!prop) {
- return undefined;
- }
- if (!props) {
- props = [prop];
- }
- else {
- props.push(prop);
- }
- }
- }
- var propTypes: Type[] = [];
- var declarations: Declaration[] = [];
- for (var i = 0; i < props.length; i++) {
- var prop = props[i];
- if (prop.declarations) {
- declarations.push.apply(declarations, prop.declarations);
- }
- propTypes.push(getTypeOfSymbol(prop));
- }
- var result = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.UnionProperty, name);
- result.unionType = unionType;
- result.declarations = declarations;
- result.type = getUnionType(propTypes);
- return result;
- }
-
- function getPropertyOfUnionType(type: UnionType, name: string): Symbol {
- var properties = type.resolvedProperties || (type.resolvedProperties = {});
- if (hasProperty(properties, name)) {
- return properties[name];
- }
- var property = createUnionProperty(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 primtive 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 {
- if (type.flags & TypeFlags.Union) {
- return getPropertyOfUnionType(type, name);
- }
- if (!(type.flags & TypeFlags.ObjectType)) {
- type = getApparentType(type);
- if (!(type.flags & TypeFlags.ObjectType)) {
- return undefined;
- }
- }
- var resolved = resolveObjectOrUnionTypeMembers(type);
- if (hasProperty(resolved.members, name)) {
- var symbol = resolved.members[name];
- if (symbolIsValue(symbol)) {
- return symbol;
- }
- }
- if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
- var symbol = getPropertyOfObjectType(globalFunctionType, name);
- if (symbol) return symbol;
- }
- return getPropertyOfObjectType(globalObjectType, name);
- }
-
- function getSignaturesOfObjectOrUnionType(type: Type, kind: SignatureKind): Signature[] {
- if (type.flags & (TypeFlags.ObjectType | TypeFlags.Union)) {
- var resolved = resolveObjectOrUnionTypeMembers(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 primtive types and type parameters are to their apparent types.
- function getSignaturesOfType(type: Type, kind: SignatureKind): Signature[] {
- return getSignaturesOfObjectOrUnionType(getApparentType(type), kind);
- }
-
- function getIndexTypeOfObjectOrUnionType(type: Type, kind: IndexKind): Type {
- if (type.flags & (TypeFlags.ObjectType | TypeFlags.Union)) {
- var resolved = resolveObjectOrUnionTypeMembers(type);
- return kind === IndexKind.String ? resolved.stringIndexType : resolved.numberIndexType;
- }
- }
-
- // Return the index type of the given kind in the given type. Creates synthetic union index types when necessary and
- // maps primtive types and type parameters are to their apparent types.
- function getIndexTypeOfType(type: Type, kind: IndexKind): Type {
- return getIndexTypeOfObjectOrUnionType(getApparentType(type), kind);
- }
-
- // Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual
- // type checking functions).
- function getTypeParametersFromDeclaration(typeParameterDeclarations: TypeParameterDeclaration[]): TypeParameter[] {
- var result: TypeParameter[] = [];
- forEach(typeParameterDeclarations, node => {
- var tp = getDeclaredTypeOfTypeParameter(node.symbol);
- if (!contains(result, tp)) {
- result.push(tp);
- }
- });
- return result;
- }
-
- function getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature {
- var links = getNodeLinks(declaration);
- if (!links.resolvedSignature) {
- var classType = declaration.kind === SyntaxKind.Constructor ? getDeclaredTypeOfClass((declaration.parent).symbol) : undefined;
- var typeParameters = classType ? classType.typeParameters :
- declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) : undefined;
- var parameters: Symbol[] = [];
- var hasStringLiterals = false;
- var minArgumentCount = -1;
- for (var i = 0, n = declaration.parameters.length; i < n; i++) {
- var param = declaration.parameters[i];
- parameters.push(param.symbol);
- if (param.type && param.type.kind === SyntaxKind.StringLiteral) {
- hasStringLiterals = true;
- }
- if (minArgumentCount < 0) {
- if (param.initializer || param.flags & (NodeFlags.QuestionMark | NodeFlags.Rest)) {
- minArgumentCount = i;
- }
- }
- }
-
- if (minArgumentCount < 0) {
- minArgumentCount = declaration.parameters.length;
- }
-
- var returnType: Type;
- if (classType) {
- returnType = classType;
- }
- else if (declaration.type) {
- returnType = getTypeFromTypeNode(declaration.type);
- }
- else {
- // 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) {
- var setter = getDeclarationOfKind(declaration.symbol, SyntaxKind.SetAccessor);
- returnType = getAnnotatedAccessorType(setter);
- }
-
- if (!returnType && !(declaration).body) {
- returnType = anyType;
- }
- }
-
- links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType,
- minArgumentCount, hasRestParameters(declaration), hasStringLiterals);
- }
- return links.resolvedSignature;
- }
-
- function getSignaturesOfSymbol(symbol: Symbol): Signature[] {
- if (!symbol) return emptyArray;
- var result: Signature[] = [];
- for (var i = 0, len = symbol.declarations.length; i < len; i++) {
- var node = symbol.declarations[i];
- switch (node.kind) {
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.Method:
- case SyntaxKind.Constructor:
- case SyntaxKind.CallSignature:
- case SyntaxKind.ConstructSignature:
- case SyntaxKind.IndexSignature:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.ArrowFunction:
- // 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) {
- var 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 getReturnTypeOfSignature(signature: Signature): Type {
- if (!signature.resolvedReturnType) {
- signature.resolvedReturnType = resolvingType;
- if (signature.target) {
- var type = instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper);
- }
- else if (signature.unionSignatures) {
- var type = getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature));
- }
- else {
- var type = getReturnTypeFromBody(signature.declaration);
- }
- if (signature.resolvedReturnType === resolvingType) {
- signature.resolvedReturnType = type;
- }
- }
- else if (signature.resolvedReturnType === resolvingType) {
- signature.resolvedReturnType = anyType;
- if (compilerOptions.noImplicitAny) {
- var 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);
- }
- }
- }
- return signature.resolvedReturnType;
- }
-
- function getRestTypeOfSignature(signature: Signature): Type {
- if (signature.hasRestParameter) {
- var type = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]);
- 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), 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), 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) {
- var isConstructor = signature.declaration.kind === SyntaxKind.Constructor || signature.declaration.kind === SyntaxKind.ConstructSignature;
- var 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 {
- var syntaxKind = kind === IndexKind.Number ? SyntaxKind.NumberKeyword : SyntaxKind.StringKeyword;
- var indexSymbol = getIndexSymbol(symbol);
- if (indexSymbol) {
- var len = indexSymbol.declarations.length;
- for (var i = 0; i < len; i++) {
- var node = indexSymbol.declarations[i];
- if (node.parameters.length === 1) {
- var parameter = node.parameters[0];
- if (parameter && parameter.type && parameter.type.kind === syntaxKind) {
- return node;
- }
- }
- }
- }
-
- return undefined;
- }
-
- function getIndexTypeOfSymbol(symbol: Symbol, kind: IndexKind): Type {
- var declaration = getIndexDeclarationOfSymbol(symbol, kind);
- return declaration
- ? declaration.type ? getTypeFromTypeNode(declaration.type) : anyType
- : undefined;
- }
-
- function getConstraintOfTypeParameter(type: TypeParameter): Type {
- if (!type.constraint) {
- if (type.target) {
- var targetConstraint = getConstraintOfTypeParameter(type.target);
- type.constraint = targetConstraint ? instantiateType(targetConstraint, type.mapper) : noConstraintType;
- }
- else {
- type.constraint = getTypeFromTypeNode((getDeclarationOfKind(type.symbol, SyntaxKind.TypeParameter)).constraint);
- }
- }
- return type.constraint === noConstraintType ? undefined : type.constraint;
- }
-
- function getTypeListId(types: Type[]) {
- switch (types.length) {
- case 1:
- return "" + types[0].id;
- case 2:
- return types[0].id + "," + types[1].id;
- default:
- var result = "";
- for (var i = 0; i < types.length; i++) {
- if (i > 0) result += ",";
- result += types[i].id;
- }
- return result;
- }
- }
-
- function createTypeReference(target: GenericType, typeArguments: Type[]): TypeReference {
- var id = getTypeListId(typeArguments);
- var type = target.instantiations[id];
- if (!type) {
- type = target.instantiations[id] = createObjectType(TypeFlags.Reference, target.symbol);
- type.target = target;
- type.typeArguments = typeArguments;
- }
- return type;
- }
-
- function isTypeParameterReferenceIllegalInConstraint(typeReferenceNode: TypeReferenceNode, typeParameterSymbol: Symbol): boolean {
- var links = getNodeLinks(typeReferenceNode);
- if (links.isIllegalTypeReferenceInConstraint !== undefined) {
- return links.isIllegalTypeReferenceInConstraint;
- }
-
- // bubble up to the declaration
- var currentNode: Node = typeReferenceNode;
- // forEach === exists
- while (!forEach(typeParameterSymbol.declarations, d => d.parent === currentNode.parent)) {
- currentNode = currentNode.parent;
- }
- // if last step was made from the type parameter this means that path has started somewhere in constraint which is illegal
- links.isIllegalTypeReferenceInConstraint = currentNode.kind === SyntaxKind.TypeParameter;
- return links.isIllegalTypeReferenceInConstraint;
- }
-
- function checkTypeParameterHasIllegalReferencesInConstraint(typeParameter: TypeParameterDeclaration): void {
- var typeParameterSymbol: Symbol;
- function check(n: Node): void {
- if (n.kind === SyntaxKind.TypeReference && (n).typeName.kind === SyntaxKind.Identifier) {
- var links = getNodeLinks(n);
- if (links.isIllegalTypeReferenceInConstraint === undefined) {
- var symbol = resolveName(typeParameter, ((n).typeName).text, SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
- if (symbol && (symbol.flags & SymbolFlags.TypeParameter)) {
- // TypeScript 1.0 spec (April 2014): 3.4.1
- // Type parameters declared in a particular type parameter list
- // may not be referenced in constraints in that type parameter list
-
- // symbol.declaration.parent === typeParameter.parent
- // -> typeParameter and symbol.declaration originate from the same type parameter list
- // -> illegal for all declarations in symbol
- // forEach === exists
- links.isIllegalTypeReferenceInConstraint = forEach(symbol.declarations, d => d.parent == typeParameter.parent);
- }
- }
- if (links.isIllegalTypeReferenceInConstraint) {
- error(typeParameter, Diagnostics.Constraint_of_a_type_parameter_cannot_reference_any_type_parameter_from_the_same_type_parameter_list);
- }
- }
- forEachChild(n, check);
- }
-
- if (typeParameter.constraint) {
- typeParameterSymbol = getSymbolOfNode(typeParameter);
- check(typeParameter.constraint);
- }
- }
-
- function getTypeFromTypeReferenceNode(node: TypeReferenceNode): Type {
- var links = getNodeLinks(node);
- if (!links.resolvedType) {
- var symbol = resolveEntityName(node, node.typeName, SymbolFlags.Type);
- if (symbol) {
- var type: Type;
- if ((symbol.flags & SymbolFlags.TypeParameter) && isTypeParameterReferenceIllegalInConstraint(node, symbol)) {
- // TypeScript 1.0 spec (April 2014): 3.4.1
- // Type parameters declared in a particular type parameter list
- // may not be referenced in constraints in that type parameter list
- // Implementation: such type references are resolved to 'unknown' type that usually denotes error
- type = unknownType;
- }
- else {
- type = getDeclaredTypeOfSymbol(symbol);
- if (type.flags & (TypeFlags.Class | TypeFlags.Interface) && type.flags & TypeFlags.Reference) {
- var typeParameters = (type).typeParameters;
- if (node.typeArguments && node.typeArguments.length === typeParameters.length) {
- type = createTypeReference(type, map(node.typeArguments, getTypeFromTypeNode));
- }
- else {
- error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length);
- type = undefined;
- }
- }
- else {
- if (node.typeArguments) {
- error(node, Diagnostics.Type_0_is_not_generic, typeToString(type));
- type = undefined;
- }
- }
- }
- }
- links.resolvedType = type || unknownType;
- }
- return links.resolvedType;
- }
-
- function getTypeFromTypeQueryNode(node: TypeQueryNode): Type {
- var 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 {
- var declarations = symbol.declarations;
- for (var i = 0; i < declarations.length; i++) {
- var declaration = declarations[i];
- switch (declaration.kind) {
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.InterfaceDeclaration:
- case SyntaxKind.EnumDeclaration:
- return declaration;
- }
- }
- }
-
- if (!symbol) {
- return emptyObjectType;
- }
- var 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 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 emptyObjectType;
- }
- return type;
- }
-
- function getGlobalSymbol(name: string): Symbol {
- return resolveName(undefined, name, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0, name);
- }
-
- function getGlobalType(name: string): ObjectType {
- return getTypeOfGlobalSymbol(getGlobalSymbol(name), 0);
- }
-
- function createArrayType(elementType: Type): Type {
- // globalArrayType will be undefined if we get here during creation of the Array type. This for example happens if
- // user code augments the Array type with call or construct signatures that have an array type as the return type.
- // We instead use globalArraySymbol to obtain the (not yet fully constructed) Array type.
- var arrayType = globalArrayType || getDeclaredTypeOfSymbol(globalArraySymbol);
- return arrayType !== emptyObjectType ? createTypeReference(arrayType, [elementType]) : emptyObjectType;
- }
-
- function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type {
- var links = getNodeLinks(node);
- if (!links.resolvedType) {
- links.resolvedType = createArrayType(getTypeFromTypeNode(node.elementType));
- }
- return links.resolvedType;
- }
-
- function createTupleType(elementTypes: Type[]) {
- var id = getTypeListId(elementTypes);
- var type = tupleTypes[id];
- if (!type) {
- type = tupleTypes[id] = createObjectType(TypeFlags.Tuple);
- type.elementTypes = elementTypes;
- }
- return type;
- }
-
- function getTypeFromTupleTypeNode(node: TupleTypeNode): Type {
- var links = getNodeLinks(node);
- if (!links.resolvedType) {
- links.resolvedType = createTupleType(map(node.elementTypes, getTypeFromTypeNode));
- }
- return links.resolvedType;
- }
-
- function addTypeToSortedSet(sortedSet: Type[], type: Type) {
- if (type.flags & TypeFlags.Union) {
- addTypesToSortedSet(sortedSet, (type).types);
- }
- else {
- var i = 0;
- var id = type.id;
- while (i < sortedSet.length && sortedSet[i].id < id) {
- i++;
- }
- if (i === sortedSet.length || sortedSet[i].id !== id) {
- sortedSet.splice(i, 0, type);
- }
- }
- }
-
- function addTypesToSortedSet(sortedTypes: Type[], types: Type[]) {
- for (var i = 0, len = types.length; i < len; i++) {
- addTypeToSortedSet(sortedTypes, types[i]);
- }
- }
-
- function isSubtypeOfAny(candidate: Type, types: Type[]): boolean {
- for (var i = 0, len = types.length; i < len; i++) {
- if (candidate !== types[i] && isTypeSubtypeOf(candidate, types[i])) {
- return true;
- }
- }
- return false;
- }
-
- function removeSubtypes(types: Type[]) {
- var i = types.length;
- while (i > 0) {
- i--;
- if (isSubtypeOfAny(types[i], types)) {
- types.splice(i, 1);
- }
- }
- }
-
- function containsAnyType(types: Type[]) {
- for (var i = 0; i < types.length; i++) {
- if (types[i].flags & TypeFlags.Any) {
- return true;
- }
- }
- return false;
- }
-
- function removeAllButLast(types: Type[], typeToRemove: Type) {
- var i = types.length;
- while (i > 0 && types.length > 1) {
- i--;
- if (types[i] === typeToRemove) {
- types.splice(i, 1);
- }
- }
- }
-
- function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type {
- if (types.length === 0) {
- return emptyObjectType;
- }
- var sortedTypes: Type[] = [];
- addTypesToSortedSet(sortedTypes, types);
- if (noSubtypeReduction) {
- if (containsAnyType(sortedTypes)) {
- return anyType;
- }
- removeAllButLast(sortedTypes, undefinedType);
- removeAllButLast(sortedTypes, nullType);
- }
- else {
- removeSubtypes(sortedTypes);
- }
- if (sortedTypes.length === 1) {
- return sortedTypes[0];
- }
- var id = getTypeListId(sortedTypes);
- var type = unionTypes[id];
- if (!type) {
- type = unionTypes[id] = createObjectType(TypeFlags.Union);
- type.types = sortedTypes;
- }
- return type;
- }
-
- function getTypeFromUnionTypeNode(node: UnionTypeNode): Type {
- var links = getNodeLinks(node);
- if (!links.resolvedType) {
- links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), /*noSubtypeReduction*/ true);
- }
- return links.resolvedType;
- }
-
- function getTypeFromTypeLiteralNode(node: TypeLiteralNode): Type {
- var 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 getStringLiteralType(node: StringLiteralTypeNode): StringLiteralType {
- if (hasProperty(stringLiteralTypes, node.text)) return stringLiteralTypes[node.text];
- var type = stringLiteralTypes[node.text] = createType(TypeFlags.StringLiteral);
- type.text = getTextOfNode(node);
- return type;
- }
-
- function getTypeFromStringLiteral(node: StringLiteralTypeNode): Type {
- var links = getNodeLinks(node);
- if (!links.resolvedType) {
- links.resolvedType = getStringLiteralType(node);
- }
- return links.resolvedType;
- }
-
- function getTypeFromTypeNode(node: TypeNode): Type {
- switch (node.kind) {
- case SyntaxKind.AnyKeyword:
- return anyType;
- case SyntaxKind.StringKeyword:
- return stringType;
- case SyntaxKind.NumberKeyword:
- return numberType;
- case SyntaxKind.BooleanKeyword:
- return booleanType;
- case SyntaxKind.VoidKeyword:
- return voidType;
- case SyntaxKind.StringLiteral:
- return getTypeFromStringLiteral(node);
- case SyntaxKind.TypeReference:
- return getTypeFromTypeReferenceNode(node);
- case SyntaxKind.TypeQuery:
- return getTypeFromTypeQueryNode(node);
- case SyntaxKind.ArrayType:
- return getTypeFromArrayTypeNode(node);
- case SyntaxKind.TupleType:
- return getTypeFromTupleTypeNode(node);
- case SyntaxKind.UnionType:
- return getTypeFromUnionTypeNode(node);
- case SyntaxKind.ParenType:
- return getTypeFromTypeNode((node).type);
- case SyntaxKind.TypeLiteral:
- return getTypeFromTypeLiteralNode(node);
- // This function assumes that an identifier or qualified name is a type expression
- // Callers should first ensure this by calling isTypeNode
- case SyntaxKind.Identifier:
- case SyntaxKind.QualifiedName:
- var symbol = getSymbolInfo(node);
- return symbol && getDeclaredTypeOfSymbol(symbol);
- default:
- return unknownType;
- }
- }
-
- function instantiateList(items: T[], mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): T[] {
- if (items && items.length) {
- var result: T[] = [];
- for (var i = 0; i < items.length; i++) {
- result.push(instantiator(items[i], 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 createTypeMapper(sources: Type[], targets: Type[]): TypeMapper {
- switch (sources.length) {
- case 1: return createUnaryTypeMapper(sources[0], targets[0]);
- case 2: return createBinaryTypeMapper(sources[0], targets[0], sources[1], targets[1]);
- }
- return t => {
- for (var i = 0; i < sources.length; i++) {
- if (t === sources[i]) return targets[i];
- }
- return t;
- };
- }
-
- function createUnaryTypeEraser(source: Type): TypeMapper {
- return t => t === source ? anyType : t;
- }
-
- function createBinaryTypeEraser(source1: Type, source2: Type): TypeMapper {
- return t => t === source1 || t === source2 ? anyType : t;
- }
-
- function createTypeEraser(sources: Type[]): TypeMapper {
- switch (sources.length) {
- case 1: return createUnaryTypeEraser(sources[0]);
- case 2: return createBinaryTypeEraser(sources[0], sources[1]);
- }
- return t => {
- for (var i = 0; i < sources.length; i++) {
- if (t === sources[i]) return anyType;
- }
- return t;
- };
- }
-
- function createInferenceMapper(context: InferenceContext): TypeMapper {
- return t => {
- for (var i = 0; i < context.typeParameters.length; i++) {
- if (t === context.typeParameters[i]) {
- return getInferredType(context, i);
- }
- }
- return t;
- }
- }
-
- function identityMapper(type: Type): Type {
- return type;
- }
-
- function combineTypeMappers(mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper {
- return t => mapper2(mapper1(t));
- }
-
- function instantiateTypeParameter(typeParameter: TypeParameter, mapper: TypeMapper): TypeParameter {
- var result = createType(TypeFlags.TypeParameter);
- result.symbol = typeParameter.symbol;
- if (typeParameter.constraint) {
- result.constraint = instantiateType(typeParameter.constraint, mapper);
- }
- else {
- result.target = typeParameter;
- result.mapper = mapper;
- }
- return result;
- }
-
- function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature {
- if (signature.typeParameters && !eraseTypeParameters) {
- var freshTypeParameters = instantiateList(signature.typeParameters, mapper, instantiateTypeParameter);
- mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper);
- }
- var result = createSignature(signature.declaration, freshTypeParameters,
- instantiateList(signature.parameters, mapper, instantiateSymbol),
- signature.resolvedReturnType ? instantiateType(signature.resolvedReturnType, mapper) : undefined,
- 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) {
- var 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.
- var 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: ObjectType, mapper: TypeMapper): ObjectType {
- var result = createObjectType(TypeFlags.Anonymous, type.symbol);
- result.properties = instantiateList(getPropertiesOfObjectType(type), mapper, instantiateSymbol);
- result.members = createSymbolTable(result.properties);
- result.callSignatures = instantiateList(getSignaturesOfType(type, SignatureKind.Call), mapper, instantiateSignature);
- result.constructSignatures = instantiateList(getSignaturesOfType(type, SignatureKind.Construct), mapper, instantiateSignature);
- var stringIndexType = getIndexTypeOfType(type, IndexKind.String);
- var numberIndexType = getIndexTypeOfType(type, IndexKind.Number);
- if (stringIndexType) result.stringIndexType = instantiateType(stringIndexType, mapper);
- if (numberIndexType) result.numberIndexType = instantiateType(numberIndexType, mapper);
- return result;
- }
-
- function instantiateType(type: Type, mapper: TypeMapper): Type {
- if (mapper !== identityMapper) {
- if (type.flags & TypeFlags.TypeParameter) {
- return mapper(type);
- }
- if (type.flags & TypeFlags.Anonymous) {
- return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) ?
- instantiateAnonymousType(type, mapper) : type;
- }
- if (type.flags & TypeFlags.Reference) {
- return createTypeReference((type).target, instantiateList((type).typeArguments, mapper, instantiateType));
- }
- if (type.flags & TypeFlags.Tuple) {
- return createTupleType(instantiateList((type).elementTypes, mapper, instantiateType));
- }
- if (type.flags & TypeFlags.Union) {
- return getUnionType(instantiateList((type).types, mapper, instantiateType), /*noSubtypeReduction*/ true);
- }
- }
- return type;
- }
-
- // Returns true if the given expression contains (at any level of nesting) a function or arrow expression
- // that is subject to contextual typing.
- function isContextSensitiveExpression(node: Expression): boolean {
- switch (node.kind) {
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.ArrowFunction:
- return !(node).typeParameters && !forEach((node).parameters, p => p.type);
- case SyntaxKind.ObjectLiteral:
- return forEach((node).properties, p =>
- p.kind === SyntaxKind.PropertyAssignment && isContextSensitiveExpression((p).initializer));
- case SyntaxKind.ArrayLiteral:
- return forEach((node).elements, e => isContextSensitiveExpression(e));
- case SyntaxKind.ConditionalExpression:
- return isContextSensitiveExpression((node).whenTrue) ||
- isContextSensitiveExpression((node).whenFalse);
- case SyntaxKind.BinaryExpression:
- return (node).operator === SyntaxKind.BarBarToken &&
- (isContextSensitiveExpression((node).left) || isContextSensitiveExpression((node).right));
- }
- return false;
- }
-
- function getTypeWithoutConstructors(type: Type): Type {
- if (type.flags & TypeFlags.ObjectType) {
- var resolved = resolveObjectOrUnionTypeMembers(type);
- if (resolved.constructSignatures.length) {
- var result = createObjectType(TypeFlags.Anonymous, type.symbol);
- result.members = resolved.members;
- result.properties = resolved.properties;
- result.callSignatures = resolved.callSignatures;
- result.constructSignatures = emptyArray;
- type = result;
- }
- }
- return type;
- }
-
- // TYPE CHECKING
-
- var subtypeRelation: Map = {};
- var assignableRelation: Map = {};
- var identityRelation: Map = {};
-
- function isTypeIdenticalTo(source: Type, target: Type): boolean {
- return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
- }
-
- function compareTypes(source: Type, target: Type): Ternary {
- return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
- }
-
- function isTypeSubtypeOf(source: Type, target: Type): boolean {
- return checkTypeSubtypeOf(source, target, /*errorNode*/ undefined);
- }
-
- function isTypeAssignableTo(source: Type, target: Type): boolean {
- return checkTypeAssignableTo(source, target, /*errorNode*/ undefined);
- }
-
- function checkTypeSubtypeOf(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: DiagnosticMessageChain): boolean {
- return checkTypeRelatedTo(source, target, subtypeRelation, errorNode, headMessage, containingMessageChain);
- }
-
- function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage): boolean {
- return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage);
- }
-
- function isSignatureAssignableTo(source: Signature, target: Signature): boolean {
- var sourceType = getOrCreateTypeFromSignature(source);
- var targetType = getOrCreateTypeFromSignature(target);
- return checkTypeRelatedTo(sourceType, targetType, assignableRelation, /*errorNode*/ undefined);
- }
-
- function checkTypeRelatedTo(
- source: Type,
- target: Type,
- relation: Map,
- errorNode: Node,
- headMessage?: DiagnosticMessage,
- containingMessageChain?: DiagnosticMessageChain): boolean {
-
- var errorInfo: DiagnosticMessageChain;
- var sourceStack: ObjectType[];
- var targetStack: ObjectType[];
- var expandingFlags: number;
- var depth = 0;
- var overflow = false;
-
- Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking");
-
- var result = isRelatedTo(source, target, errorNode !== undefined, headMessage);
- if (overflow) {
- error(errorNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target));
- }
- else if (errorInfo) {
- if (containingMessageChain) {
- errorInfo = concatenateDiagnosticMessageChains(containingMessageChain, errorInfo);
- }
- addDiagnostic(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo, program.getCompilerHost().getNewLine()));
- }
- return result !== Ternary.False;
-
- function reportError(message: DiagnosticMessage, arg0?: string, arg1?: string, arg2?: string): void {
- errorInfo = chainDiagnosticMessages(errorInfo, message, arg0, arg1, arg2);
- }
-
- // Compare two types and return
- // Ternary.True if they are related with no assumptions,
- // Ternary.Maybe if they are related with assumptions of other relationships, or
- // Ternary.False if they are not related.
- function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary {
- var result: Ternary;
- if (relation === identityRelation) {
- // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases
- if (source === target) return Ternary.True;
- }
- else {
- if (source === target) return Ternary.True;
- if (target.flags & TypeFlags.Any) return Ternary.True;
- if (source === undefinedType) return Ternary.True;
- if (source === nullType && target !== undefinedType) return Ternary.True;
- if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True;
- if (source.flags & TypeFlags.StringLiteral && target === stringType) return Ternary.True;
- if (relation === assignableRelation) {
- if (source.flags & TypeFlags.Any) return Ternary.True;
- if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True;
- }
- }
- if (source.flags & TypeFlags.Union) {
- if (result = unionTypeRelatedToType(source, target, reportErrors)) {
- return result;
- }
- }
- else if (target.flags & TypeFlags.Union) {
- if (result = typeRelatedToUnionType(source, target, reportErrors)) {
- return result;
- }
- }
- else if (source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.TypeParameter) {
- if (result = typeParameterRelatedTo(source, target, reportErrors)) {
- return result;
- }
- }
- else {
- var saveErrorInfo = errorInfo;
- if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (source).target === (target).target) {
- // We have type references to same target type, see if relationship holds for all type arguments
- if (result = typesRelatedTo((source).typeArguments, (target).typeArguments, reportErrors)) {
- return result;
- }
- }
- // Even if relationship doesn't hold for type arguments, it may hold in a structural comparison
- // Report structural errors only if we haven't reported any errors yet
- var reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo;
- // identity relation does not use apparent type
- var sourceOrApparentType = relation === identityRelation ? source : getApparentType(source);
- if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType &&
- (result = objectTypeRelatedTo(sourceOrApparentType, target, reportStructuralErrors))) {
- errorInfo = saveErrorInfo;
- return result;
- }
- }
- if (reportErrors) {
- headMessage = headMessage || Diagnostics.Type_0_is_not_assignable_to_type_1;
- reportError(headMessage, typeToString(source), typeToString(target));
- }
- return Ternary.False;
- }
-
- function typeRelatedToUnionType(source: Type, target: UnionType, reportErrors: boolean): Ternary {
- var targetTypes = target.types;
- for (var i = 0, len = targetTypes.length; i < len; i++) {
- var related = isRelatedTo(source, targetTypes[i], reportErrors && i === len - 1);
- if (related) {
- return related;
- }
- }
- return Ternary.False;
- }
-
- function unionTypeRelatedToType(source: UnionType, target: Type, reportErrors: boolean): Ternary {
- var result = Ternary.True;
- var sourceTypes = source.types;
- for (var i = 0, len = sourceTypes.length; i < len; i++) {
- var related = isRelatedTo(sourceTypes[i], target, reportErrors);
- if (!related) {
- return Ternary.False;
- }
- result &= related;
- }
- return result;
- }
-
- function typesRelatedTo(sources: Type[], targets: Type[], reportErrors: boolean): Ternary {
- var result = Ternary.True;
- for (var i = 0, len = sources.length; i < len; i++) {
- var related = isRelatedTo(sources[i], targets[i], reportErrors);
- if (!related) {
- return Ternary.False;
- }
- result &= related;
- }
- return result;
- }
-
- function typeParameterRelatedTo(source: TypeParameter, target: TypeParameter, reportErrors: boolean): Ternary {
- if (relation === identityRelation) {
- if (source.symbol.name !== target.symbol.name) {
- return Ternary.False;
- }
- // covers case when both type parameters does not have constraint (both equal to noConstraintType)
- if (source.constraint === target.constraint) {
- return Ternary.True;
- }
- if (source.constraint === noConstraintType || target.constraint === noConstraintType) {
- return Ternary.False;
- }
- return isRelatedTo(source.constraint, target.constraint, reportErrors);
- }
- else {
- while (true) {
- var constraint = getConstraintOfTypeParameter(source);
- if (constraint === target) return Ternary.True;
- if (!(constraint && constraint.flags & TypeFlags.TypeParameter)) break;
- source = constraint;
- }
- return Ternary.False;
- }
- }
-
- // Determine if two object types are related by structure. First, check if the result is already available in the global cache.
- // Second, check if we have already started a comparison of the given two types in which case we assume the result to be true.
- // Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are
- // equal and infinitely expanding. Fourth, if we have reached a depth of 100 nested comparisons, assume we have runaway recursion
- // and issue an error. Otherwise, actually compare the structure of the two types.
- function objectTypeRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary {
- if (overflow) {
- return Ternary.False;
- }
- var id = source.id + "," + target.id;
- var related = relation[id];
- if (related !== undefined) {
- return related;
- }
- if (depth > 0) {
- for (var i = 0; i < depth; i++) {
- // If source and target are already being compared, consider them related with assumptions
- if (source === sourceStack[i] && target === targetStack[i]) {
- return Ternary.Maybe;
- }
- }
- if (depth === 100) {
- overflow = true;
- return Ternary.False;
- }
- }
- else {
- sourceStack = [];
- targetStack = [];
- expandingFlags = 0;
- }
- sourceStack[depth] = source;
- targetStack[depth] = target;
- depth++;
- var saveExpandingFlags = expandingFlags;
- if (!(expandingFlags & 1) && isDeeplyNestedGeneric(source, sourceStack)) expandingFlags |= 1;
- if (!(expandingFlags & 2) && isDeeplyNestedGeneric(target, targetStack)) expandingFlags |= 2;
- if (expandingFlags === 3) {
- var result = Ternary.True;
- }
- else {
- var result = propertiesRelatedTo(source, target, reportErrors);
- if (result) {
- result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportErrors);
- if (result) {
- result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportErrors);
- if (result) {
- result &= stringIndexTypesRelatedTo(source, target, reportErrors);
- if (result) {
- result &= numberIndexTypesRelatedTo(source, target, reportErrors);
- }
- }
- }
- }
- }
- expandingFlags = saveExpandingFlags;
- depth--;
- // Only cache results that are free of assumptions
- if (result !== Ternary.Maybe) {
- relation[id] = result;
- }
- return result;
- }
-
- // Return true if the given type is part of a deeply nested chain of generic instantiations. We consider this to be the case
- // when structural type comparisons have been started for 10 or more instantiations of the same generic type. It is possible,
- // though highly unlikely, for this test to be true in a situation where a chain of instantiations is not infinitely expanding.
- // Effectively, we will generate a false positive when two types are structurally equal to at least 10 levels, but unequal at
- // some level beyond that.
- function isDeeplyNestedGeneric(type: ObjectType, stack: ObjectType[]): boolean {
- if (type.flags & TypeFlags.Reference && depth >= 10) {
- var target = (type).target;
- var count = 0;
- for (var i = 0; i < depth; i++) {
- var t = stack[i];
- if (t.flags & TypeFlags.Reference && (t).target === target) {
- count++;
- if (count >= 10) return true;
- }
- }
- }
- return false;
- }
-
- function propertiesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary {
- if (relation === identityRelation) {
- return propertiesIdenticalTo(source, target);
- }
- var result = Ternary.True;
- var properties = getPropertiesOfObjectType(target);
- for (var i = 0; i < properties.length; i++) {
- var targetProp = properties[i];
- var sourceProp = getPropertyOfType(source, targetProp.name);
- if (sourceProp !== targetProp) {
- if (!sourceProp) {
- if (relation === subtypeRelation || !isOptionalProperty(targetProp)) {
- if (reportErrors) {
- reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(targetProp), typeToString(source));
- }
- return Ternary.False;
- }
- }
- else if (!(targetProp.flags & SymbolFlags.Prototype)) {
- var sourceFlags = getDeclarationFlagsFromSymbol(sourceProp);
- var targetFlags = getDeclarationFlagsFromSymbol(targetProp);
- if (sourceFlags & NodeFlags.Private || targetFlags & NodeFlags.Private) {
- if (sourceProp.valueDeclaration !== targetProp.valueDeclaration) {
- if (reportErrors) {
- if (sourceFlags & NodeFlags.Private && targetFlags & NodeFlags.Private) {
- reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp));
- }
- else {
- reportError(Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, symbolToString(targetProp),
- typeToString(sourceFlags & NodeFlags.Private ? source : target),
- typeToString(sourceFlags & NodeFlags.Private ? target : source));
- }
- }
- return Ternary.False;
- }
- }
- else if (targetFlags & NodeFlags.Protected) {
- var sourceDeclaredInClass = sourceProp.parent && sourceProp.parent.flags & SymbolFlags.Class;
- var sourceClass = sourceDeclaredInClass ? getDeclaredTypeOfSymbol(sourceProp.parent) : undefined;
- var targetClass = getDeclaredTypeOfSymbol(targetProp.parent);
- if (!sourceClass || !hasBaseType(sourceClass, targetClass)) {
- if (reportErrors) {
- reportError(Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2,
- symbolToString(targetProp), typeToString(sourceClass || source), typeToString(targetClass));
- }
- return Ternary.False;
- }
- }
- else if (sourceFlags & NodeFlags.Protected) {
- if (reportErrors) {
- reportError(Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2,
- symbolToString(targetProp), typeToString(source), typeToString(target));
- }
- return Ternary.False;
- }
- var related = isRelatedTo(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp), reportErrors);
- if (!related) {
- if (reportErrors) {
- reportError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp));
- }
- return Ternary.False;
- }
- result &= related;
- if (isOptionalProperty(sourceProp) && !isOptionalProperty(targetProp)) {
- // TypeScript 1.0 spec (April 2014): 3.8.3
- // S is a subtype of a type T, and T is a supertype of S if ...
- // S' and T are object types and, for each member M in T..
- // M is a property and S' contains a property N where
- // if M is a required property, N is also a required property
- // (M - property in T)
- // (N - property in S)
- if (reportErrors) {
- reportError(Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2,
- symbolToString(targetProp), typeToString(source), typeToString(target));
- }
- return Ternary.False;
- }
- }
- }
- }
- return result;
- }
-
- function propertiesIdenticalTo(source: ObjectType, target: ObjectType): Ternary {
- var sourceProperties = getPropertiesOfObjectType(source);
- var targetProperties = getPropertiesOfObjectType(target);
- if (sourceProperties.length !== targetProperties.length) {
- return Ternary.False;
- }
- var result = Ternary.True;
- for (var i = 0, len = sourceProperties.length; i < len; ++i) {
- var sourceProp = sourceProperties[i];
- var targetProp = getPropertyOfObjectType(target, sourceProp.name);
- if (!targetProp) {
- return Ternary.False;
- }
- var related = compareProperties(sourceProp, targetProp, isRelatedTo);
- if (!related) {
- return Ternary.False;
- }
- result &= related;
- }
- return result;
- }
-
- function signaturesRelatedTo(source: ObjectType, target: ObjectType, kind: SignatureKind, reportErrors: boolean): Ternary {
- if (relation === identityRelation) {
- return signaturesIdenticalTo(source, target, kind);
- }
- if (target === anyFunctionType || source === anyFunctionType) {
- return Ternary.True;
- }
- var sourceSignatures = getSignaturesOfType(source, kind);
- var targetSignatures = getSignaturesOfType(target, kind);
- var result = Ternary.True;
- var saveErrorInfo = errorInfo;
- outer: for (var i = 0; i < targetSignatures.length; i++) {
- var t = targetSignatures[i];
- if (!t.hasStringLiterals || target.flags & TypeFlags.FromSignature) {
- var localErrors = reportErrors;
- for (var j = 0; j < sourceSignatures.length; j++) {
- var s = sourceSignatures[j];
- if (!s.hasStringLiterals || source.flags & TypeFlags.FromSignature) {
- var related = signatureRelatedTo(s, t, localErrors);
- if (related) {
- result &= related;
- errorInfo = saveErrorInfo;
- continue outer;
- }
- // Only report errors from the first failure
- localErrors = false;
- }
- }
- return Ternary.False;
- }
- }
- return result;
- }
-
- function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
- if (source === target) {
- return Ternary.True;
- }
- if (!target.hasRestParameter && source.minArgumentCount > target.parameters.length) {
- return Ternary.False;
- }
- var sourceMax = source.parameters.length;
- var targetMax = target.parameters.length;
- var checkCount: number;
- if (source.hasRestParameter && target.hasRestParameter) {
- checkCount = sourceMax > targetMax ? sourceMax : targetMax;
- sourceMax--;
- targetMax--;
- }
- else if (source.hasRestParameter) {
- sourceMax--;
- checkCount = targetMax;
- }
- else if (target.hasRestParameter) {
- targetMax--;
- checkCount = sourceMax;
- }
- else {
- checkCount = sourceMax < targetMax ? sourceMax : targetMax;
- }
- // Spec 1.0 Section 3.8.3 & 3.8.4:
- // M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
- source = getErasedSignature(source);
- target = getErasedSignature(target);
- var result = Ternary.True;
- for (var i = 0; i < checkCount; i++) {
- var s = i < sourceMax ? getTypeOfSymbol(source.parameters[i]) : getRestTypeOfSignature(source);
- var t = i < targetMax ? getTypeOfSymbol(target.parameters[i]) : getRestTypeOfSignature(target);
- var saveErrorInfo = errorInfo;
- var related = isRelatedTo(s, t, reportErrors);
- if (!related) {
- related = isRelatedTo(t, s, false);
- if (!related) {
- if (reportErrors) {
- reportError(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
- source.parameters[i < sourceMax ? i : sourceMax].name,
- target.parameters[i < targetMax ? i : targetMax].name);
- }
- return Ternary.False;
- }
- errorInfo = saveErrorInfo;
- }
- result &= related;
- }
- var t = getReturnTypeOfSignature(target);
- if (t === voidType) return result;
- var s = getReturnTypeOfSignature(source);
- return result & isRelatedTo(s, t, reportErrors);
- }
-
- function signaturesIdenticalTo(source: ObjectType, target: ObjectType, kind: SignatureKind): Ternary {
- var sourceSignatures = getSignaturesOfType(source, kind);
- var targetSignatures = getSignaturesOfType(target, kind);
- if (sourceSignatures.length !== targetSignatures.length) {
- return Ternary.False;
- }
- var result = Ternary.True;
- for (var i = 0, len = sourceSignatures.length; i < len; ++i) {
- var related = compareSignatures(sourceSignatures[i], targetSignatures[i], /*compareReturnTypes*/ true, isRelatedTo);
- if (!related) {
- return Ternary.False;
- }
- result &= related;
- }
- return result;
- }
-
- function stringIndexTypesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary {
- if (relation === identityRelation) {
- return indexTypesIdenticalTo(IndexKind.String, source, target);
- }
- var targetType = getIndexTypeOfType(target, IndexKind.String);
- if (targetType) {
- var sourceType = getIndexTypeOfType(source, IndexKind.String);
- if (!sourceType) {
- if (reportErrors) {
- reportError(Diagnostics.Index_signature_is_missing_in_type_0, typeToString(source));
- }
- return Ternary.False;
- }
- var related = isRelatedTo(sourceType, targetType, reportErrors);
- if (!related) {
- if (reportErrors) {
- reportError(Diagnostics.Index_signatures_are_incompatible);
- }
- return Ternary.False;
- }
- return related;
- }
- return Ternary.True;
- }
-
- function numberIndexTypesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary {
- if (relation === identityRelation) {
- return indexTypesIdenticalTo(IndexKind.Number, source, target);
- }
- var targetType = getIndexTypeOfType(target, IndexKind.Number);
- if (targetType) {
- var sourceStringType = getIndexTypeOfType(source, IndexKind.String);
- var sourceNumberType = getIndexTypeOfType(source, IndexKind.Number);
- if (!(sourceStringType || sourceNumberType)) {
- if (reportErrors) {
- reportError(Diagnostics.Index_signature_is_missing_in_type_0, typeToString(source));
- }
- return Ternary.False;
- }
- if (sourceStringType && sourceNumberType) {
- // If we know for sure we're testing both string and numeric index types then only report errors from the second one
- var related = isRelatedTo(sourceStringType, targetType, false) || isRelatedTo(sourceNumberType, targetType, reportErrors);
- }
- else {
- var related = isRelatedTo(sourceStringType || sourceNumberType, targetType, reportErrors);
- }
- if (!related) {
- if (reportErrors) {
- reportError(Diagnostics.Index_signatures_are_incompatible);
- }
- return Ternary.False;
- }
- return related;
- }
- return Ternary.True;
- }
-
- function indexTypesIdenticalTo(indexKind: IndexKind, source: ObjectType, target: ObjectType): Ternary {
- var targetType = getIndexTypeOfType(target, indexKind);
- var sourceType = getIndexTypeOfType(source, indexKind);
- if (!sourceType && !targetType) {
- return Ternary.True;
- }
- if (sourceType && targetType) {
- return isRelatedTo(sourceType, targetType);
- }
- return Ternary.False;
- }
- }
-
- function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
- return compareProperties(sourceProp, targetProp, compareTypes) !== Ternary.False;
- }
-
- function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary {
- // Two members are considered identical when
- // - they are public properties with identical names, optionality, and types,
- // - they are private or protected properties originating in the same declaration and having identical types
- if (sourceProp === targetProp) {
- return Ternary.True;
- }
- var sourcePropAccessibility = getDeclarationFlagsFromSymbol(sourceProp) & (NodeFlags.Private | NodeFlags.Protected);
- var targetPropAccessibility = getDeclarationFlagsFromSymbol(targetProp) & (NodeFlags.Private | NodeFlags.Protected);
- if (sourcePropAccessibility !== targetPropAccessibility) {
- return Ternary.False;
- }
- if (sourcePropAccessibility) {
- if (getTargetSymbol(sourceProp) !== getTargetSymbol(targetProp)) {
- return Ternary.False;
- }
- }
- else {
- if (isOptionalProperty(sourceProp) !== isOptionalProperty(targetProp)) {
- return Ternary.False;
- }
- }
- return compareTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp));
- }
-
- function compareSignatures(source: Signature, target: Signature, compareReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
- if (source === target) {
- return Ternary.True;
- }
- if (source.parameters.length !== target.parameters.length ||
- source.minArgumentCount !== target.minArgumentCount ||
- source.hasRestParameter !== target.hasRestParameter) {
- return Ternary.False;
- }
- var result = Ternary.True;
- if (source.typeParameters && target.typeParameters) {
- if (source.typeParameters.length !== target.typeParameters.length) {
- return Ternary.False;
- }
- for (var i = 0, len = source.typeParameters.length; i < len; ++i) {
- var related = compareTypes(source.typeParameters[i], target.typeParameters[i]);
- if (!related) {
- return Ternary.False;
- }
- result &= related;
- }
- }
- else if (source.typeParameters || source.typeParameters) {
- return Ternary.False;
- }
- // Spec 1.0 Section 3.8.3 & 3.8.4:
- // M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
- source = getErasedSignature(source);
- target = getErasedSignature(target);
- for (var i = 0, len = source.parameters.length; i < len; i++) {
- var s = source.hasRestParameter && i === len - 1 ? getRestTypeOfSignature(source) : getTypeOfSymbol(source.parameters[i]);
- var t = target.hasRestParameter && i === len - 1 ? getRestTypeOfSignature(target) : getTypeOfSymbol(target.parameters[i]);
- var related = compareTypes(s, t);
- if (!related) {
- return Ternary.False;
- }
- result &= related;
- }
- if (compareReturnTypes) {
- result &= compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target));
- }
- return result;
- }
-
- function isSupertypeOfEach(candidate: Type, types: Type[]): boolean {
- for (var i = 0, len = types.length; i < len; i++) {
- if (candidate !== types[i] && !isTypeSubtypeOf(types[i], candidate)) return false;
- }
- return true;
- }
-
- function getCommonSupertype(types: Type[]): Type {
- return forEach(types, t => isSupertypeOfEach(t, types) ? t : undefined);
- }
-
- function reportNoCommonSupertypeError(types: Type[], errorLocation: Node, errorMessageChainHead: DiagnosticMessageChain): void {
- var bestSupertype: Type;
- var bestSupertypeDownfallType: Type; // The type that caused bestSupertype not to be the common supertype
- var bestSupertypeScore = 0;
-
- for (var i = 0; i < types.length; i++) {
- var score = 0;
- var downfallType: Type = undefined;
- for (var j = 0; j < types.length; j++) {
- if (isTypeSubtypeOf(types[j], types[i])) {
- score++;
- }
- else if (!downfallType) {
- downfallType = types[j];
- }
- }
-
- if (score > bestSupertypeScore) {
- bestSupertype = types[i];
- bestSupertypeDownfallType = downfallType;
- bestSupertypeScore = score;
- }
-
- // types.length - 1 is the maximum score, given that getCommonSupertype returned false
- if (bestSupertypeScore === types.length - 1) {
- break;
- }
- }
-
- // In the following errors, the {1} slot is before the {0} slot because checkTypeSubtypeOf supplies the
- // subtype as the first argument to the error
- checkTypeSubtypeOf(bestSupertypeDownfallType, bestSupertype, errorLocation,
- Diagnostics.Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0,
- errorMessageChainHead);
- }
-
- function isTypeOfObjectLiteral(type: Type): boolean {
- return (type.flags & TypeFlags.Anonymous) && type.symbol && (type.symbol.flags & SymbolFlags.ObjectLiteral) ? true : false;
- }
-
- function isArrayType(type: Type): boolean {
- return type.flags & TypeFlags.Reference && (type).target === globalArrayType;
- }
-
- function getInnermostTypeOfNestedArrayTypes(type: Type): Type {
- while (isArrayType(type)) {
- type = (type).typeArguments[0];
- }
- return type;
- }
-
- /* If we are widening on a literal, then we may need to the 'node' parameter for reporting purposes */
- function getWidenedType(type: Type, suppressNoImplicitAnyErrors?: boolean): Type {
- if (type.flags & (TypeFlags.Undefined | TypeFlags.Null)) {
- return anyType;
- }
- if (type.flags & TypeFlags.Union) {
- return getWidenedTypeOfUnion(type);
- }
- if (isTypeOfObjectLiteral(type)) {
- return getWidenedTypeOfObjectLiteral(type);
- }
- if (isArrayType(type)) {
- return getWidenedTypeOfArrayLiteral(type);
- }
- return type;
-
- function getWidenedTypeOfUnion(type: Type): Type {
- return getUnionType(map((type).types, t => getWidenedType(t, suppressNoImplicitAnyErrors)));
- }
-
- function getWidenedTypeOfObjectLiteral(type: Type): Type {
- var properties = getPropertiesOfObjectType(type);
- if (properties.length) {
- var widenedTypes: Type[] = [];
- var propTypeWasWidened: boolean = false;
- forEach(properties, p => {
- var propType = getTypeOfSymbol(p);
- var widenedType = getWidenedType(propType);
- if (propType !== widenedType) {
- propTypeWasWidened = true;
- if (!suppressNoImplicitAnyErrors && compilerOptions.noImplicitAny && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) {
- error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(widenedType));
- }
- }
- widenedTypes.push(widenedType);
- });
- if (propTypeWasWidened) {
- var members: SymbolTable = {};
- var index = 0;
- forEach(properties, p => {
- var symbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | p.flags, p.name);
- symbol.declarations = p.declarations;
- symbol.parent = p.parent;
- symbol.type = widenedTypes[index++];
- symbol.target = p;
- if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration;
- members[symbol.name] = symbol;
- });
- var stringIndexType = getIndexTypeOfType(type, IndexKind.String);
- var numberIndexType = getIndexTypeOfType(type, IndexKind.Number);
- if (stringIndexType) stringIndexType = getWidenedType(stringIndexType);
- if (numberIndexType) numberIndexType = getWidenedType(numberIndexType);
- type = createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexType, numberIndexType);
- }
- }
- return type;
- }
-
- function getWidenedTypeOfArrayLiteral(type: Type): Type {
- var elementType = (type).typeArguments[0];
- var widenedType = getWidenedType(elementType, suppressNoImplicitAnyErrors);
- type = elementType !== widenedType ? createArrayType(widenedType) : type;
- return type;
- }
- }
-
- function forEachMatchingParameterType(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) {
- var sourceMax = source.parameters.length;
- var targetMax = target.parameters.length;
- var count: number;
- if (source.hasRestParameter && target.hasRestParameter) {
- count = sourceMax > targetMax ? sourceMax : targetMax;
- sourceMax--;
- targetMax--;
- }
- else if (source.hasRestParameter) {
- sourceMax--;
- count = targetMax;
- }
- else if (target.hasRestParameter) {
- targetMax--;
- count = sourceMax;
- }
- else {
- count = sourceMax < targetMax ? sourceMax : targetMax;
- }
- for (var i = 0; i < count; i++) {
- var s = i < sourceMax ? getTypeOfSymbol(source.parameters[i]) : getRestTypeOfSignature(source);
- var t = i < targetMax ? getTypeOfSymbol(target.parameters[i]) : getRestTypeOfSignature(target);
- callback(s, t);
- }
- }
-
- function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
- var inferences: TypeInferences[] = [];
- for (var i = 0; i < typeParameters.length; i++) {
- inferences.push({ primary: undefined, secondary: undefined });
- }
- return {
- typeParameters: typeParameters,
- inferUnionTypes: inferUnionTypes,
- inferenceCount: 0,
- inferences: inferences,
- inferredTypes: new Array(typeParameters.length),
- };
- }
-
- function inferTypes(context: InferenceContext, source: Type, target: Type) {
- var sourceStack: Type[];
- var targetStack: Type[];
- var depth = 0;
- var inferiority = 0;
- inferFromTypes(source, target);
-
- function isInProcess(source: Type, target: Type) {
- for (var i = 0; i < depth; i++) {
- if (source === sourceStack[i] && target === targetStack[i]) return true;
- }
- return false;
- }
-
- function isWithinDepthLimit(type: Type, stack: Type[]) {
- if (depth >= 5) {
- var target = (type).target;
- var count = 0;
- for (var i = 0; i < depth; i++) {
- var t = stack[i];
- if (t.flags & TypeFlags.Reference && (t).target === target) count++;
- }
- return count < 5;
- }
- return true;
- }
-
- function inferFromTypes(source: Type, target: Type) {
- if (target.flags & TypeFlags.TypeParameter) {
- // If target is a type parameter, make an inference
- var typeParameters = context.typeParameters;
- for (var i = 0; i < typeParameters.length; i++) {
- if (target === typeParameters[i]) {
- var inferences = context.inferences[i];
- var candidates = inferiority ?
- inferences.secondary || (inferences.secondary = []) :
- inferences.primary || (inferences.primary = []);
- if (!contains(candidates, source)) candidates.push(source);
- break;
- }
- }
- }
- else if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (source).target === (target).target) {
- // If source and target are references to the same generic type, infer from type arguments
- var sourceTypes = (source).typeArguments;
- var targetTypes = (target).typeArguments;
- for (var i = 0; i < sourceTypes.length; i++) {
- inferFromTypes(sourceTypes[i], targetTypes[i]);
- }
- }
- else if (target.flags & TypeFlags.Union) {
- var targetTypes = (target).types;
- var typeParameterCount = 0;
- var typeParameter: TypeParameter;
- // First infer to each type in union that isn't a type parameter
- for (var i = 0; i < targetTypes.length; i++) {
- var t = targetTypes[i];
- if (t.flags & TypeFlags.TypeParameter && contains(context.typeParameters, t)) {
- typeParameter = t;
- typeParameterCount++;
- }
- else {
- inferFromTypes(source, t);
- }
- }
- // If union contains a single naked type parameter, make a secondary inference to that type parameter
- if (typeParameterCount === 1) {
- inferiority++;
- inferFromTypes(source, typeParameter);
- inferiority--;
- }
- }
- else if (source.flags & TypeFlags.Union) {
- // Source is a union type, infer from each consituent type
- var sourceTypes = (source).types;
- for (var i = 0; i < sourceTypes.length; i++) {
- inferFromTypes(sourceTypes[i], target);
- }
- }
- else if (source.flags & TypeFlags.ObjectType && (target.flags & (TypeFlags.Reference | TypeFlags.Tuple) ||
- (target.flags & TypeFlags.Anonymous) && target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral))) {
- // If source is an object type, and target is a type reference, a tuple type, the type of a method, or a type literal, infer from members
- if (!isInProcess(source, target) && isWithinDepthLimit(source, sourceStack) && isWithinDepthLimit(target, targetStack)) {
- if (depth === 0) {
- sourceStack = [];
- targetStack = [];
- }
- sourceStack[depth] = source;
- targetStack[depth] = target;
- depth++;
- inferFromProperties(source, target);
- inferFromSignatures(source, target, SignatureKind.Call);
- inferFromSignatures(source, target, SignatureKind.Construct);
- inferFromIndexTypes(source, target, IndexKind.String, IndexKind.String);
- inferFromIndexTypes(source, target, IndexKind.Number, IndexKind.Number);
- inferFromIndexTypes(source, target, IndexKind.String, IndexKind.Number);
- depth--;
- }
- }
- }
-
- function inferFromProperties(source: Type, target: Type) {
- var properties = getPropertiesOfObjectType(target);
- for (var i = 0; i < properties.length; i++) {
- var targetProp = properties[i];
- var sourceProp = getPropertyOfObjectType(source, targetProp.name);
- if (sourceProp) {
- inferFromTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp));
- }
- }
- }
-
- function inferFromSignatures(source: Type, target: Type, kind: SignatureKind) {
- var sourceSignatures = getSignaturesOfType(source, kind);
- var targetSignatures = getSignaturesOfType(target, kind);
- var sourceLen = sourceSignatures.length;
- var targetLen = targetSignatures.length;
- var len = sourceLen < targetLen ? sourceLen : targetLen;
- for (var i = 0; i < len; i++) {
- inferFromSignature(getErasedSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i]));
- }
- }
-
- function inferFromSignature(source: Signature, target: Signature) {
- forEachMatchingParameterType(source, target, inferFromTypes);
- inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target));
- }
-
- function inferFromIndexTypes(source: Type, target: Type, sourceKind: IndexKind, targetKind: IndexKind) {
- var targetIndexType = getIndexTypeOfType(target, targetKind);
- if (targetIndexType) {
- var sourceIndexType = getIndexTypeOfType(source, sourceKind);
- if (sourceIndexType) {
- inferFromTypes(sourceIndexType, targetIndexType);
- }
- }
- }
- }
-
- function getInferenceCandidates(context: InferenceContext, index: number): Type[]{
- var inferences = context.inferences[index];
- return inferences.primary || inferences.secondary || emptyArray;
- }
-
- function getInferredType(context: InferenceContext, index: number): Type {
- var inferredType = context.inferredTypes[index];
- if (!inferredType) {
- var inferences = getInferenceCandidates(context, index);
- if (inferences.length) {
- // Infer widened union or supertype, or the undefined type for no common supertype
- var unionOrSuperType = context.inferUnionTypes ? getUnionType(inferences) : getCommonSupertype(inferences);
- inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : inferenceFailureType;
- }
- else {
- // Infer the empty object type when no inferences were made
- inferredType = emptyObjectType;
- }
- if (inferredType !== inferenceFailureType) {
- var constraint = getConstraintOfTypeParameter(context.typeParameters[index]);
- inferredType = constraint && !isTypeAssignableTo(inferredType, constraint) ? constraint : inferredType;
- }
- context.inferredTypes[index] = inferredType;
- }
- return inferredType;
- }
-
- function getInferredTypes(context: InferenceContext): Type[] {
- for (var i = 0; i < context.inferredTypes.length; i++) {
- getInferredType(context, i);
- }
-
- return context.inferredTypes;
- }
-
- function hasAncestor(node: Node, kind: SyntaxKind): boolean {
- return getAncestor(node, kind) !== undefined;
- }
-
- // EXPRESSION TYPE CHECKING
-
- function getResolvedSymbol(node: Identifier): Symbol {
- var links = getNodeLinks(node);
- if (!links.resolvedSymbol) {
- links.resolvedSymbol = resolveName(node, node.text, SymbolFlags.Value | SymbolFlags.ExportValue, Diagnostics.Cannot_find_name_0, node) || unknownSymbol;
- }
- return links.resolvedSymbol;
- }
-
- function isInTypeQuery(node: Node): boolean {
- // TypeScript 1.0 spec (April 2014): 3.6.3
- // A type query consists of the keyword typeof followed by an expression.
- // The expression is restricted to a single identifier or a sequence of identifiers separated by periods
- while (node) {
- switch (node.kind) {
- case SyntaxKind.TypeQuery:
- return true;
- case SyntaxKind.Identifier:
- case SyntaxKind.QualifiedName:
- node = node.parent;
- continue;
- default:
- return false;
- }
- }
- Debug.fail("should not get here");
- }
-
- // Remove one or more primitive types from a union type
- function subtractPrimitiveTypes(type: Type, subtractMask: TypeFlags): Type {
- if (type.flags & TypeFlags.Union) {
- var types = (type).types;
- if (forEach(types, t => t.flags & subtractMask)) {
- return getUnionType(filter(types, t => !(t.flags & subtractMask)));
- }
- }
- return type;
- }
-
- // Check if a given variable is assigned within a given syntax node
- function isVariableAssignedWithin(symbol: Symbol, node: Node): boolean {
- var links = getNodeLinks(node);
- if (links.assignmentChecks) {
- var cachedResult = links.assignmentChecks[symbol.id];
- if (cachedResult !== undefined) {
- return cachedResult;
- }
- }
- else {
- links.assignmentChecks = {};
- }
- return links.assignmentChecks[symbol.id] = isAssignedIn(node);
-
- function isAssignedInBinaryExpression(node: BinaryExpression) {
- if (node.operator >= SyntaxKind.FirstAssignment && node.operator <= SyntaxKind.LastAssignment) {
- var n = node.left;
- while (n.kind === SyntaxKind.ParenExpression) {
- n = (n).expression;
- }
- if (n.kind === SyntaxKind.Identifier && getResolvedSymbol(n) === symbol) {
- return true;
- }
- }
- return forEachChild(node, isAssignedIn);
- }
-
- function isAssignedInVariableDeclaration(node: VariableDeclaration) {
- if (getSymbolOfNode(node) === symbol && node.initializer) {
- return true;
- }
- return forEachChild(node, isAssignedIn);
- }
-
- function isAssignedIn(node: Node): boolean {
- switch (node.kind) {
- case SyntaxKind.BinaryExpression:
- return isAssignedInBinaryExpression(node);
- case SyntaxKind.VariableDeclaration:
- return isAssignedInVariableDeclaration(node);
- case SyntaxKind.ArrayLiteral:
- case SyntaxKind.ObjectLiteral:
- case SyntaxKind.PropertyAccess:
- case SyntaxKind.IndexedAccess:
- case SyntaxKind.CallExpression:
- case SyntaxKind.NewExpression:
- case SyntaxKind.TypeAssertion:
- case SyntaxKind.ParenExpression:
- case SyntaxKind.PrefixOperator:
- case SyntaxKind.PostfixOperator:
- case SyntaxKind.ConditionalExpression:
- case SyntaxKind.Block:
- case SyntaxKind.VariableStatement:
- case SyntaxKind.ExpressionStatement:
- case SyntaxKind.IfStatement:
- case SyntaxKind.DoStatement:
- case SyntaxKind.WhileStatement:
- case SyntaxKind.ForStatement:
- case SyntaxKind.ForInStatement:
- case SyntaxKind.ReturnStatement:
- case SyntaxKind.WithStatement:
- case SyntaxKind.SwitchStatement:
- case SyntaxKind.CaseClause:
- case SyntaxKind.DefaultClause:
- case SyntaxKind.LabeledStatement:
- case SyntaxKind.ThrowStatement:
- case SyntaxKind.TryStatement:
- case SyntaxKind.TryBlock:
- case SyntaxKind.CatchBlock:
- case SyntaxKind.FinallyBlock:
- return forEachChild(node, isAssignedIn);
- }
- return false;
- }
- }
-
- // Get the narrowed type of a given symbol at a given location
- function getNarrowedTypeOfSymbol(symbol: Symbol, node: Node) {
- var type = getTypeOfSymbol(symbol);
- // Only narrow when symbol is variable of a structured type
- if (node && (symbol.flags & SymbolFlags.Variable && type.flags & TypeFlags.Structured)) {
- while (true) {
- var child = node;
- node = node.parent;
- // Stop at containing function or module block
- if (!node || node.kind === SyntaxKind.FunctionBlock || node.kind === SyntaxKind.ModuleBlock) {
- break;
- }
- var narrowedType = type;
- switch (node.kind) {
- case SyntaxKind.IfStatement:
- // In a branch of an if statement, narrow based on controlling expression
- if (child !== (node).expression) {
- narrowedType = narrowType(type, (node).expression, /*assumeTrue*/ child === (node).thenStatement);
- }
- break;
- case SyntaxKind.ConditionalExpression:
- // In a branch of a conditional expression, narrow based on controlling condition
- if (child !== (node).condition) {
- narrowedType = narrowType(type, (node).condition, /*assumeTrue*/ child === (node).whenTrue);
- }
- break;
- case SyntaxKind.BinaryExpression:
- // In the right operand of an && or ||, narrow based on left operand
- if (child === (node).right) {
- if ((node).operator === SyntaxKind.AmpersandAmpersandToken) {
- narrowedType = narrowType(type, (node).left, /*assumeTrue*/ true);
- }
- else if ((node).operator === SyntaxKind.BarBarToken) {
- narrowedType = narrowType(type, (node).left, /*assumeTrue*/ false);
- }
- }
- break;
- }
- // Only use narrowed type if construct contains no assignments to variable
- if (narrowedType !== type) {
- if (isVariableAssignedWithin(symbol, node)) {
- break;
- }
- type = narrowedType;
- }
- }
- }
- return type;
-
- function narrowTypeByEquality(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
- var left = expr.left;
- var right = expr.right;
- // Check that we have 'typeof ' on the left and string literal on the right
- if (left.kind !== SyntaxKind.PrefixOperator || left.operator !== SyntaxKind.TypeOfKeyword ||
- left.operand.kind !== SyntaxKind.Identifier || right.kind !== SyntaxKind.StringLiteral ||
- getResolvedSymbol(left.operand) !== symbol) {
- return type;
- }
- var t = right.text;
- var checkType: Type = t === "string" ? stringType : t === "number" ? numberType : t === "boolean" ? booleanType : emptyObjectType;
- if (expr.operator === SyntaxKind.ExclamationEqualsEqualsToken) {
- assumeTrue = !assumeTrue;
- }
- if (assumeTrue) {
- // The assumed result is true. If check was for a primitive type, that type is the narrowed type. Otherwise we can
- // remove the primitive types from the narrowed type.
- return checkType === emptyObjectType ? subtractPrimitiveTypes(type, TypeFlags.String | TypeFlags.Number | TypeFlags.Boolean) : checkType;
- }
- else {
- // The assumed result is false. If check was for a primitive type we can remove that type from the narrowed type.
- // Otherwise we don't have enough information to do anything.
- return checkType === emptyObjectType ? type : subtractPrimitiveTypes(type, checkType.flags);
- }
- }
-
- function narrowTypeByAnd(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
- if (assumeTrue) {
- // The assumed result is true, therefore we narrow assuming each operand to be true.
- return narrowType(narrowType(type, expr.left, /*assumeTrue*/ true), expr.right, /*assumeTrue*/ true);
- }
- else {
- // The assumed result is false. This means either the first operand was false, or the first operand was true
- // and the second operand was false. We narrow with those assumptions and union the two resulting types.
- return getUnionType([
- narrowType(type, expr.left, /*assumeTrue*/ false),
- narrowType(narrowType(type, expr.left, /*assumeTrue*/ true), expr.right, /*assumeTrue*/ false)
- ]);
- }
- }
-
- function narrowTypeByOr(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
- if (assumeTrue) {
- // The assumed result is true. This means either the first operand was true, or the first operand was false
- // and the second operand was true. We narrow with those assumptions and union the two resulting types.
- return getUnionType([
- narrowType(type, expr.left, /*assumeTrue*/ true),
- narrowType(narrowType(type, expr.left, /*assumeTrue*/ false), expr.right, /*assumeTrue*/ true)
- ]);
- }
- else {
- // The assumed result is false, therefore we narrow assuming each operand to be false.
- return narrowType(narrowType(type, expr.left, /*assumeTrue*/ false), expr.right, /*assumeTrue*/ false);
- }
- }
-
- function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
- // Check that assumed result is true and we have variable symbol on the left
- if (!assumeTrue || expr.left.kind !== SyntaxKind.Identifier || getResolvedSymbol(expr.left) !== symbol) {
- return type;
- }
- // Check that right operand is a function type with a prototype property
- var rightType = checkExpression(expr.right);
- if (!isTypeSubtypeOf(rightType, globalFunctionType)) {
- return type;
- }
- var prototypeProperty = getPropertyOfType(rightType, "prototype");
- if (!prototypeProperty) {
- return type;
- }
- var prototypeType = getTypeOfSymbol(prototypeProperty);
- // Narrow to type of prototype property if it is a subtype of current type
- return isTypeSubtypeOf(prototypeType, type) ? prototypeType : type;
- }
-
- // Narrow the given type based on the given expression having the assumed boolean value
- function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type {
- switch (expr.kind) {
- case SyntaxKind.ParenExpression:
- return narrowType(type, (expr).expression, assumeTrue);
- case SyntaxKind.BinaryExpression:
- var operator = (expr).operator;
- if (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) {
- return narrowTypeByEquality(type, expr, assumeTrue);
- }
- else if (operator === SyntaxKind.AmpersandAmpersandToken) {
- return narrowTypeByAnd(type, expr, assumeTrue);
- }
- else if (operator === SyntaxKind.BarBarToken) {
- return narrowTypeByOr(type, expr, assumeTrue);
- }
- else if (operator === SyntaxKind.InstanceOfKeyword) {
- return narrowTypeByInstanceof(type, expr, assumeTrue);
- }
- break;
- case SyntaxKind.PrefixOperator:
- if ((expr).operator === SyntaxKind.ExclamationToken) {
- return narrowType(type, (expr).operand, !assumeTrue);
- }
- break;
- }
- return type;
- }
- }
-
- function checkIdentifier(node: Identifier): Type {
- var symbol = getResolvedSymbol(node);
-
- if (symbol.flags & SymbolFlags.Import) {
- // Mark the import as referenced so that we emit it in the final .js file.
- // exception: identifiers that appear in type queries, const enums, modules that contain only const enums
- getSymbolLinks(symbol).referenced = !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveImport(symbol));
- }
-
- checkCollisionWithCapturedSuperVariable(node, node);
- checkCollisionWithCapturedThisVariable(node, node);
- checkCollisionWithIndexVariableInGeneratedCode(node, node);
-
- return getNarrowedTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol), node);
- }
-
- function captureLexicalThis(node: Node, container: Node): void {
- var classNode = container.parent && container.parent.kind === SyntaxKind.ClassDeclaration ? container.parent : undefined;
- getNodeLinks(node).flags |= NodeCheckFlags.LexicalThis;
- if (container.kind === SyntaxKind.Property || container.kind === SyntaxKind.Constructor) {
- getNodeLinks(classNode).flags |= NodeCheckFlags.CaptureThis;
- }
- else {
- getNodeLinks(container).flags |= NodeCheckFlags.CaptureThis;
- }
- }
-
- function checkThisExpression(node: Node): Type {
- // Stop at the first arrow function so that we can
- // tell whether 'this' needs to be captured.
- var container = getThisContainer(node, /* includeArrowFunctions */ true);
- var needToCaptureLexicalThis = false;
-
- // Now skip arrow functions to get the "real" owner of 'this'.
- if (container.kind === SyntaxKind.ArrowFunction) {
- container = getThisContainer(container, /* includeArrowFunctions */ false);
- needToCaptureLexicalThis = true;
- }
-
- switch (container.kind) {
- case SyntaxKind.ModuleDeclaration:
- error(node, Diagnostics.this_cannot_be_referenced_in_a_module_body);
- // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks
- break;
- case SyntaxKind.EnumDeclaration:
- error(node, Diagnostics.this_cannot_be_referenced_in_current_location);
- // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks
- break;
- case SyntaxKind.Constructor:
- if (isInConstructorArgumentInitializer(node, container)) {
- error(node, Diagnostics.this_cannot_be_referenced_in_constructor_arguments);
- // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks
- }
- break;
- case SyntaxKind.Property:
- if (container.flags & NodeFlags.Static) {
- error(node, Diagnostics.this_cannot_be_referenced_in_a_static_property_initializer);
- // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks
- }
- break;
- }
-
- if (needToCaptureLexicalThis) {
- captureLexicalThis(node, container);
- }
-
- var classNode = container.parent && container.parent.kind === SyntaxKind.ClassDeclaration ? container.parent : undefined;
- if (classNode) {
- var symbol = getSymbolOfNode(classNode);
- return container.flags & NodeFlags.Static ? getTypeOfSymbol(symbol) : getDeclaredTypeOfSymbol(symbol);
- }
- return anyType;
- }
-
- function getSuperContainer(node: Node): Node {
- while (true) {
- node = node.parent;
- if (!node) return node;
- switch (node.kind) {
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.ArrowFunction:
- case SyntaxKind.Property:
- case SyntaxKind.Method:
- case SyntaxKind.Constructor:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- return node;
- }
- }
- }
-
- function isInConstructorArgumentInitializer(node: Node, constructorDecl: Node): boolean {
- for (var n = node; n && n !== constructorDecl; n = n.parent) {
- if (n.kind === SyntaxKind.Parameter) {
- return true;
- }
- }
- return false;
- }
-
- function checkSuperExpression(node: Node): Type {
- var isCallExpression = node.parent.kind === SyntaxKind.CallExpression && (node.parent).func === node;
- var enclosingClass = getAncestor(node, SyntaxKind.ClassDeclaration);
- var baseClass: Type;
- if (enclosingClass && enclosingClass.baseType) {
- var classType = getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClass));
- baseClass = classType.baseTypes.length && classType.baseTypes[0];
- }
-
- if (!baseClass) {
- error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class);
- return unknownType;
- }
-
- var container = getSuperContainer(node);
-
- if (container) {
- var canUseSuperExpression = false;
- if (isCallExpression) {
- // TS 1.0 SPEC (April 2014): 4.8.1
- // Super calls are only permitted in constructors of derived classes
- canUseSuperExpression = container.kind === SyntaxKind.Constructor;
- }
- else {
- // TS 1.0 SPEC (April 2014)
- // 'super' property access is allowed
- // - In a constructor, instance member function, instance member accessor, or instance member variable initializer where this references a derived class instance
- // - In a static member function or static member accessor
-
- // super property access might appear in arrow functions with arbitrary deep nesting
- var needToCaptureLexicalThis = false;
- while (container && container.kind === SyntaxKind.ArrowFunction) {
- container = getSuperContainer(container);
- needToCaptureLexicalThis = true;
- }
-
- // topmost container must be something that is directly nested in the class declaration
- if (container && container.parent && container.parent.kind === SyntaxKind.ClassDeclaration) {
- if (container.flags & NodeFlags.Static) {
- canUseSuperExpression =
- container.kind === SyntaxKind.Method ||
- container.kind === SyntaxKind.GetAccessor ||
- container.kind === SyntaxKind.SetAccessor;
- }
- else {
- canUseSuperExpression =
- container.kind === SyntaxKind.Method ||
- container.kind === SyntaxKind.GetAccessor ||
- container.kind === SyntaxKind.SetAccessor ||
- container.kind === SyntaxKind.Property ||
- container.kind === SyntaxKind.Constructor;
- }
- }
- }
-
- if (canUseSuperExpression) {
- var returnType: Type;
-
- if ((container.flags & NodeFlags.Static) || isCallExpression) {
- getNodeLinks(node).flags |= NodeCheckFlags.SuperStatic;
- returnType = getTypeOfSymbol(baseClass.symbol);
- }
- else {
- getNodeLinks(node).flags |= NodeCheckFlags.SuperInstance;
- returnType = baseClass;
- }
-
- if (container.kind === SyntaxKind.Constructor && isInConstructorArgumentInitializer(node, container)) {
- // issue custom error message for super property access in constructor arguments (to be aligned with old compiler)
- error(node, Diagnostics.super_cannot_be_referenced_in_constructor_arguments);
- returnType = unknownType;
- }
-
- if (!isCallExpression && needToCaptureLexicalThis) {
- // call expressions are allowed only in constructors so they should always capture correct 'this'
- // super property access expressions can also appear in arrow functions -
- // in this case they should also use correct lexical this
- captureLexicalThis(node.parent, container);
- }
-
- return returnType;
- }
- }
-
- if (isCallExpression) {
- error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors);
- }
- else {
- error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class);
- }
-
- return unknownType;
- }
-
- // Return contextual type of parameter or undefined if no contextual type is available
- function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type {
- var func = parameter.parent;
- if (func.kind === SyntaxKind.FunctionExpression || func.kind === SyntaxKind.ArrowFunction) {
- if (isContextSensitiveExpression(func)) {
- var contextualSignature = getContextualSignature(func);
- if (contextualSignature) {
-
- var funcHasRestParameters = hasRestParameters(func);
- var len = func.parameters.length - (funcHasRestParameters ? 1 : 0);
- var indexOfParameter = indexOf(func.parameters, parameter);
- if (indexOfParameter < len) {
- return getTypeAtPosition(contextualSignature, indexOfParameter);
- }
-
- // If last parameter is contextually rest parameter get its type
- if (indexOfParameter === (func.parameters.length - 1) &&
- funcHasRestParameters && contextualSignature.hasRestParameter && func.parameters.length >= contextualSignature.parameters.length) {
- return getTypeOfSymbol(contextualSignature.parameters[contextualSignature.parameters.length - 1]);
- }
- }
- }
- }
- return undefined;
- }
-
- // In a variable, parameter or property declaration with a type annotation, the contextual type of an initializer
- // expression is the type of the variable, parameter or property. In a parameter declaration of a contextually
- // typed function expression, the contextual type of an initializer expression is the contextual type of the
- // parameter.
- function getContextualTypeForInitializerExpression(node: Expression): Type {
- var declaration = node.parent;
- if (node === declaration.initializer) {
- if (declaration.type) {
- return getTypeFromTypeNode(declaration.type);
- }
- if (declaration.kind === SyntaxKind.Parameter) {
- return getContextuallyTypedParameterType(declaration);
- }
- }
- return undefined;
- }
-
- function getContextualTypeForReturnExpression(node: Expression): Type {
- var func = getContainingFunction(node);
- if (func) {
- // If the containing function has a return type annotation, is a constructor, or is a get accessor whose
- // corresponding set accessor has a type annotation, return statements in the function are contextually typed
- if (func.type || func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(func.symbol, SyntaxKind.SetAccessor))) {
- return getReturnTypeOfSignature(getSignatureFromDeclaration(func));
- }
- // Otherwise, if the containing function is contextually typed by a function type with exactly one call signature
- // and that call signature is non-generic, return statements are contextually typed by the return type of the signature
- var signature = getContextualSignature(func);
- if (signature) {
- return getReturnTypeOfSignature(signature);
- }
- }
- return undefined;
- }
-
- // In a typed function call, an argument expression is contextually typed by the type of the corresponding parameter.
- function getContextualTypeForArgument(node: Expression): Type {
- var callExpression = node.parent;
- var argIndex = indexOf(callExpression.arguments, node);
- if (argIndex >= 0) {
- var signature = getResolvedSignature(callExpression);
- return getTypeAtPosition(signature, argIndex);
- }
- return undefined;
- }
-
- function getContextualTypeForBinaryOperand(node: Expression): Type {
- var binaryExpression = node.parent;
- var operator = binaryExpression.operator;
- if (operator >= SyntaxKind.FirstAssignment && operator <= SyntaxKind.LastAssignment) {
- // In an assignment expression, the right operand is contextually typed by the type of the left operand.
- if (node === binaryExpression.right) {
- return checkExpression(binaryExpression.left);
- }
- }
- else if (operator === SyntaxKind.BarBarToken) {
- // When an || expression has a contextual type, the operands are contextually typed by that type. When an ||
- // expression has no contextual type, the right operand is contextually typed by the type of the left operand.
- var type = getContextualType(binaryExpression);
- if (!type && node === binaryExpression.right) {
- type = checkExpression(binaryExpression.left);
- }
- return type;
- }
- return undefined;
- }
-
- // Apply a mapping function to a contextual type and return the resulting type. If the contextual type
- // is a union type, the mapping function is applied to each constituent type and a union of the resulting
- // types is returned.
- function applyToContextualType(type: Type, mapper: (t: Type) => Type): Type {
- if (!(type.flags & TypeFlags.Union)) {
- return mapper(type);
- }
- var types = (type).types;
- var mappedType: Type;
- var mappedTypes: Type[];
- for (var i = 0; i < types.length; i++) {
- var t = mapper(types[i]);
- if (t) {
- if (!mappedType) {
- mappedType = t;
- }
- else if (!mappedTypes) {
- mappedTypes = [mappedType, t];
- }
- else {
- mappedTypes.push(t);
- }
- }
- }
- return mappedTypes ? getUnionType(mappedTypes) : mappedType;
- }
-
- function getTypeOfPropertyOfContextualType(type: Type, name: string) {
- return applyToContextualType(type, t => {
- var prop = getPropertyOfObjectType(t, name);
- return prop ? getTypeOfSymbol(prop) : undefined;
- });
- }
-
- function getIndexTypeOfContextualType(type: Type, kind: IndexKind) {
- return applyToContextualType(type, t => getIndexTypeOfObjectOrUnionType(t, kind));
- }
-
- // Return true if the given contextual type is a tuple-like type
- function contextualTypeIsTupleType(type: Type): boolean {
- return !!(type.flags & TypeFlags.Union ? forEach((type).types, t => getPropertyOfObjectType(t, "0")) : getPropertyOfObjectType(type, "0"));
- }
-
- // Return true if the given contextual type provides an index signature of the given kind
- function contextualTypeHasIndexSignature(type: Type, kind: IndexKind): boolean {
- return !!(type.flags & TypeFlags.Union ? forEach((type).types, t => getIndexTypeOfObjectOrUnionType(t, kind)) : getIndexTypeOfObjectOrUnionType(type, kind));
- }
-
- // In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of
- // the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one
- // exists. Otherwise, it is the type of the string index signature in T, if one exists.
- function getContextualTypeForPropertyExpression(node: Expression): Type {
- var declaration = node.parent;
- var objectLiteral = declaration.parent;
- var type = getContextualType(objectLiteral);
- // TODO(jfreeman): Handle this case for computed names and symbols
- var name = (declaration.name).text;
- if (type && name) {
- return getTypeOfPropertyOfContextualType(type, name) ||
- isNumericName(name) && getIndexTypeOfContextualType(type, IndexKind.Number) ||
- getIndexTypeOfContextualType(type, IndexKind.String);
- }
- return undefined;
- }
-
- // In an array literal contextually typed by a type T, the contextual type of an element expression at index N is
- // the type of the property with the numeric name N in T, if one exists. Otherwise, it is the type of the numeric
- // index signature in T, if one exists.
- function getContextualTypeForElementExpression(node: Expression): Type {
- var arrayLiteral = node.parent;
- var type = getContextualType(arrayLiteral);
- if (type) {
- var index = indexOf(arrayLiteral.elements, node);
- return getTypeOfPropertyOfContextualType(type, "" + index) || getIndexTypeOfContextualType(type, IndexKind.Number);
- }
- return undefined;
- }
-
- // In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type.
- function getContextualTypeForConditionalOperand(node: Expression): Type {
- var conditional = node.parent;
- return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
- }
-
- // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
- // be "pushed" onto a node using the contextualType property.
- function getContextualType(node: Expression): Type {
- if (isInsideWithStatementBody(node)) {
- // We cannot answer semantic questions within a with block, do not proceed any further
- return undefined;
- }
- if (node.contextualType) {
- return node.contextualType;
- }
- var parent = node.parent;
- switch (parent.kind) {
- case SyntaxKind.VariableDeclaration:
- case SyntaxKind.Parameter:
- case SyntaxKind.Property:
- return getContextualTypeForInitializerExpression(node);
- case SyntaxKind.ArrowFunction:
- case SyntaxKind.ReturnStatement:
- return getContextualTypeForReturnExpression(node);
- case SyntaxKind.CallExpression:
- case SyntaxKind.NewExpression:
- return getContextualTypeForArgument(node);
- case SyntaxKind.TypeAssertion:
- return getTypeFromTypeNode((parent).type);
- case SyntaxKind.BinaryExpression:
- return getContextualTypeForBinaryOperand(node);
- case SyntaxKind.PropertyAssignment:
- return getContextualTypeForPropertyExpression(node);
- case SyntaxKind.ArrayLiteral:
- return getContextualTypeForElementExpression(node);
- case SyntaxKind.ConditionalExpression:
- return getContextualTypeForConditionalOperand(node);
- }
- return undefined;
- }
-
- // If the given type is an object or union type, if that type has a single signature, and if
- // that signature is non-generic, return the signature. Otherwise return undefined.
- function getNonGenericSignature(type: Type): Signature {
- var signatures = getSignaturesOfObjectOrUnionType(type, SignatureKind.Call);
- if (signatures.length === 1) {
- var signature = signatures[0];
- if (!signature.typeParameters) {
- return signature;
- }
- }
- }
-
- // Return the contextual signature for a given expression node. A contextual type provides a
- // contextual signature if it has a single call signature and if that call signature is non-generic.
- // If the contextual type is a union type, get the signature from each type possible and if they are
- // all identical ignoring their return type, the result is same signature but with return type as
- // union type of return types from these signatures
- function getContextualSignature(node: Expression): Signature {
- var type = getContextualType(node);
- if (!type) {
- return undefined;
- }
- if (!(type.flags & TypeFlags.Union)) {
- return getNonGenericSignature(type);
- }
- var signatureList: Signature[];
- var types = (type).types;
- for (var i = 0; i < types.length; i++) {
- // The signature set of all constituent type with call signatures should match
- // So number of signatures allowed is either 0 or 1
- if (signatureList &&
- getSignaturesOfObjectOrUnionType(types[i], SignatureKind.Call).length > 1) {
- return undefined;
- }
-
- var signature = getNonGenericSignature(types[i]);
- if (signature) {
- if (!signatureList) {
- // This signature will contribute to contextual union signature
- signatureList = [signature];
- }
- else if (!compareSignatures(signatureList[0], signature, /*compareReturnTypes*/ false, compareTypes)) {
- // Signatures arent identical, do not use
- return undefined;
- }
- else {
- // Use this signature for contextual union signature
- signatureList.push(signature);
- }
- }
- }
-
- // Result is union of signatures collected (return type is union of return types of this signature set)
- var result: Signature;
- if (signatureList) {
- result = cloneSignature(signatureList[0]);
- // Clear resolved return type we possibly got from cloneSignature
- result.resolvedReturnType = undefined;
- result.unionSignatures = signatureList;
- }
- return result;
- }
-
- // Presence of a contextual type mapper indicates inferential typing, except the identityMapper object is
- // used as a special marker for other purposes.
- function isInferentialContext(mapper: TypeMapper) {
- return mapper && mapper !== identityMapper;
- }
-
- function checkArrayLiteral(node: ArrayLiteral, contextualMapper?: TypeMapper): Type {
- var elements = node.elements;
- if (!elements.length) {
- return createArrayType(undefinedType);
- }
- var elementTypes = map(elements, e => checkExpression(e, contextualMapper));
- var contextualType = getContextualType(node);
- if (contextualType && contextualTypeIsTupleType(contextualType)) {
- return createTupleType(elementTypes);
- }
- return createArrayType(getUnionType(elementTypes));
- }
-
- function isNumericName(name: string) {
- // The intent of numeric names is that
- // - they are names with text in a numeric form, and that
- // - setting properties/indexing with them is always equivalent to doing so with the numeric literal 'numLit',
- // acquired by applying the abstract 'ToNumber' operation on the name's text.
- //
- // The subtlety is in the latter portion, as we cannot reliably say that anything that looks like a numeric literal is a numeric name.
- // In fact, it is the case that the text of the name must be equal to 'ToString(numLit)' for this to hold.
- //
- // Consider the property name '"0xF00D"'. When one indexes with '0xF00D', they are actually indexing with the value of 'ToString(0xF00D)'
- // according to the ECMAScript specification, so it is actually as if the user indexed with the string '"61453"'.
- // Thus, the text of all numeric literals equivalent to '61543' such as '0xF00D', '0xf00D', '0170015', etc. are not valid numeric names
- // because their 'ToString' representation is not equal to their original text.
- // This is motivated by ECMA-262 sections 9.3.1, 9.8.1, 11.1.5, and 11.2.1.
- //
- // Here, we test whether 'ToString(ToNumber(name))' is exactly equal to 'name'.
- // The '+' prefix operator is equivalent here to applying the abstract ToNumber operation.
- // Applying the 'toString()' method on a number gives us the abstract ToString operation on a number.
- //
- // Note that this accepts the values 'Infinity', '-Infinity', and 'NaN', and that this is intentional.
- // This is desired behavior, because when indexing with them as numeric entities, you are indexing
- // with the strings '"Infinity"', '"-Infinity"', and '"NaN"' respectively.
- return (+name).toString() === name;
- }
-
- function checkObjectLiteral(node: ObjectLiteral, contextualMapper?: TypeMapper): Type {
- var members = node.symbol.members;
- var properties: SymbolTable = {};
- var contextualType = getContextualType(node);
- for (var id in members) {
- if (hasProperty(members, id)) {
- var member = members[id];
- if (member.flags & SymbolFlags.Property) {
- var type = checkExpression((member.declarations[0]).initializer, contextualMapper);
- var prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name);
- prop.declarations = member.declarations;
- prop.parent = member.parent;
- if (member.valueDeclaration) prop.valueDeclaration = member.valueDeclaration;
- prop.type = type;
- prop.target = member;
- member = prop;
- }
- else {
- // TypeScript 1.0 spec (April 2014)
- // A get accessor declaration is processed in the same manner as
- // an ordinary function declaration(section 6.1) with no parameters.
- // A set accessor declaration is processed in the same manner
- // as an ordinary function declaration with a single parameter and a Void return type.
- var getAccessor = getDeclarationOfKind(member, SyntaxKind.GetAccessor);
- if (getAccessor) {
- checkAccessorDeclaration(getAccessor);
- }
-
- var setAccessor = getDeclarationOfKind(member, SyntaxKind.SetAccessor);
- if (setAccessor) {
- checkAccessorDeclaration(setAccessor);
- }
- }
- properties[member.name] = member;
- }
- }
- var stringIndexType = getIndexType(IndexKind.String);
- var numberIndexType = getIndexType(IndexKind.Number);
- return createAnonymousType(node.symbol, properties, emptyArray, emptyArray, stringIndexType, numberIndexType);
-
- function getIndexType(kind: IndexKind) {
- if (contextualType && contextualTypeHasIndexSignature(contextualType, kind)) {
- var propTypes: Type[] = [];
- for (var id in properties) {
- if (hasProperty(properties, id)) {
- if (kind === IndexKind.String || isNumericName(id)) {
- var type = getTypeOfSymbol(properties[id]);
- if (!contains(propTypes, type)) {
- propTypes.push(type);
- }
- }
- }
- }
- return propTypes.length ? getUnionType(propTypes) : undefinedType;
- }
- return undefined;
- }
- }
-
- // If a symbol is a synthesized symbol with no value declaration, we assume it is a property. Example of this are the synthesized
- // '.prototype' property as well as synthesized tuple index properties.
- function getDeclarationKindFromSymbol(s: Symbol) {
- return s.valueDeclaration ? s.valueDeclaration.kind : SyntaxKind.Property;
- }
-
- function getDeclarationFlagsFromSymbol(s: Symbol) {
- return s.valueDeclaration ? s.valueDeclaration.flags : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0;
- }
-
- function checkClassPropertyAccess(node: PropertyAccess, type: Type, prop: Symbol) {
- var flags = getDeclarationFlagsFromSymbol(prop);
- // Public properties are always accessible
- if (!(flags & (NodeFlags.Private | NodeFlags.Protected))) {
- return;
- }
- // Property is known to be private or protected at this point
- // Get the declaring and enclosing class instance types
- var enclosingClassDeclaration = getAncestor(node, SyntaxKind.ClassDeclaration);
- var enclosingClass = enclosingClassDeclaration ? getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClassDeclaration)) : undefined;
- var declaringClass = getDeclaredTypeOfSymbol(prop.parent);
- // Private property is accessible if declaring and enclosing class are the same
- if (flags & NodeFlags.Private) {
- if (declaringClass !== enclosingClass) {
- error(node, Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, symbolToString(prop), typeToString(declaringClass));
- }
- return;
- }
- // Property is known to be protected at this point
- // All protected properties of a supertype are accessible in a super access
- if (node.left.kind === SyntaxKind.SuperKeyword) {
- return;
- }
- // A protected property is accessible in the declaring class and classes derived from it
- if (!enclosingClass || !hasBaseType(enclosingClass, declaringClass)) {
- error(node, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(declaringClass));
- return;
- }
- // No further restrictions for static properties
- if (flags & NodeFlags.Static) {
- return;
- }
- // An instance property must be accessed through an instance of the enclosing class
- if (!(getTargetType(type).flags & (TypeFlags.Class | TypeFlags.Interface) && hasBaseType(type, enclosingClass))) {
- error(node, Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1, symbolToString(prop), typeToString(enclosingClass));
- }
- }
-
- function checkPropertyAccess(node: PropertyAccess) {
- var type = checkExpression(node.left);
- if (type === unknownType) return type;
- if (type !== anyType) {
- var apparentType = getApparentType(getWidenedType(type));
- if (apparentType === unknownType) {
- // handle cases when type is Type parameter with invalid constraint
- return unknownType;
- }
- var prop = getPropertyOfType(apparentType, node.right.text);
- if (!prop) {
- if (node.right.text) {
- error(node.right, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(node.right), typeToString(type));
- }
- return unknownType;
- }
- getNodeLinks(node).resolvedSymbol = prop;
- if (prop.parent && prop.parent.flags & SymbolFlags.Class) {
- // TS 1.0 spec (April 2014): 4.8.2
- // - In a constructor, instance member function, instance member accessor, or
- // instance member variable initializer where this references a derived class instance,
- // a super property access is permitted and must specify a public instance member function of the base class.
- // - In a static member function or static member accessor
- // where this references the constructor function object of a derived class,
- // a super property access is permitted and must specify a public static member function of the base class.
- if (node.left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.Method) {
- error(node.right, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword);
- }
- else {
- checkClassPropertyAccess(node, type, prop);
- }
- }
- return getTypeOfSymbol(prop);
- }
- return anyType;
- }
-
- function isValidPropertyAccess(node: PropertyAccess, propertyName: string): boolean {
- var type = checkExpression(node.left);
- if (type !== unknownType && type !== anyType) {
- var prop = getPropertyOfType(getWidenedType(type), propertyName);
- if (prop && prop.parent && prop.parent.flags & SymbolFlags.Class) {
- if (node.left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.Method) {
- return false;
- }
- else {
- var diagnosticsCount = diagnostics.length;
- checkClassPropertyAccess(node, type, prop);
- return diagnostics.length === diagnosticsCount
- }
- }
- }
- return true;
- }
-
- function checkIndexedAccess(node: IndexedAccess): Type {
- // Obtain base constraint such that we can bail out if the constraint is an unknown type
- var objectType = getApparentType(checkExpression(node.object));
- var indexType = checkExpression(node.index);
-
- if (objectType === unknownType) return unknownType;
-
- if (isConstEnumObjectType(objectType) && node.index.kind !== SyntaxKind.StringLiteral) {
- error(node.index, Diagnostics.Index_expression_arguments_in_const_enums_must_be_of_type_string);
- }
-
- // TypeScript 1.0 spec (April 2014): 4.10 Property Access
- // - If IndexExpr is a string literal or a numeric literal and ObjExpr's apparent type has a property with the name
- // given by that literal(converted to its string representation in the case of a numeric literal), the property access is of the type of that property.
- // - Otherwise, if ObjExpr's apparent type has a numeric index signature and IndexExpr is of type Any, the Number primitive type, or an enum type,
- // the property access is of the type of that index signature.
- // - Otherwise, if ObjExpr's apparent type has a string index signature and IndexExpr is of type Any, the String or Number primitive type, or an enum type,
- // the property access is of the type of that index signature.
- // - Otherwise, if IndexExpr is of type Any, the String or Number primitive type, or an enum type, the property access is of type Any.
-
- // See if we can index as a property.
- if (node.index.kind === SyntaxKind.StringLiteral || node.index.kind === SyntaxKind.NumericLiteral) {
- var name = (node.index).text;
- var prop = getPropertyOfType(objectType, name);
- if (prop) {
- getNodeLinks(node).resolvedSymbol = prop;
- return getTypeOfSymbol(prop);
- }
- }
-
- // Check for compatible indexer types.
- if (indexType.flags & (TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike)) {
-
- // Try to use a number indexer.
- if (indexType.flags & (TypeFlags.Any | TypeFlags.NumberLike)) {
- var numberIndexType = getIndexTypeOfType(objectType, IndexKind.Number);
- if (numberIndexType) {
- return numberIndexType;
- }
- }
-
- // Try to use string indexing.
- var stringIndexType = getIndexTypeOfType(objectType, IndexKind.String);
- if (stringIndexType) {
- return stringIndexType;
- }
-
- // Fall back to any.
- if (compilerOptions.noImplicitAny && objectType !== anyType) {
- error(node, Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type);
- }
-
- return anyType;
- }
-
- // REVIEW: Users should know the type that was actually used.
- error(node, Diagnostics.An_index_expression_argument_must_be_of_type_string_number_or_any);
-
- return unknownType;
- }
-
- function resolveUntypedCall(node: CallLikeExpression): Signature {
- if (node.kind === SyntaxKind.TaggedTemplateExpression) {
- checkExpression((node).template);
- }
- else {
- forEach((node).arguments, argument => {
- checkExpression(argument);
- });
- }
- return anySignature;
- }
-
- function resolveErrorCall(node: CallLikeExpression): Signature {
- resolveUntypedCall(node);
- return unknownSignature;
- }
-
- function hasCorrectArity(node: CallLikeExpression, args: Expression[], signature: Signature) {
- var adjustedArgCount: number;
- var typeArguments: NodeArray;
- var callIsIncomplete: boolean;
-
- if (node.kind === SyntaxKind.TaggedTemplateExpression) {
- var tagExpression = node;
-
- // Even if the call is incomplete, we'll have a missing expression as our last argument,
- // so we can say the count is just the arg list length
- adjustedArgCount = args.length;
- typeArguments = undefined;
-
- if (tagExpression.template.kind === SyntaxKind.TemplateExpression) {
- // If a tagged template expression lacks a tail literal, the call is incomplete.
- // Specifically, a template only can end in a TemplateTail or a Missing literal.
- var templateExpression =