From 4cdc97094f972e3868493eaed0b72ec5e9348508 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 3 Apr 2015 16:17:05 -0700 Subject: [PATCH 01/11] Produce a map of named declarations instead of a flat list. Produce a map of named declarations instead of a flat list. --- src/services/navigateTo.ts | 69 ++++++--------- src/services/services.ts | 84 ++++++++++++++----- .../baselines/reference/APISample_compile.js | 1 - .../reference/APISample_compile.types | 4 - tests/baselines/reference/APISample_linter.js | 1 - .../reference/APISample_linter.types | 4 - .../reference/APISample_linter.types.pull | 4 - .../reference/APISample_transform.js | 1 - .../reference/APISample_transform.types | 4 - .../baselines/reference/APISample_watcher.js | 1 - .../reference/APISample_watcher.types | 4 - .../fourslash/navigationItemsOverloads2.ts | 2 +- .../navigationItemsOverloadsBroken1.ts | 10 +-- 13 files changed, 97 insertions(+), 92 deletions(-) diff --git a/src/services/navigateTo.ts b/src/services/navigateTo.ts index 54f87d8e50b..cc81031fc04 100644 --- a/src/services/navigateTo.ts +++ b/src/services/navigateTo.ts @@ -9,11 +9,10 @@ module ts.NavigateTo { forEach(program.getSourceFiles(), sourceFile => { cancellationToken.throwIfCancellationRequested(); - let declarations = sourceFile.getNamedDeclarations(); - for (let declaration of declarations) { - var name = getDeclarationName(declaration); - if (name !== undefined) { - + let nameToDeclarations = sourceFile.getNamedDeclarations(); + for (let name in nameToDeclarations) { + let declarations = getProperty(nameToDeclarations, name); + if (declarations) { // First do a quick check to see if the name of the declaration matches the // last portion of the (possibly) dotted name they're searching for. let matches = patternMatcher.getMatchesForLastSegmentOfPattern(name); @@ -22,24 +21,26 @@ module ts.NavigateTo { continue; } - // It was a match! If the pattern has dots in it, then also see if the - // declaration container matches as well. - if (patternMatcher.patternContainsDots) { - let containers = getContainers(declaration); - if (!containers) { - return undefined; + for (let declaration of declarations) { + // It was a match! If the pattern has dots in it, then also see if the + // declaration container matches as well. + if (patternMatcher.patternContainsDots) { + let containers = getContainers(declaration); + if (!containers) { + return undefined; + } + + matches = patternMatcher.getMatches(containers, name); + + if (!matches) { + continue; + } } - matches = patternMatcher.getMatches(containers, name); - - if (!matches) { - continue; - } + let fileName = sourceFile.fileName; + let matchKind = bestMatchKind(matches); + rawItems.push({ name, fileName, matchKind, isCaseSensitive: allMatchesAreCaseSensitive(matches), declaration }); } - - let fileName = sourceFile.fileName; - let matchKind = bestMatchKind(matches); - rawItems.push({ name, fileName, matchKind, isCaseSensitive: allMatchesAreCaseSensitive(matches), declaration }); } } }); @@ -66,30 +67,14 @@ module ts.NavigateTo { return true; } - function getDeclarationName(declaration: Declaration): string { - let result = getTextOfIdentifierOrLiteral(declaration.name); - if (result !== undefined) { - return result; - } - - if (declaration.name.kind === SyntaxKind.ComputedPropertyName) { - let expr = (declaration.name).expression; - if (expr.kind === SyntaxKind.PropertyAccessExpression) { - return (expr).name.text; - } - - return getTextOfIdentifierOrLiteral(expr); - } - - return undefined; - } - function getTextOfIdentifierOrLiteral(node: Node) { - if (node.kind === SyntaxKind.Identifier || - node.kind === SyntaxKind.StringLiteral || - node.kind === SyntaxKind.NumericLiteral) { + if (node) { + if (node.kind === SyntaxKind.Identifier || + node.kind === SyntaxKind.StringLiteral || + node.kind === SyntaxKind.NumericLiteral) { - return (node).text; + return (node).text; + } } return undefined; diff --git a/src/services/services.ts b/src/services/services.ts index 12ea84eafc1..67d799f62f0 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -63,7 +63,8 @@ module ts { /* @internal */ scriptSnapshot: IScriptSnapshot; /* @internal */ nameTable: Map; - getNamedDeclarations(): Declaration[]; + /* @internal */ getNamedDeclarations(): Map; + getLineAndCharacterOfPosition(pos: number): LineAndCharacter; getLineStarts(): number[]; getPositionOfLineAndCharacter(line: number, character: number): number; @@ -749,7 +750,7 @@ module ts { public identifiers: Map; public nameTable: Map; - private namedDeclarations: Declaration[]; + private namedDeclarations: Map; public update(newText: string, textChangeRange: TextChangeRange): SourceFile { return updateSourceFile(this, newText, textChangeRange); @@ -767,7 +768,7 @@ module ts { return ts.getPositionOfLineAndCharacter(this, line, character); } - public getNamedDeclarations() { + public getNamedDeclarations(): Map { if (!this.namedDeclarations) { this.namedDeclarations = this.computeNamedDeclarations(); } @@ -775,12 +776,57 @@ module ts { return this.namedDeclarations; } - private computeNamedDeclarations() { - let namedDeclarations: Declaration[] = []; + private computeNamedDeclarations(): Map { + let result: Map = {}; forEachChild(this, visit); - return namedDeclarations; + return result; + + function addDeclaration(declaration: Declaration) { + let name = getDeclarationName(declaration); + if (name) { + let declarations = getDeclarations(name); + declarations.push(declaration); + } + } + + function getDeclarations(name: string) { + return getProperty(result, name) || (result[name] = []); + } + + function getDeclarationName(declaration: Declaration) { + if (declaration.name) { + let result = getTextOfIdentifierOrLiteral(declaration.name); + if (result !== undefined) { + return result; + } + + if (declaration.name.kind === SyntaxKind.ComputedPropertyName) { + let expr = (declaration.name).expression; + if (expr.kind === SyntaxKind.PropertyAccessExpression) { + return (expr).name.text; + } + + return getTextOfIdentifierOrLiteral(expr); + } + } + + return undefined; + } + + function getTextOfIdentifierOrLiteral(node: Node) { + if (node) { + if (node.kind === SyntaxKind.Identifier || + node.kind === SyntaxKind.StringLiteral || + node.kind === SyntaxKind.NumericLiteral) { + + return (node).text; + } + } + + return undefined; + } function visit(node: Node): void { switch (node.kind) { @@ -788,22 +834,22 @@ module ts { case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: let functionDeclaration = node; + let declarationName = getDeclarationName(functionDeclaration); - if (functionDeclaration.name && functionDeclaration.name.getFullWidth() > 0) { - let lastDeclaration = namedDeclarations.length > 0 ? - namedDeclarations[namedDeclarations.length - 1] : - undefined; + if (declarationName) { + let declarations = getDeclarations(declarationName); + let lastDeclaration = lastOrUndefined(declarations); // Check whether this declaration belongs to an "overload group". - if (lastDeclaration && functionDeclaration.symbol === lastDeclaration.symbol) { + if (lastDeclaration && functionDeclaration.parent === lastDeclaration.parent && functionDeclaration.symbol === lastDeclaration.symbol) { // Overwrite the last declaration if it was an overload // and this one is an implementation. if (functionDeclaration.body && !(lastDeclaration).body) { - namedDeclarations[namedDeclarations.length - 1] = functionDeclaration; + declarations[declarations.length - 1] = functionDeclaration; } } else { - namedDeclarations.push(functionDeclaration); + declarations.push(functionDeclaration); } forEachChild(node, visit); @@ -824,10 +870,8 @@ module ts { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.TypeLiteral: - if ((node).name) { - namedDeclarations.push(node); - } - // fall through + addDeclaration(node); + // fall through case SyntaxKind.Constructor: case SyntaxKind.VariableStatement: case SyntaxKind.VariableDeclarationList: @@ -858,7 +902,7 @@ module ts { case SyntaxKind.EnumMember: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - namedDeclarations.push(node); + addDeclaration(node); break; case SyntaxKind.ExportDeclaration: @@ -875,7 +919,7 @@ module ts { // Handle default import case e.g.: // import d from "mod"; if (importClause.name) { - namedDeclarations.push(importClause); + addDeclaration(importClause); } // Handle named bindings in imports e.g.: @@ -883,7 +927,7 @@ module ts { // import {a, b as B} from "mod"; if (importClause.namedBindings) { if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { - namedDeclarations.push(importClause.namedBindings); + addDeclaration(importClause.namedBindings); } else { forEach((importClause.namedBindings).elements, visit); diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index 6c28c96a6d8..b604b5f950b 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -1562,7 +1562,6 @@ declare module "typescript" { getDocumentationComment(): SymbolDisplayPart[]; } interface SourceFile { - getNamedDeclarations(): Declaration[]; getLineAndCharacterOfPosition(pos: number): LineAndCharacter; getLineStarts(): number[]; getPositionOfLineAndCharacter(line: number, character: number): number; diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index 635aff75628..3b66a5bfe29 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -5018,10 +5018,6 @@ declare module "typescript" { interface SourceFile { >SourceFile : SourceFile - getNamedDeclarations(): Declaration[]; ->getNamedDeclarations : () => Declaration[] ->Declaration : Declaration - getLineAndCharacterOfPosition(pos: number): LineAndCharacter; >getLineAndCharacterOfPosition : (pos: number) => LineAndCharacter >pos : number diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index f59fa91da14..5c2627041f0 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -1593,7 +1593,6 @@ declare module "typescript" { getDocumentationComment(): SymbolDisplayPart[]; } interface SourceFile { - getNamedDeclarations(): Declaration[]; getLineAndCharacterOfPosition(pos: number): LineAndCharacter; getLineStarts(): number[]; getPositionOfLineAndCharacter(line: number, character: number): number; diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 12f4ac12fdc..048eb9b5604 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -5164,10 +5164,6 @@ declare module "typescript" { interface SourceFile { >SourceFile : SourceFile - getNamedDeclarations(): Declaration[]; ->getNamedDeclarations : () => Declaration[] ->Declaration : Declaration - getLineAndCharacterOfPosition(pos: number): LineAndCharacter; >getLineAndCharacterOfPosition : (pos: number) => LineAndCharacter >pos : number diff --git a/tests/baselines/reference/APISample_linter.types.pull b/tests/baselines/reference/APISample_linter.types.pull index 0a2a7ea948a..e262cf3954b 100644 --- a/tests/baselines/reference/APISample_linter.types.pull +++ b/tests/baselines/reference/APISample_linter.types.pull @@ -5164,10 +5164,6 @@ declare module "typescript" { interface SourceFile { >SourceFile : SourceFile - getNamedDeclarations(): Declaration[]; ->getNamedDeclarations : () => Declaration[] ->Declaration : Declaration - getLineAndCharacterOfPosition(pos: number): LineAndCharacter; >getLineAndCharacterOfPosition : (pos: number) => LineAndCharacter >pos : number diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index 6bdf755ae12..b160719f947 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -1594,7 +1594,6 @@ declare module "typescript" { getDocumentationComment(): SymbolDisplayPart[]; } interface SourceFile { - getNamedDeclarations(): Declaration[]; getLineAndCharacterOfPosition(pos: number): LineAndCharacter; getLineStarts(): number[]; getPositionOfLineAndCharacter(line: number, character: number): number; diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index 4bd248d70c7..4ac4e6da456 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -5114,10 +5114,6 @@ declare module "typescript" { interface SourceFile { >SourceFile : SourceFile - getNamedDeclarations(): Declaration[]; ->getNamedDeclarations : () => Declaration[] ->Declaration : Declaration - getLineAndCharacterOfPosition(pos: number): LineAndCharacter; >getLineAndCharacterOfPosition : (pos: number) => LineAndCharacter >pos : number diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index 3c11e27f0e1..a5ec8a9a8ab 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -1631,7 +1631,6 @@ declare module "typescript" { getDocumentationComment(): SymbolDisplayPart[]; } interface SourceFile { - getNamedDeclarations(): Declaration[]; getLineAndCharacterOfPosition(pos: number): LineAndCharacter; getLineStarts(): number[]; getPositionOfLineAndCharacter(line: number, character: number): number; diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index f38cdc9b1af..8166244a838 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -5287,10 +5287,6 @@ declare module "typescript" { interface SourceFile { >SourceFile : SourceFile - getNamedDeclarations(): Declaration[]; ->getNamedDeclarations : () => Declaration[] ->Declaration : Declaration - getLineAndCharacterOfPosition(pos: number): LineAndCharacter; >getLineAndCharacterOfPosition : (pos: number) => LineAndCharacter >pos : number diff --git a/tests/cases/fourslash/navigationItemsOverloads2.ts b/tests/cases/fourslash/navigationItemsOverloads2.ts index 2c33ef65f0d..98908c84e98 100644 --- a/tests/cases/fourslash/navigationItemsOverloads2.ts +++ b/tests/cases/fourslash/navigationItemsOverloads2.ts @@ -8,5 +8,5 @@ ////interface I { //// interfaceMethodSignature(b: boolean): boolean; ////} - +debugger; verify.navigationItemsListCount(2, "interfaceMethodSignature", "exact"); diff --git a/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts b/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts index d2a9ec8e25f..21b7d33dd41 100644 --- a/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts +++ b/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts @@ -4,7 +4,7 @@ ////function overload1(b: boolean): boolean; ////function overload1(b: number): boolean; //// -////var heyImNotInterruptingAnythingAmI = '?'; +////var x= '?'; //// ////function overload1(f: typeof overload): boolean; ////function overload1(x: any, b = (function overload() { return false })): boolean { @@ -15,7 +15,7 @@ ////function overload2(b: boolean): boolean; ////function overload2(b: number): boolean; //// -////function iJustRuinEverything(x: any, b = (function overload() { return false })): boolean { +////function y(x: any, b = (function overload() { return false })): boolean { //// throw overload; ////} //// @@ -24,6 +24,6 @@ //// throw overload; ////} -verify.navigationItemsListCount(2, "overload1", "exact"); -verify.navigationItemsListCount(2, "overload2", "exact"); -verify.navigationItemsListCount(4, "overload", "prefix"); \ No newline at end of file +verify.navigationItemsListCount(1, "overload1", "exact"); +verify.navigationItemsListCount(1, "overload2", "exact"); +verify.navigationItemsListCount(2, "overload", "prefix"); \ No newline at end of file From 1178e84a68268728cd1c9703562c5af0aa17e060 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 3 Apr 2015 16:50:32 -0700 Subject: [PATCH 02/11] Don't cache the typechecker at the LS level. Just get it when needed from the program. --- src/services/services.ts | 111 +++++++++--------- src/services/signatureHelp.ts | 4 +- .../fourslash/definitionNameOnEnumMember.ts | 1 + 3 files changed, 61 insertions(+), 55 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 67d799f62f0..5a200489db6 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2284,8 +2284,6 @@ module ts { let ruleProvider: formatting.RulesProvider; let program: Program; - // this checker is used to answer all LS questions except errors - let typeInfoResolver: TypeChecker; let useCaseSensitivefileNames = false; let cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken()); @@ -2367,8 +2365,10 @@ module ts { } program = newProgram; - typeInfoResolver = program.getTypeChecker(); + // Make sure all the nodes in the program are both bound, and have their parent + // pointers set property. + program.getTypeChecker(); return; function getOrCreateSourceFile(fileName: string): SourceFile { @@ -2452,15 +2452,8 @@ module ts { return program; } - /** - * Clean up any semantic caches that are not needed. - * The host can call this method if it wants to jettison unused memory. - * We will just dump the typeChecker and recreate a new one. this should have the effect of destroying all the semantic caches. - */ function cleanupSemanticCache(): void { - if (program) { - typeInfoResolver = program.getTypeChecker(); - } + // TODO: Should we jettison the program (or it's type checker) here? } function dispose(): void { @@ -2728,32 +2721,8 @@ module ts { return unescapeIdentifier(displayName); } - function createCompletionEntry(symbol: Symbol, typeChecker: TypeChecker, location: Node): CompletionEntry { - // Try to get a valid display name for this symbol, if we could not find one, then ignore it. - // We would like to only show things that can be added after a dot, so for instance numeric properties can - // not be accessed with a dot (a.1 <- invalid) - let displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, /*performCharacterChecks:*/ true); - if (!displayName) { - return undefined; - } - - // TODO(drosen): Right now we just permit *all* semantic meanings when calling - // 'getSymbolKind' which is permissible given that it is backwards compatible; but - // really we should consider passing the meaning for the node so that we don't report - // that a suggestion for a value is an interface. We COULD also just do what - // 'getSymbolModifiers' does, which is to use the first declaration. - - // Use a 'sortText' of 0' so that all symbol completion entries come before any other - // entries (like JavaScript identifier entries). - return { - name: displayName, - kind: getSymbolKind(symbol, typeChecker, location), - kindModifiers: getSymbolModifiers(symbol), - sortText: "0", - }; - } - function getCompletionData(fileName: string, position: number) { + let typeInfoResolver = program.getTypeChecker(); let syntacticStart = new Date().getTime(); let sourceFile = getValidSourceFile(fileName); @@ -3307,6 +3276,31 @@ module ts { return entries; } + function createCompletionEntry(symbol: Symbol, location: Node): CompletionEntry { + // Try to get a valid display name for this symbol, if we could not find one, then ignore it. + // We would like to only show things that can be added after a dot, so for instance numeric properties can + // not be accessed with a dot (a.1 <- invalid) + let displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, /*performCharacterChecks:*/ true); + if (!displayName) { + return undefined; + } + + // TODO(drosen): Right now we just permit *all* semantic meanings when calling + // 'getSymbolKind' which is permissible given that it is backwards compatible; but + // really we should consider passing the meaning for the node so that we don't report + // that a suggestion for a value is an interface. We COULD also just do what + // 'getSymbolModifiers' does, which is to use the first declaration. + + // Use a 'sortText' of 0' so that all symbol completion entries come before any other + // entries (like JavaScript identifier entries). + return { + name: displayName, + kind: getSymbolKind(symbol, location), + kindModifiers: getSymbolModifiers(symbol), + sortText: "0", + }; + } + function getCompletionEntriesFromSymbols(symbols: Symbol[]): CompletionEntry[] { let start = new Date().getTime(); var entries: CompletionEntry[] = []; @@ -3314,7 +3308,7 @@ module ts { if (symbols) { var nameToSymbol: Map = {}; for (let symbol of symbols) { - let entry = createCompletionEntry(symbol, typeInfoResolver, location); + let entry = createCompletionEntry(symbol, location); if (entry) { let id = escapeIdentifier(entry.name); if (!lookUp(nameToSymbol, id)) { @@ -3346,7 +3340,7 @@ module ts { let symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, target, /*performCharacterChecks:*/ false) === entryName ? s : undefined); if (symbol) { - let displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getValidSourceFile(fileName), location, typeInfoResolver, location, SemanticMeaning.All); + let displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getValidSourceFile(fileName), location, location, SemanticMeaning.All); return { name: entryName, kind: displayPartsDocumentationsAndSymbolKind.symbolKind, @@ -3373,7 +3367,7 @@ module ts { } // TODO(drosen): use contextual SemanticMeaning. - function getSymbolKind(symbol: Symbol, typeResolver: TypeChecker, location: Node): string { + function getSymbolKind(symbol: Symbol, location: Node): string { let flags = symbol.getFlags(); if (flags & SymbolFlags.Class) return ScriptElementKind.classElement; @@ -3382,7 +3376,7 @@ module ts { if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement; if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; - let result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, typeResolver, location); + let result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, location); if (result === ScriptElementKind.unknown) { if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; if (flags & SymbolFlags.EnumMember) return ScriptElementKind.variableElement; @@ -3393,7 +3387,9 @@ module ts { return result; } - function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags, typeResolver: TypeChecker, location: Node) { + function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags, location: Node) { + let typeResolver = program.getTypeChecker(); + if (typeResolver.isUndefinedSymbol(symbol)) { return ScriptElementKind.variableElement; } @@ -3421,7 +3417,7 @@ module ts { if (flags & SymbolFlags.Property) { if (flags & SymbolFlags.UnionProperty) { // If union property is result of union of non method (property/accessors/variables), it is labeled as property - let unionPropertyKind = forEach(typeInfoResolver.getRootSymbols(symbol), rootSymbol => { + let unionPropertyKind = forEach(typeResolver.getRootSymbols(symbol), rootSymbol => { let rootSymbolFlags = rootSymbol.getFlags(); if (rootSymbolFlags & (SymbolFlags.PropertyOrAccessor | SymbolFlags.Variable)) { return ScriptElementKind.memberVariableElement; @@ -3431,7 +3427,7 @@ module ts { if (!unionPropertyKind) { // If this was union of all methods, //make sure it has call signatures before we can label it as method - let typeOfUnionProperty = typeInfoResolver.getTypeOfSymbolAtLocation(symbol, location); + let typeOfUnionProperty = typeResolver.getTypeOfSymbolAtLocation(symbol, location); if (typeOfUnionProperty.getCallSignatures().length) { return ScriptElementKind.memberFunctionElement; } @@ -3464,15 +3460,16 @@ module ts { : ScriptElementKindModifier.none; } + // TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location function getSymbolDisplayPartsDocumentationAndSymbolKind(symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node, - typeResolver: TypeChecker, location: Node, - // TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location - semanticMeaning = getMeaningFromLocation(location)) { + location: Node, semanticMeaning = getMeaningFromLocation(location)) { + + let typeResolver = program.getTypeChecker(); let displayParts: SymbolDisplayPart[] = []; let documentation: SymbolDisplayPart[]; let symbolFlags = symbol.flags; - let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags, typeResolver, location); + let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags, location); let hasAddedSymbolInfo: boolean; let type: Type; @@ -3738,7 +3735,7 @@ module ts { } } else { - symbolKind = getSymbolKind(symbol, typeResolver, location); + symbolKind = getSymbolKind(symbol, location); } } @@ -3817,6 +3814,7 @@ module ts { return undefined; } + let typeInfoResolver = program.getTypeChecker(); let symbol = typeInfoResolver.getSymbolAtLocation(node); if (!symbol) { // Try getting just type at this position and show @@ -3842,7 +3840,7 @@ module ts { return undefined; } - let displayPartsDocumentationsAndKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, getContainerNode(node), typeInfoResolver, node); + let displayPartsDocumentationsAndKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, getContainerNode(node), node); return { kind: displayPartsDocumentationsAndKind.symbolKind, kindModifiers: getSymbolModifiers(symbol), @@ -3898,6 +3896,7 @@ module ts { return undefined; } + let typeInfoResolver = program.getTypeChecker(); let symbol = typeInfoResolver.getSymbolAtLocation(node); // Could not find a symbol e.g. node is string or number keyword, @@ -3929,7 +3928,7 @@ module ts { } let shorthandDeclarations = shorthandSymbol.getDeclarations(); - let shorthandSymbolKind = getSymbolKind(shorthandSymbol, typeInfoResolver, node); + let shorthandSymbolKind = getSymbolKind(shorthandSymbol, node); let shorthandSymbolName = typeInfoResolver.symbolToString(shorthandSymbol); let shorthandContainerName = typeInfoResolver.symbolToString(symbol.parent, node); return map(shorthandDeclarations, @@ -3939,7 +3938,7 @@ module ts { let result: DefinitionInfo[] = []; let declarations = symbol.getDeclarations(); let symbolName = typeInfoResolver.symbolToString(symbol); // Do not get scoped name, just the name of the symbol - let symbolKind = getSymbolKind(symbol, typeInfoResolver, node); + let symbolKind = getSymbolKind(symbol, node); let containerSymbol = symbol.parent; let containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : ""; @@ -4609,6 +4608,8 @@ module ts { } function getReferencesForNode(node: Node, sourceFiles: SourceFile[], searchOnlyInCurrentFile: boolean, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[]{ + let typeInfoResolver = program.getTypeChecker(); + // Labels if (isLabelName(node)) { if (isJumpStatementTarget(node)) { @@ -4689,7 +4690,7 @@ module ts { return result; function getDefinition(symbol: Symbol): DefinitionInfo { - let info = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, node.getSourceFile(), getContainerNode(node), typeInfoResolver, node); + let info = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, node.getSourceFile(), getContainerNode(node), node); let name = map(info.displayParts, p => p.text).join(""); let declarations = symbol.declarations; if (!declarations || declarations.length === 0) { @@ -5615,7 +5616,7 @@ module ts { let sourceFile = getValidSourceFile(fileName); - return SignatureHelp.getSignatureHelpItems(sourceFile, position, typeInfoResolver, cancellationToken); + return SignatureHelp.getSignatureHelpItems(program, sourceFile, position, cancellationToken); } /// Syntactic features @@ -5696,6 +5697,7 @@ module ts { synchronizeHostData(); let sourceFile = getValidSourceFile(fileName); + let typeInfoResolver = program.getTypeChecker(); let result: ClassifiedSpan[] = []; processNode(sourceFile); @@ -6230,6 +6232,7 @@ module ts { synchronizeHostData(); let sourceFile = getValidSourceFile(fileName); + let typeInfoResolver = program.getTypeChecker(); let node = getTouchingWord(sourceFile, position); @@ -6252,7 +6255,7 @@ module ts { } } - let kind = getSymbolKind(symbol, typeInfoResolver, node); + let kind = getSymbolKind(symbol, node); if (kind) { return { canRename: true, diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 419d4819ba6..e7b88e3a2fd 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -178,7 +178,9 @@ module ts.SignatureHelp { argumentCount: number; } - export function getSignatureHelpItems(sourceFile: SourceFile, position: number, typeInfoResolver: TypeChecker, cancellationToken: CancellationTokenObject): SignatureHelpItems { + export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, cancellationToken: CancellationTokenObject): SignatureHelpItems { + let typeInfoResolver = program.getTypeChecker(); + // Decide whether to show signature help let startingToken = findTokenOnLeftOfPosition(sourceFile, position); if (!startingToken) { diff --git a/tests/cases/fourslash/definitionNameOnEnumMember.ts b/tests/cases/fourslash/definitionNameOnEnumMember.ts index d88e1ef688e..3844d4a46f3 100644 --- a/tests/cases/fourslash/definitionNameOnEnumMember.ts +++ b/tests/cases/fourslash/definitionNameOnEnumMember.ts @@ -7,5 +7,6 @@ ////} ////var enumMember = e./*1*/thirdMember; +debugger; goTo.marker("1"); verify.verifyDefinitionsName("thirdMember", "e"); \ No newline at end of file From 766d34d0dcd6b467b4ac6d7283a3e817924546e9 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 3 Apr 2015 16:55:54 -0700 Subject: [PATCH 03/11] Rename variables to be consistent. --- src/services/services.ts | 130 +++++++++++++++++----------------- src/services/signatureHelp.ts | 18 ++--- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 5a200489db6..d23c5fa1dfb 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2722,7 +2722,7 @@ module ts { } function getCompletionData(fileName: string, position: number) { - let typeInfoResolver = program.getTypeChecker(); + let typeChecker = program.getTypeChecker(); let syntacticStart = new Date().getTime(); let sourceFile = getValidSourceFile(fileName); @@ -2806,29 +2806,29 @@ module ts { isNewIdentifierLocation = false; if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression) { - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let symbol = typeChecker.getSymbolAtLocation(node); // This is an alias, follow what it aliases if (symbol && symbol.flags & SymbolFlags.Alias) { - symbol = typeInfoResolver.getAliasedSymbol(symbol); + symbol = typeChecker.getAliasedSymbol(symbol); } if (symbol && symbol.flags & SymbolFlags.HasExports) { // Extract module or enum members - let exportedSymbols = typeInfoResolver.getExportsOfModule(symbol); + let exportedSymbols = typeChecker.getExportsOfModule(symbol); forEach(exportedSymbols, symbol => { - if (typeInfoResolver.isValidPropertyAccess((node.parent), symbol.name)) { + if (typeChecker.isValidPropertyAccess((node.parent), symbol.name)) { symbols.push(symbol); } }); } } - let type = typeInfoResolver.getTypeAtLocation(node); + let type = typeChecker.getTypeAtLocation(node); if (type) { // Filter private properties forEach(type.getApparentProperties(), symbol => { - if (typeInfoResolver.isValidPropertyAccess((node.parent), symbol.name)) { + if (typeChecker.isValidPropertyAccess((node.parent), symbol.name)) { symbols.push(symbol); } }); @@ -2842,12 +2842,12 @@ module ts { isMemberCompletion = true; isNewIdentifierLocation = true; - let contextualType = typeInfoResolver.getContextualType(containingObjectLiteral); + let contextualType = typeChecker.getContextualType(containingObjectLiteral); if (!contextualType) { return false; } - let contextualTypeMembers = typeInfoResolver.getPropertiesOfType(contextualType); + let contextualTypeMembers = typeChecker.getPropertiesOfType(contextualType); if (contextualTypeMembers && contextualTypeMembers.length > 0) { // Add filtered items to the completion list symbols = filterContextualMembersList(contextualTypeMembers, containingObjectLiteral.properties); @@ -2864,9 +2864,9 @@ module ts { let exports: Symbol[]; if (importDeclaration.moduleSpecifier) { - let moduleSpecifierSymbol = typeInfoResolver.getSymbolAtLocation(importDeclaration.moduleSpecifier); + let moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importDeclaration.moduleSpecifier); if (moduleSpecifierSymbol) { - exports = typeInfoResolver.getExportsOfModule(moduleSpecifierSymbol); + exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol); } } @@ -2915,7 +2915,7 @@ module ts { /// TODO filter meaning based on the current context let symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Alias; - symbols = typeInfoResolver.getSymbolsInScope(scopeNode, symbolMeanings); + symbols = typeChecker.getSymbolsInScope(scopeNode, symbolMeanings); } return true; @@ -3388,12 +3388,12 @@ module ts { } function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags, location: Node) { - let typeResolver = program.getTypeChecker(); + let typeChecker = program.getTypeChecker(); - if (typeResolver.isUndefinedSymbol(symbol)) { + if (typeChecker.isUndefinedSymbol(symbol)) { return ScriptElementKind.variableElement; } - if (typeResolver.isArgumentsSymbol(symbol)) { + if (typeChecker.isArgumentsSymbol(symbol)) { return ScriptElementKind.localVariableElement; } if (flags & SymbolFlags.Variable) { @@ -3417,7 +3417,7 @@ module ts { if (flags & SymbolFlags.Property) { if (flags & SymbolFlags.UnionProperty) { // If union property is result of union of non method (property/accessors/variables), it is labeled as property - let unionPropertyKind = forEach(typeResolver.getRootSymbols(symbol), rootSymbol => { + let unionPropertyKind = forEach(typeChecker.getRootSymbols(symbol), rootSymbol => { let rootSymbolFlags = rootSymbol.getFlags(); if (rootSymbolFlags & (SymbolFlags.PropertyOrAccessor | SymbolFlags.Variable)) { return ScriptElementKind.memberVariableElement; @@ -3427,7 +3427,7 @@ module ts { if (!unionPropertyKind) { // If this was union of all methods, //make sure it has call signatures before we can label it as method - let typeOfUnionProperty = typeResolver.getTypeOfSymbolAtLocation(symbol, location); + let typeOfUnionProperty = typeChecker.getTypeOfSymbolAtLocation(symbol, location); if (typeOfUnionProperty.getCallSignatures().length) { return ScriptElementKind.memberFunctionElement; } @@ -3464,7 +3464,7 @@ module ts { function getSymbolDisplayPartsDocumentationAndSymbolKind(symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node, location: Node, semanticMeaning = getMeaningFromLocation(location)) { - let typeResolver = program.getTypeChecker(); + let typeChecker = program.getTypeChecker(); let displayParts: SymbolDisplayPart[] = []; let documentation: SymbolDisplayPart[]; @@ -3481,7 +3481,7 @@ module ts { } let signature: Signature; - type = typeResolver.getTypeOfSymbolAtLocation(symbol, location); + type = typeChecker.getTypeOfSymbolAtLocation(symbol, location); if (type) { if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) { let right = (location.parent).name; @@ -3502,7 +3502,7 @@ module ts { if (callExpression) { let candidateSignatures: Signature[] = []; - signature = typeResolver.getResolvedSignature(callExpression, candidateSignatures); + signature = typeChecker.getResolvedSignature(callExpression, candidateSignatures); if (!signature && candidateSignatures.length) { // Use the first candidate: signature = candidateSignatures[0]; @@ -3551,7 +3551,7 @@ module ts { displayParts.push(spacePart()); } if (!(type.flags & TypeFlags.Anonymous)) { - displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); + displayParts.push.apply(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); } addSignatureDisplayParts(signature, allSignatures, TypeFormatFlags.WriteArrowStyleSignature); break; @@ -3568,8 +3568,8 @@ module ts { // get the signature from the declaration and write it let functionDeclaration = location.parent; let allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getConstructSignatures() : type.getCallSignatures(); - if (!typeResolver.isImplementationOfOverload(functionDeclaration)) { - signature = typeResolver.getSignatureFromDeclaration(functionDeclaration); + if (!typeChecker.isImplementationOfOverload(functionDeclaration)) { + signature = typeChecker.getSignatureFromDeclaration(functionDeclaration); } else { signature = allSignatures[0]; @@ -3612,7 +3612,7 @@ module ts { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); displayParts.push(spacePart()); - displayParts.push.apply(displayParts, typeToDisplayParts(typeResolver, typeResolver.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration)); + displayParts.push.apply(displayParts, typeToDisplayParts(typeChecker, typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration)); } if (symbolFlags & SymbolFlags.Enum) { addNewLineIfDisplayPartsExist(); @@ -3648,7 +3648,7 @@ module ts { else { // Method/function type parameter let signatureDeclaration = getDeclarationOfKind(symbol, SyntaxKind.TypeParameter).parent; - let signature = typeResolver.getSignatureFromDeclaration(signatureDeclaration); + let signature = typeChecker.getSignatureFromDeclaration(signatureDeclaration); if (signatureDeclaration.kind === SyntaxKind.ConstructSignature) { displayParts.push(keywordPart(SyntaxKind.NewKeyword)); displayParts.push(spacePart()); @@ -3656,14 +3656,14 @@ module ts { else if (signatureDeclaration.kind !== SyntaxKind.CallSignature && signatureDeclaration.name) { addFullSymbolName(signatureDeclaration.symbol); } - displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); + displayParts.push.apply(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); } } if (symbolFlags & SymbolFlags.EnumMember) { addPrefixForAnyFunctionOrVar(symbol, "enum member"); let declaration = symbol.declarations[0]; if (declaration.kind === SyntaxKind.EnumMember) { - let constantValue = typeResolver.getConstantValue(declaration); + let constantValue = typeChecker.getConstantValue(declaration); if (constantValue !== undefined) { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); @@ -3690,7 +3690,7 @@ module ts { displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); } else { - let internalAliasSymbol = typeResolver.getSymbolAtLocation(importEqualsDeclaration.moduleReference); + let internalAliasSymbol = typeChecker.getSymbolAtLocation(importEqualsDeclaration.moduleReference); if (internalAliasSymbol) { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); @@ -3715,12 +3715,12 @@ module ts { // If the type is type parameter, format it specially if (type.symbol && type.symbol.flags & SymbolFlags.TypeParameter) { let typeParameterParts = mapToDisplayParts(writer => { - typeResolver.getSymbolDisplayBuilder().buildTypeParameterDisplay(type, writer, enclosingDeclaration); + typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(type, writer, enclosingDeclaration); }); displayParts.push.apply(displayParts, typeParameterParts); } else { - displayParts.push.apply(displayParts, typeToDisplayParts(typeResolver, type, enclosingDeclaration)); + displayParts.push.apply(displayParts, typeToDisplayParts(typeChecker, type, enclosingDeclaration)); } } else if (symbolFlags & SymbolFlags.Function || @@ -3752,7 +3752,7 @@ module ts { } function addFullSymbolName(symbol: Symbol, enclosingDeclaration?: Node) { - let fullSymbolDisplayParts = symbolToDisplayParts(typeResolver, symbol, enclosingDeclaration || sourceFile, /*meaning*/ undefined, + let fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbol, enclosingDeclaration || sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing); displayParts.push.apply(displayParts, fullSymbolDisplayParts); } @@ -3784,7 +3784,7 @@ module ts { } function addSignatureDisplayParts(signature: Signature, allSignatures: Signature[], flags?: TypeFormatFlags) { - displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature)); + displayParts.push.apply(displayParts, signatureToDisplayParts(typeChecker, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature)); if (allSignatures.length > 1) { displayParts.push(spacePart()); displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); @@ -3799,7 +3799,7 @@ module ts { function writeTypeParametersOfSymbol(symbol: Symbol, enclosingDeclaration: Node) { let typeParameterParts = mapToDisplayParts(writer => { - typeResolver.getSymbolDisplayBuilder().buildTypeParameterDisplayFromSymbol(symbol, writer, enclosingDeclaration); + typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplayFromSymbol(symbol, writer, enclosingDeclaration); }); displayParts.push.apply(displayParts, typeParameterParts); } @@ -3814,8 +3814,8 @@ module ts { return undefined; } - let typeInfoResolver = program.getTypeChecker(); - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let typeChecker = program.getTypeChecker(); + let symbol = typeChecker.getSymbolAtLocation(node); if (!symbol) { // Try getting just type at this position and show switch (node.kind) { @@ -3825,13 +3825,13 @@ module ts { case SyntaxKind.ThisKeyword: case SyntaxKind.SuperKeyword: // For the identifiers/this/super etc get the type at position - let type = typeInfoResolver.getTypeAtLocation(node); + let type = typeChecker.getTypeAtLocation(node); if (type) { return { kind: ScriptElementKind.unknown, kindModifiers: ScriptElementKindModifier.none, textSpan: createTextSpan(node.getStart(), node.getWidth()), - displayParts: typeToDisplayParts(typeInfoResolver, type, getContainerNode(node)), + displayParts: typeToDisplayParts(typeChecker, type, getContainerNode(node)), documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined }; } @@ -3896,8 +3896,8 @@ module ts { return undefined; } - let typeInfoResolver = program.getTypeChecker(); - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let typeChecker = program.getTypeChecker(); + let symbol = typeChecker.getSymbolAtLocation(node); // Could not find a symbol e.g. node is string or number keyword, // or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol @@ -3912,7 +3912,7 @@ module ts { if (symbol.flags & SymbolFlags.Alias) { let declaration = symbol.declarations[0]; if (node.kind === SyntaxKind.Identifier && node.parent === declaration) { - symbol = typeInfoResolver.getAliasedSymbol(symbol); + symbol = typeChecker.getAliasedSymbol(symbol); } } @@ -3922,25 +3922,25 @@ module ts { // is performed at the location of property access, we would like to go to definition of the property in the short-hand // assignment. This case and others are handled by the following code. if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) { - let shorthandSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(symbol.valueDeclaration); + let shorthandSymbol = typeChecker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration); if (!shorthandSymbol) { return []; } let shorthandDeclarations = shorthandSymbol.getDeclarations(); let shorthandSymbolKind = getSymbolKind(shorthandSymbol, node); - let shorthandSymbolName = typeInfoResolver.symbolToString(shorthandSymbol); - let shorthandContainerName = typeInfoResolver.symbolToString(symbol.parent, node); + let shorthandSymbolName = typeChecker.symbolToString(shorthandSymbol); + let shorthandContainerName = typeChecker.symbolToString(symbol.parent, node); return map(shorthandDeclarations, declaration => createDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName)); } let result: DefinitionInfo[] = []; let declarations = symbol.getDeclarations(); - let symbolName = typeInfoResolver.symbolToString(symbol); // Do not get scoped name, just the name of the symbol + let symbolName = typeChecker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol let symbolKind = getSymbolKind(symbol, node); let containerSymbol = symbol.parent; - let containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : ""; + let containerName = containerSymbol ? typeChecker.symbolToString(containerSymbol, node) : ""; if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) && !tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) { @@ -4608,7 +4608,7 @@ module ts { } function getReferencesForNode(node: Node, sourceFiles: SourceFile[], searchOnlyInCurrentFile: boolean, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[]{ - let typeInfoResolver = program.getTypeChecker(); + let typeChecker = program.getTypeChecker(); // Labels if (isLabelName(node)) { @@ -4632,7 +4632,7 @@ module ts { return getReferencesForSuperKeyword(node); } - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let symbol = typeChecker.getSymbolAtLocation(node); // Could not find a symbol e.g. unknown identifier if (!symbol) { @@ -4740,7 +4740,7 @@ module ts { return location.getText(); } - name = typeInfoResolver.symbolToString(symbol); + name = typeChecker.symbolToString(symbol); return stripQuotes(name); } @@ -4976,10 +4976,10 @@ module ts { return; } - let referenceSymbol = typeInfoResolver.getSymbolAtLocation(referenceLocation); + let referenceSymbol = typeChecker.getSymbolAtLocation(referenceLocation); if (referenceSymbol) { let referenceSymbolDeclaration = referenceSymbol.valueDeclaration; - let shorthandValueSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration); + let shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration); var relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation); if (relatedSymbol) { @@ -5204,7 +5204,7 @@ module ts { // If the symbol is an alias, add what it alaises to the list if (isImportOrExportSpecifierImportSymbol(symbol)) { - result.push(typeInfoResolver.getAliasedSymbol(symbol)); + result.push(typeChecker.getAliasedSymbol(symbol)); } // If the location is in a context sensitive location (i.e. in an object literal) try @@ -5212,7 +5212,7 @@ module ts { // type to the search set if (isNameOfPropertyAssignment(location)) { forEach(getPropertySymbolsFromContextualType(location), contextualSymbol => { - result.push.apply(result, typeInfoResolver.getRootSymbols(contextualSymbol)); + result.push.apply(result, typeChecker.getRootSymbols(contextualSymbol)); }); /* Because in short-hand property assignment, location has two meaning : property name and as value of the property @@ -5226,7 +5226,7 @@ module ts { * so that when matching with potential reference symbol, both symbols from property declaration and variable declaration * will be included correctly. */ - let shorthandValueSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(location.parent); + let shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(location.parent); if (shorthandValueSymbol) { result.push(shorthandValueSymbol); } @@ -5234,7 +5234,7 @@ module ts { // If this is a union property, add all the symbols from all its source symbols in all unioned types. // If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list - forEach(typeInfoResolver.getRootSymbols(symbol), rootSymbol => { + forEach(typeChecker.getRootSymbols(symbol), rootSymbol => { if (rootSymbol !== symbol) { result.push(rootSymbol); } @@ -5264,9 +5264,9 @@ module ts { function getPropertySymbolFromTypeReference(typeReference: HeritageClauseElement) { if (typeReference) { - let type = typeInfoResolver.getTypeAtLocation(typeReference); + let type = typeChecker.getTypeAtLocation(typeReference); if (type) { - let propertySymbol = typeInfoResolver.getPropertyOfType(type, propertyName); + let propertySymbol = typeChecker.getPropertyOfType(type, propertyName); if (propertySymbol) { result.push(propertySymbol); } @@ -5286,7 +5286,7 @@ module ts { // If the reference symbol is an alias, check if what it is aliasing is one of the search // symbols. if (isImportOrExportSpecifierImportSymbol(referenceSymbol)) { - var aliasedSymbol = typeInfoResolver.getAliasedSymbol(referenceSymbol); + var aliasedSymbol = typeChecker.getAliasedSymbol(referenceSymbol); if (searchSymbols.indexOf(aliasedSymbol) >= 0) { return aliasedSymbol; } @@ -5297,13 +5297,13 @@ module ts { // compare to our searchSymbol if (isNameOfPropertyAssignment(referenceLocation)) { return forEach(getPropertySymbolsFromContextualType(referenceLocation), contextualSymbol => { - return forEach(typeInfoResolver.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined); + return forEach(typeChecker.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined); }); } // Unwrap symbols to get to the root (e.g. transient symbols as a result of widening) // Or a union property, use its underlying unioned symbols - return forEach(typeInfoResolver.getRootSymbols(referenceSymbol), rootSymbol => { + return forEach(typeChecker.getRootSymbols(referenceSymbol), rootSymbol => { // if it is in the list, then we are done if (searchSymbols.indexOf(rootSymbol) >= 0) { return rootSymbol; @@ -5324,7 +5324,7 @@ module ts { function getPropertySymbolsFromContextualType(node: Node): Symbol[] { if (isNameOfPropertyAssignment(node)) { let objectLiteral = node.parent.parent; - let contextualType = typeInfoResolver.getContextualType(objectLiteral); + let contextualType = typeChecker.getContextualType(objectLiteral); let name = (node).text; if (contextualType) { if (contextualType.flags & TypeFlags.Union) { @@ -5697,7 +5697,7 @@ module ts { synchronizeHostData(); let sourceFile = getValidSourceFile(fileName); - let typeInfoResolver = program.getTypeChecker(); + let typeChecker = program.getTypeChecker(); let result: ClassifiedSpan[] = []; processNode(sourceFile); @@ -5750,7 +5750,7 @@ module ts { // Only walk into nodes that intersect the requested span. if (node && textSpanIntersectsWith(span, node.getStart(), node.getWidth())) { if (node.kind === SyntaxKind.Identifier && node.getWidth() > 0) { - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let symbol = typeChecker.getSymbolAtLocation(node); if (symbol) { let type = classifySymbol(symbol, getMeaningFromLocation(node)); if (type) { @@ -6232,13 +6232,13 @@ module ts { synchronizeHostData(); let sourceFile = getValidSourceFile(fileName); - let typeInfoResolver = program.getTypeChecker(); + let typeChecker = program.getTypeChecker(); let node = getTouchingWord(sourceFile, position); // Can only rename an identifier. if (node && node.kind === SyntaxKind.Identifier) { - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let symbol = typeChecker.getSymbolAtLocation(node); // Only allow a symbol to be renamed if it actually has at least one declaration. if (symbol) { @@ -6261,7 +6261,7 @@ module ts { canRename: true, localizedErrorMessage: undefined, displayName: symbol.name, - fullDisplayName: typeInfoResolver.getFullyQualifiedName(symbol), + fullDisplayName: typeChecker.getFullyQualifiedName(symbol), kind: kind, kindModifiers: getSymbolModifiers(symbol), triggerSpan: createTextSpan(node.getStart(), node.getWidth()) diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index e7b88e3a2fd..93856912dce 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -179,7 +179,7 @@ module ts.SignatureHelp { } export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, cancellationToken: CancellationTokenObject): SignatureHelpItems { - let typeInfoResolver = program.getTypeChecker(); + let typeChecker = program.getTypeChecker(); // Decide whether to show signature help let startingToken = findTokenOnLeftOfPosition(sourceFile, position); @@ -198,7 +198,7 @@ module ts.SignatureHelp { let call = argumentInfo.invocation; let candidates = []; - let resolvedSignature = typeInfoResolver.getResolvedSignature(call, candidates); + let resolvedSignature = typeChecker.getResolvedSignature(call, candidates); cancellationToken.throwIfCancellationRequested(); if (!candidates.length) { @@ -496,8 +496,8 @@ module ts.SignatureHelp { let invocation = argumentListInfo.invocation; let callTarget = getInvokedExpression(invocation) - let callTargetSymbol = typeInfoResolver.getSymbolAtLocation(callTarget); - let callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeInfoResolver, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined); + let callTargetSymbol = typeChecker.getSymbolAtLocation(callTarget); + let callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined); let items: SignatureHelpItem[] = map(candidates, candidateSignature => { let signatureHelpParameters: SignatureHelpParameter[]; let prefixDisplayParts: SymbolDisplayPart[] = []; @@ -513,12 +513,12 @@ module ts.SignatureHelp { signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray; suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken)); let parameterParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.parameters, writer, invocation)); + typeChecker.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.parameters, writer, invocation)); suffixDisplayParts.push.apply(suffixDisplayParts, parameterParts); } else { let typeParameterParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, invocation)); + typeChecker.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, invocation)); prefixDisplayParts.push.apply(prefixDisplayParts, typeParameterParts); prefixDisplayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); @@ -528,7 +528,7 @@ module ts.SignatureHelp { } let returnTypeParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, invocation)); + typeChecker.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, invocation)); suffixDisplayParts.push.apply(suffixDisplayParts, returnTypeParts); return { @@ -563,7 +563,7 @@ module ts.SignatureHelp { function createSignatureHelpParameterForParameter(parameter: Symbol): SignatureHelpParameter { let displayParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, invocation)); + typeChecker.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, invocation)); let isOptional = hasQuestionToken(parameter.valueDeclaration); @@ -577,7 +577,7 @@ module ts.SignatureHelp { function createSignatureHelpParameterForTypeParameter(typeParameter: TypeParameter): SignatureHelpParameter { let displayParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildTypeParameterDisplay(typeParameter, writer, invocation)); + typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(typeParameter, writer, invocation)); return { name: typeParameter.symbol.name, From 78a79140b3a193af285416d4401b84c0180927d2 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 6 Apr 2015 14:10:04 -0700 Subject: [PATCH 04/11] Get sighelp for arbitrary functions working in .js files. --- src/services/outliningElementsCollector.ts | 1 + src/services/services.ts | 4 -- src/services/signatureHelp.ts | 46 ++++++++++++++++++++++ src/services/utilities.ts | 4 ++ 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts index 4c9dcedc7a4..25e7671bbe4 100644 --- a/src/services/outliningElementsCollector.ts +++ b/src/services/outliningElementsCollector.ts @@ -35,6 +35,7 @@ module ts { return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction; } + let depth = 0; let maxDepth = 20; function walk(n: Node): void { diff --git a/src/services/services.ts b/src/services/services.ts index d23c5fa1dfb..25ecee61fdd 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2470,10 +2470,6 @@ module ts { return program.getSyntacticDiagnostics(getValidSourceFile(fileName)); } - function isJavaScript(fileName: string) { - return fileExtensionIs(fileName, ".js"); - } - /** * getSemanticDiagnostiscs return array of Diagnostics. If '-d' is not enabled, only report semantic errors * If '-d' enabled, report both semantic and emitter errors diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 93856912dce..07b963d2461 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -202,11 +202,57 @@ module ts.SignatureHelp { cancellationToken.throwIfCancellationRequested(); if (!candidates.length) { + // We didn't have any sig help items produced by the TS compiler. If this is a JS + // file, then see if we can figure out anything better. + if (isJavaScript(sourceFile.fileName)) { + return createJavaScriptSignatureHelpItems(argumentInfo); + } + return undefined; } return createSignatureHelpItems(candidates, resolvedSignature, argumentInfo); + function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo): SignatureHelpItems { + if (argumentInfo.invocation.kind !== SyntaxKind.CallExpression) { + return undefined; + } + + // See if we can find some symbol with the call expression name that has call signatures. + let callExpression = argumentInfo.invocation; + let expression = callExpression.expression; + let name = expression.kind === SyntaxKind.Identifier + ? expression + : expression.kind === SyntaxKind.PropertyAccessExpression + ? (expression).name + : undefined; + + if (!name || !name.text) { + return undefined; + } + + let typeChecker = program.getTypeChecker(); + for (let sourceFile of program.getSourceFiles()) { + let nameToDeclarations = sourceFile.getNamedDeclarations(); + let declarations = getProperty(nameToDeclarations, name.text); + + if (declarations) { + for (let declaration of declarations) { + let symbol = declaration.symbol; + if (symbol) { + let type = typeChecker.getTypeOfSymbolAtLocation(symbol, declaration); + if (type) { + let callSignatures = type.getCallSignatures(); + if (callSignatures && callSignatures.length) { + return createSignatureHelpItems(callSignatures, callSignatures[0], argumentInfo); + } + } + } + } + } + } + } + /** * Returns relevant information for the argument list and the current argument if we are * in the argument of an invocation; returns undefined otherwise. diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 719aa658724..5ad392c5a6c 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -650,4 +650,8 @@ module ts { typechecker.getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags); }); } + + export function isJavaScript(fileName: string) { + return fileExtensionIs(fileName, ".js"); + } } \ No newline at end of file From e8ee5005390b9434f4608c57a9a25f7d338ec848 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 12 Apr 2015 10:35:57 -0700 Subject: [PATCH 05/11] Consistently reduce union types in property access --- src/compiler/checker.ts | 51 +++++++++++-------- src/compiler/types.ts | 1 + ...onEntryForPropertyFromUnionOfModuleType.ts | 2 + .../goToDefinitionUnionTypeProperty2.ts | 4 +- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3c0bf39f1fa..1465f1ab51b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2846,16 +2846,17 @@ module ts { } function getPropertiesOfType(type: Type): Symbol[] { - if (type.flags & TypeFlags.Union) { - return getPropertiesOfUnionType(type); - } - return getPropertiesOfObjectType(getApparentType(type)); + type = getApparentType(type); + return type.flags & TypeFlags.Union ? getPropertiesOfUnionType(type) : getPropertiesOfObjectType(type); } // For a type parameter, return the base constraint of the type parameter. For the string, number, // boolean, and symbol primitive types, return the corresponding object types. Otherwise return the // type itself. Note that the apparent type of a union type is the union type itself. function getApparentType(type: Type): Type { + if (type.flags & TypeFlags.Union) { + type = getReducedTypeOfUnionType(type); + } if (type.flags & TypeFlags.TypeParameter) { do { type = getConstraintOfTypeParameter(type); @@ -2928,27 +2929,25 @@ module ts { // necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from // Object and Function as appropriate. function getPropertyOfType(type: Type, name: string): Symbol { + type = getApparentType(type); + if (type.flags & TypeFlags.ObjectType) { + let resolved = resolveObjectOrUnionTypeMembers(type); + if (hasProperty(resolved.members, name)) { + let symbol = resolved.members[name]; + if (symbolIsValue(symbol)) { + return symbol; + } + } + if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) { + let symbol = getPropertyOfObjectType(globalFunctionType, name); + if (symbol) return symbol; + } + return getPropertyOfObjectType(globalObjectType, name); + } if (type.flags & TypeFlags.Union) { return getPropertyOfUnionType(type, name); } - if (!(type.flags & TypeFlags.ObjectType)) { - type = getApparentType(type); - if (!(type.flags & TypeFlags.ObjectType)) { - return undefined; - } - } - let resolved = resolveObjectOrUnionTypeMembers(type); - if (hasProperty(resolved.members, name)) { - let symbol = resolved.members[name]; - if (symbolIsValue(symbol)) { - return symbol; - } - } - if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) { - let symbol = getPropertyOfObjectType(globalFunctionType, name); - if (symbol) return symbol; - } - return getPropertyOfObjectType(globalObjectType, name); + return undefined; } function getSignaturesOfObjectOrUnionType(type: Type, kind: SignatureKind): Signature[] { @@ -3526,10 +3525,18 @@ module ts { if (!type) { type = unionTypes[id] = createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(sortedTypes)); type.types = sortedTypes; + type.reducedType = noSubtypeReduction ? undefined : type; } return type; } + function getReducedTypeOfUnionType(type: UnionType): Type { + if (!type.reducedType) { + type.reducedType = getUnionType(type.types); + } + return type.reducedType; + } + function getTypeFromUnionTypeNode(node: UnionTypeNode): Type { let links = getNodeLinks(node); if (!links.resolvedType) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d24ee45e21e..e5dc3dc3306 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1458,6 +1458,7 @@ module ts { export interface UnionType extends Type { types: Type[]; // Constituent types + reducedType: Type; // Reduced union type (all subtypes removed) resolvedProperties: SymbolTable; // Cache of resolved properties } diff --git a/tests/cases/fourslash/completionEntryForPropertyFromUnionOfModuleType.ts b/tests/cases/fourslash/completionEntryForPropertyFromUnionOfModuleType.ts index 1e072acd1fa..a9205b97f1f 100644 --- a/tests/cases/fourslash/completionEntryForPropertyFromUnionOfModuleType.ts +++ b/tests/cases/fourslash/completionEntryForPropertyFromUnionOfModuleType.ts @@ -2,9 +2,11 @@ ////module E { //// export var n = 1; +//// export var x = 0; ////} ////module F { //// export var n = 1; +//// export var y = 0; ////} ////var q: typeof E | typeof F; ////var j = q./*1*/ diff --git a/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts b/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts index 674d5f4b623..0e18e543ec3 100644 --- a/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts +++ b/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts @@ -19,8 +19,8 @@ goTo.marker("propertyReference"); verify.definitionCountIs(2); goTo.definition(0); -verify.caretAtMarker("propertyDefinition2"); +verify.caretAtMarker("propertyDefinition1"); goTo.marker("propertyReference"); goTo.definition(1); -verify.caretAtMarker("propertyDefinition1"); +verify.caretAtMarker("propertyDefinition2"); From b7408fa0b4357171c874dcb91019a61cb9c4b625 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 12 Apr 2015 10:37:14 -0700 Subject: [PATCH 06/11] Accepting new baselines --- tests/baselines/reference/APISample_compile.js | 1 + tests/baselines/reference/APISample_compile.types | 4 ++++ tests/baselines/reference/APISample_linter.js | 1 + tests/baselines/reference/APISample_linter.types | 4 ++++ tests/baselines/reference/APISample_transform.js | 1 + tests/baselines/reference/APISample_transform.types | 4 ++++ tests/baselines/reference/APISample_watcher.js | 1 + tests/baselines/reference/APISample_watcher.types | 4 ++++ 8 files changed, 20 insertions(+) diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index 3f0ba5f18cd..c5455d26bac 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -1149,6 +1149,7 @@ declare module "typescript" { } interface UnionType extends Type { types: Type[]; + reducedType: Type; resolvedProperties: SymbolTable; } interface ResolvedType extends ObjectType, UnionType { diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index eff47a4cb7b..1df5b188d3a 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -3701,6 +3701,10 @@ declare module "typescript" { types: Type[]; >types : Type[] +>Type : Type + + reducedType: Type; +>reducedType : Type >Type : Type resolvedProperties: SymbolTable; diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index ab48f78affc..d9757de48a1 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -1180,6 +1180,7 @@ declare module "typescript" { } interface UnionType extends Type { types: Type[]; + reducedType: Type; resolvedProperties: SymbolTable; } interface ResolvedType extends ObjectType, UnionType { diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 600bf5c6adc..99d1405a244 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -3847,6 +3847,10 @@ declare module "typescript" { types: Type[]; >types : Type[] +>Type : Type + + reducedType: Type; +>reducedType : Type >Type : Type resolvedProperties: SymbolTable; diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index d40c078a150..019ff29148b 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -1181,6 +1181,7 @@ declare module "typescript" { } interface UnionType extends Type { types: Type[]; + reducedType: Type; resolvedProperties: SymbolTable; } interface ResolvedType extends ObjectType, UnionType { diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index 4ea9c49d758..f977fbcc2be 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -3797,6 +3797,10 @@ declare module "typescript" { types: Type[]; >types : Type[] +>Type : Type + + reducedType: Type; +>reducedType : Type >Type : Type resolvedProperties: SymbolTable; diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index c53034c11d7..832ddc25b1f 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -1218,6 +1218,7 @@ declare module "typescript" { } interface UnionType extends Type { types: Type[]; + reducedType: Type; resolvedProperties: SymbolTable; } interface ResolvedType extends ObjectType, UnionType { diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 3903e169b4e..8ecc20e860c 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -3970,6 +3970,10 @@ declare module "typescript" { types: Type[]; >types : Type[] +>Type : Type + + reducedType: Type; +>reducedType : Type >Type : Type resolvedProperties: SymbolTable; From c91e2855caae4e7c4cb5ab77faaa70e1a9be7df3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 12 Apr 2015 10:52:20 -0700 Subject: [PATCH 07/11] Adding test --- .../baselines/reference/unionTypeReduction.js | 25 +++++++++++ .../reference/unionTypeReduction.types | 42 +++++++++++++++++++ .../types/union/unionTypeReduction.ts | 16 +++++++ 3 files changed, 83 insertions(+) create mode 100644 tests/baselines/reference/unionTypeReduction.js create mode 100644 tests/baselines/reference/unionTypeReduction.types create mode 100644 tests/cases/conformance/types/union/unionTypeReduction.ts diff --git a/tests/baselines/reference/unionTypeReduction.js b/tests/baselines/reference/unionTypeReduction.js new file mode 100644 index 00000000000..1c914489ecc --- /dev/null +++ b/tests/baselines/reference/unionTypeReduction.js @@ -0,0 +1,25 @@ +//// [unionTypeReduction.ts] +interface I2 { + (): number; + (q): boolean; +} + +interface I3 { + (): number; +} + +var i2: I2, i3: I3; + +var e1: I2 | I3; +var e2 = i2 || i3; // Type of e2 immediately reduced to I3 + +var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature +var r2 = e2(); + + +//// [unionTypeReduction.js] +var i2, i3; +var e1; +var e2 = i2 || i3; // Type of e2 immediately reduced to I3 +var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature +var r2 = e2(); diff --git a/tests/baselines/reference/unionTypeReduction.types b/tests/baselines/reference/unionTypeReduction.types new file mode 100644 index 00000000000..073d690162a --- /dev/null +++ b/tests/baselines/reference/unionTypeReduction.types @@ -0,0 +1,42 @@ +=== tests/cases/conformance/types/union/unionTypeReduction.ts === +interface I2 { +>I2 : I2 + + (): number; + (q): boolean; +>q : any +} + +interface I3 { +>I3 : I3 + + (): number; +} + +var i2: I2, i3: I3; +>i2 : I2 +>I2 : I2 +>i3 : I3 +>I3 : I3 + +var e1: I2 | I3; +>e1 : I2 | I3 +>I2 : I2 +>I3 : I3 + +var e2 = i2 || i3; // Type of e2 immediately reduced to I3 +>e2 : I3 +>i2 || i3 : I3 +>i2 : I2 +>i3 : I3 + +var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature +>r1 : number +>e1() : number +>e1 : I2 | I3 + +var r2 = e2(); +>r2 : number +>e2() : number +>e2 : I3 + diff --git a/tests/cases/conformance/types/union/unionTypeReduction.ts b/tests/cases/conformance/types/union/unionTypeReduction.ts new file mode 100644 index 00000000000..8bc3d1cdc8c --- /dev/null +++ b/tests/cases/conformance/types/union/unionTypeReduction.ts @@ -0,0 +1,16 @@ +interface I2 { + (): number; + (q): boolean; +} + +interface I3 { + (): number; +} + +var i2: I2, i3: I3; + +var e1: I2 | I3; +var e2 = i2 || i3; // Type of e2 immediately reduced to I3 + +var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature +var r2 = e2(); From 56e0fb0b35e684d0c2db84669269c8fd4d6d464f Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Apr 2015 10:01:11 -0700 Subject: [PATCH 08/11] Addressing CR feedback --- src/compiler/checker.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f9815a22b8c..e1f0a53ca85 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2998,7 +2998,9 @@ module ts { } if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) { let symbol = getPropertyOfObjectType(globalFunctionType, name); - if (symbol) return symbol; + if (symbol) { + return symbol; + } } return getPropertyOfObjectType(globalObjectType, name); } @@ -3580,6 +3582,9 @@ module ts { } } + // The noSubtypeReduction flag is there because it isn't possible to always do subtype reduction. The flag + // is true when creating a union type from a type node and when instantiating a union type. In both of those + // cases subtype reduction has to be deferred to properly support recursive union types. function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type { if (types.length === 0) { return emptyObjectType; From f33acf8ba47d27ab125e0005ef454c9468fc2081 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Apr 2015 14:18:57 -0700 Subject: [PATCH 09/11] Accepting new baselines --- .../reference/unionTypeReduction.types | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/baselines/reference/unionTypeReduction.types b/tests/baselines/reference/unionTypeReduction.types index 073d690162a..e4dffff8174 100644 --- a/tests/baselines/reference/unionTypeReduction.types +++ b/tests/baselines/reference/unionTypeReduction.types @@ -1,42 +1,42 @@ === tests/cases/conformance/types/union/unionTypeReduction.ts === interface I2 { ->I2 : I2 +>I2 : I2, Symbol(I2, Decl(unionTypeReduction.ts, 0, 0)) (): number; (q): boolean; ->q : any +>q : any, Symbol(q, Decl(unionTypeReduction.ts, 2, 5)) } interface I3 { ->I3 : I3 +>I3 : I3, Symbol(I3, Decl(unionTypeReduction.ts, 3, 1)) (): number; } var i2: I2, i3: I3; ->i2 : I2 ->I2 : I2 ->i3 : I3 ->I3 : I3 +>i2 : I2, Symbol(i2, Decl(unionTypeReduction.ts, 9, 3)) +>I2 : I2, Symbol(I2, Decl(unionTypeReduction.ts, 0, 0)) +>i3 : I3, Symbol(i3, Decl(unionTypeReduction.ts, 9, 11)) +>I3 : I3, Symbol(I3, Decl(unionTypeReduction.ts, 3, 1)) var e1: I2 | I3; ->e1 : I2 | I3 ->I2 : I2 ->I3 : I3 +>e1 : I2 | I3, Symbol(e1, Decl(unionTypeReduction.ts, 11, 3)) +>I2 : I2, Symbol(I2, Decl(unionTypeReduction.ts, 0, 0)) +>I3 : I3, Symbol(I3, Decl(unionTypeReduction.ts, 3, 1)) var e2 = i2 || i3; // Type of e2 immediately reduced to I3 ->e2 : I3 +>e2 : I3, Symbol(e2, Decl(unionTypeReduction.ts, 12, 3)) >i2 || i3 : I3 ->i2 : I2 ->i3 : I3 +>i2 : I2, Symbol(i2, Decl(unionTypeReduction.ts, 9, 3)) +>i3 : I3, Symbol(i3, Decl(unionTypeReduction.ts, 9, 11)) var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature ->r1 : number +>r1 : number, Symbol(r1, Decl(unionTypeReduction.ts, 14, 3)) >e1() : number ->e1 : I2 | I3 +>e1 : I2 | I3, Symbol(e1, Decl(unionTypeReduction.ts, 11, 3)) var r2 = e2(); ->r2 : number +>r2 : number, Symbol(r2, Decl(unionTypeReduction.ts, 15, 3)) >e2() : number ->e2 : I3 +>e2 : I3, Symbol(e2, Decl(unionTypeReduction.ts, 12, 3)) From 9a2846ef72e7d9d14945609a3009315e1f9cee20 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Apr 2015 14:51:08 -0700 Subject: [PATCH 10/11] Addressing CR feedback --- src/compiler/checker.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3f4a5b83ac4..e9430a058f8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3584,7 +3584,8 @@ module ts { // The noSubtypeReduction flag is there because it isn't possible to always do subtype reduction. The flag // is true when creating a union type from a type node and when instantiating a union type. In both of those - // cases subtype reduction has to be deferred to properly support recursive union types. + // cases subtype reduction has to be deferred to properly support recursive union types. For example, a + // type alias of the form "type Item = string | (() => Item)" cannot be reduced during its declaration. function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type { if (types.length === 0) { return emptyObjectType; @@ -3615,8 +3616,9 @@ module ts { } function getReducedTypeOfUnionType(type: UnionType): Type { + // If union type was created without subtype reduction, perform the deferred reduction now if (!type.reducedType) { - type.reducedType = getUnionType(type.types); + type.reducedType = getUnionType(type.types, /*noSubtypeReduction*/ false); } return type.reducedType; } From 4783d9f252dfdd208acd8a140ed809b9cc4601ae Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 14 Apr 2015 16:05:03 -0700 Subject: [PATCH 11/11] Move asKeyword into correct section --- src/compiler/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 43c210331a5..f03122d21b6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -121,7 +121,6 @@ module ts { WhileKeyword, WithKeyword, // Strict mode reserved words - AsKeyword, ImplementsKeyword, InterfaceKeyword, LetKeyword, @@ -132,6 +131,7 @@ module ts { StaticKeyword, YieldKeyword, // Contextual keywords + AsKeyword, AnyKeyword, BooleanKeyword, ConstructorKeyword,