Fix getTypeOfSymbolAtLocation to handle hypothetical lookups

This commit is contained in:
Anders Hejlsberg 2016-02-27 18:12:40 -08:00
parent 3d7631dbe8
commit 82169ce7eb
2 changed files with 35 additions and 4 deletions

View File

@ -6863,7 +6863,19 @@ namespace ts {
// EXPRESSION TYPE CHECKING
function createTransientIdentifier(symbol: Symbol, location: Node): Identifier {
let result = <TransientIdentifier>createNode(SyntaxKind.Identifier);
result.text = symbol.name;
result.resolvedSymbol = symbol;
result.parent = location;
result.id = -1;
return result;
}
function getResolvedSymbol(node: Identifier): Symbol {
if (node.id === -1) {
return (<TransientIdentifier>node).resolvedSymbol;
}
const links = getNodeLinks(node);
if (!links.resolvedSymbol) {
links.resolvedSymbol = !nodeIsMissing(node) && resolveName(node, node.text, SymbolFlags.Value | SymbolFlags.ExportValue, Diagnostics.Cannot_find_name_0, node) || unknownSymbol;
@ -7356,11 +7368,25 @@ namespace ts {
function getTypeOfSymbolAtLocation(symbol: Symbol, location: Node) {
// The language service will always care about the narrowed type of a symbol, because that is
// the type the language says the symbol should have.
let type = getTypeOfSymbol(symbol);
if (location.kind === SyntaxKind.Identifier && isExpression(location) && getResolvedSymbol(<Identifier>location) === symbol) {
type = getNarrowedTypeOfReference(type, <Identifier>location);
const type = getTypeOfSymbol(symbol);
if (location.kind === SyntaxKind.Identifier) {
if (isRightSideOfQualifiedNameOrPropertyAccess(location)) {
location = location.parent;
}
// If location is an identifier or property access that references the given
// symbol, use the location as the reference with respect to which we narrow.
if (isExpression(location)) {
checkExpression(<Expression>location);
if (getNodeLinks(location).resolvedSymbol === symbol) {
return getNarrowedTypeOfReference(type, <IdentifierOrPropertyAccess>location);
}
}
}
return type;
// The location isn't a reference to the given symbol, meaning we're being asked
// a hypothetical question of what type the symbol would have if there was a reference
// to it at the given location. To answer that question we manufacture a transient
// identifier at the location and narrow with respect to that identifier.
return getNarrowedTypeOfReference(type, createTransientIdentifier(symbol, location));
}
function skipParenthesizedNodes(expression: Expression): Expression {

View File

@ -476,6 +476,11 @@ namespace ts {
originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later
}
// Transient identifier node (marked by id === -1)
export interface TransientIdentifier extends Identifier {
resolvedSymbol: Symbol;
}
// @kind(SyntaxKind.QualifiedName)
export interface QualifiedName extends Node {
// Must have same layout as PropertyAccess