Skip to content

Commit 2da47e8

Browse files
committed
Merge pull request #3919 from Microsoft/remove_resolveLocation
Remove resolveLocation from the checker
2 parents 96b02a8 + fffe6c5 commit 2da47e8

File tree

2 files changed

+87
-78
lines changed

2 files changed

+87
-78
lines changed

src/compiler/checker.ts

+84-75
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ namespace ts {
5959
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
6060
getDiagnostics,
6161
getGlobalDiagnostics,
62-
getTypeOfSymbolAtLocation,
62+
63+
// The language service will always care about the narrowed type of a symbol, because that is
64+
// the type the language says the symbol should have.
65+
getTypeOfSymbolAtLocation: getNarrowedTypeOfSymbol,
6366
getDeclaredTypeOfSymbol,
6467
getPropertiesOfType,
6568
getPropertyOfType,
@@ -69,7 +72,7 @@ namespace ts {
6972
getSymbolsInScope,
7073
getSymbolAtLocation,
7174
getShorthandAssignmentValueSymbol,
72-
getTypeAtLocation,
75+
getTypeAtLocation: getTypeOfNode,
7376
typeToString,
7477
getSymbolDisplayBuilder,
7578
symbolToString,
@@ -159,8 +162,9 @@ namespace ts {
159162
let emitAwaiter = false;
160163
let emitGenerator = false;
161164

162-
let resolutionTargets: Object[] = [];
165+
let resolutionTargets: TypeSystemEntity[] = [];
163166
let resolutionResults: boolean[] = [];
167+
let resolutionPropertyNames: TypeSystemPropertyName[] = [];
164168

165169
let mergedSymbols: Symbol[] = [];
166170
let symbolLinks: SymbolLinks[] = [];
@@ -201,6 +205,15 @@ namespace ts {
201205
let assignableRelation: Map<RelationComparisonResult> = {};
202206
let identityRelation: Map<RelationComparisonResult> = {};
203207

208+
type TypeSystemEntity = Symbol | Type | Signature;
209+
210+
const enum TypeSystemPropertyName {
211+
Type,
212+
ResolvedBaseConstructorType,
213+
DeclaredType,
214+
ResolvedReturnType
215+
}
216+
204217
initializeTypeChecker();
205218

206219
return checker;
@@ -2177,35 +2190,69 @@ namespace ts {
21772190
}
21782191
}
21792192

2180-
// Push an entry on the type resolution stack. If an entry with the given target is not already on the stack,
2181-
// a new entry with that target and an associated result value of true is pushed on the stack, and the value
2182-
// true is returned. Otherwise, a circularity has occurred and the result values of the existing entry and
2183-
// all entries pushed after it are changed to false, and the value false is returned. The target object provides
2184-
// a unique identity for a particular type resolution result: Symbol instances are used to track resolution of
2185-
// SymbolLinks.type, SymbolLinks instances are used to track resolution of SymbolLinks.declaredType, and
2186-
// Signature instances are used to track resolution of Signature.resolvedReturnType.
2187-
function pushTypeResolution(target: Object): boolean {
2188-
let i = 0;
2189-
let count = resolutionTargets.length;
2190-
while (i < count && resolutionTargets[i] !== target) {
2191-
i++;
2192-
}
2193-
if (i < count) {
2194-
do {
2195-
resolutionResults[i++] = false;
2193+
/**
2194+
* Push an entry on the type resolution stack. If an entry with the given target and the given property name
2195+
* is already on the stack, and no entries in between already have a type, then a circularity has occurred.
2196+
* In this case, the result values of the existing entry and all entries pushed after it are changed to false,
2197+
* and the value false is returned. Otherwise, the new entry is just pushed onto the stack, and true is returned.
2198+
* In order to see if the same query has already been done before, the target object and the propertyName both
2199+
* must match the one passed in.
2200+
*
2201+
* @param target The symbol, type, or signature whose type is being queried
2202+
* @param propertyName The property name that should be used to query the target for its type
2203+
*/
2204+
function pushTypeResolution(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): boolean {
2205+
let resolutionCycleStartIndex = findResolutionCycleStartIndex(target, propertyName);
2206+
if (resolutionCycleStartIndex >= 0) {
2207+
// A cycle was found
2208+
let { length } = resolutionTargets;
2209+
for (let i = resolutionCycleStartIndex; i < length; i++) {
2210+
resolutionResults[i] = false;
21962211
}
2197-
while (i < count);
21982212
return false;
21992213
}
22002214
resolutionTargets.push(target);
22012215
resolutionResults.push(true);
2216+
resolutionPropertyNames.push(propertyName);
22022217
return true;
22032218
}
22042219

2220+
function findResolutionCycleStartIndex(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): number {
2221+
for (let i = resolutionTargets.length - 1; i >= 0; i--) {
2222+
if (hasType(resolutionTargets[i], resolutionPropertyNames[i])) {
2223+
return -1;
2224+
}
2225+
if (resolutionTargets[i] === target && resolutionPropertyNames[i] === propertyName) {
2226+
return i;
2227+
}
2228+
}
2229+
2230+
return -1;
2231+
}
2232+
2233+
function hasType(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): Type {
2234+
if (propertyName === TypeSystemPropertyName.Type) {
2235+
return getSymbolLinks(<Symbol>target).type;
2236+
}
2237+
if (propertyName === TypeSystemPropertyName.DeclaredType) {
2238+
return getSymbolLinks(<Symbol>target).declaredType;
2239+
}
2240+
if (propertyName === TypeSystemPropertyName.ResolvedBaseConstructorType) {
2241+
Debug.assert(!!((<Type>target).flags & TypeFlags.Class));
2242+
return (<InterfaceType>target).resolvedBaseConstructorType;
2243+
}
2244+
if (propertyName === TypeSystemPropertyName.ResolvedReturnType) {
2245+
return (<Signature>target).resolvedReturnType;
2246+
}
2247+
2248+
Debug.fail("Unhandled TypeSystemPropertyName " + propertyName);
2249+
}
2250+
22052251
// Pop an entry from the type resolution stack and return its associated result value. The result value will
22062252
// be true if no circularities were detected, or false if a circularity was found.
22072253
function popTypeResolution(): boolean {
22082254
resolutionTargets.pop();
2255+
resolutionPropertyNames.pop();
22092256
return resolutionResults.pop();
22102257
}
22112258

@@ -2468,7 +2515,7 @@ namespace ts {
24682515
return links.type = checkExpression((<ExportAssignment>declaration).expression);
24692516
}
24702517
// Handle variable, parameter or property
2471-
if (!pushTypeResolution(symbol)) {
2518+
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
24722519
return unknownType;
24732520
}
24742521
let type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true);
@@ -2509,7 +2556,7 @@ namespace ts {
25092556
function getTypeOfAccessors(symbol: Symbol): Type {
25102557
let links = getSymbolLinks(symbol);
25112558
if (!links.type) {
2512-
if (!pushTypeResolution(symbol)) {
2559+
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
25132560
return unknownType;
25142561
}
25152562
let getter = <AccessorDeclaration>getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
@@ -2725,7 +2772,7 @@ namespace ts {
27252772
if (!baseTypeNode) {
27262773
return type.resolvedBaseConstructorType = undefinedType;
27272774
}
2728-
if (!pushTypeResolution(type)) {
2775+
if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseConstructorType)) {
27292776
return unknownType;
27302777
}
27312778
let baseConstructorType = checkExpression(baseTypeNode.expression);
@@ -2852,7 +2899,7 @@ namespace ts {
28522899
if (!links.declaredType) {
28532900
// Note that we use the links object as the target here because the symbol object is used as the unique
28542901
// identity for resolution of the 'type' property in SymbolLinks.
2855-
if (!pushTypeResolution(links)) {
2902+
if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) {
28562903
return unknownType;
28572904
}
28582905
let declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
@@ -3539,7 +3586,7 @@ namespace ts {
35393586

35403587
function getReturnTypeOfSignature(signature: Signature): Type {
35413588
if (!signature.resolvedReturnType) {
3542-
if (!pushTypeResolution(signature)) {
3589+
if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) {
35433590
return unknownType;
35443591
}
35453592
let type: Type;
@@ -4184,7 +4231,7 @@ namespace ts {
41844231
// Callers should first ensure this by calling isTypeNode
41854232
case SyntaxKind.Identifier:
41864233
case SyntaxKind.QualifiedName:
4187-
let symbol = getSymbolInfo(node);
4234+
let symbol = getSymbolAtLocation(node);
41884235
return symbol && getDeclaredTypeOfSymbol(symbol);
41894236
default:
41904237
return unknownType;
@@ -5841,47 +5888,6 @@ namespace ts {
58415888
}
58425889
}
58435890

5844-
function resolveLocation(node: Node) {
5845-
// Resolve location from top down towards node if it is a context sensitive expression
5846-
// That helps in making sure not assigning types as any when resolved out of order
5847-
let containerNodes: Node[] = [];
5848-
for (let parent = node.parent; parent; parent = parent.parent) {
5849-
if ((isExpression(parent) || isObjectLiteralMethod(node)) &&
5850-
isContextSensitive(<Expression>parent)) {
5851-
containerNodes.unshift(parent);
5852-
}
5853-
}
5854-
5855-
ts.forEach(containerNodes, node => { getTypeOfNode(node); });
5856-
}
5857-
5858-
function getSymbolAtLocation(node: Node): Symbol {
5859-
resolveLocation(node);
5860-
return getSymbolInfo(node);
5861-
}
5862-
5863-
function getTypeAtLocation(node: Node): Type {
5864-
resolveLocation(node);
5865-
return getTypeOfNode(node);
5866-
}
5867-
5868-
function getTypeOfSymbolAtLocation(symbol: Symbol, node: Node): Type {
5869-
resolveLocation(node);
5870-
// Get the narrowed type of symbol at given location instead of just getting
5871-
// the type of the symbol.
5872-
// eg.
5873-
// function foo(a: string | number) {
5874-
// if (typeof a === "string") {
5875-
// a/**/
5876-
// }
5877-
// }
5878-
// getTypeOfSymbol for a would return type of parameter symbol string | number
5879-
// Unless we provide location /**/, checker wouldn't know how to narrow the type
5880-
// By using getNarrowedTypeOfSymbol would return string since it would be able to narrow
5881-
// it by typeguard in the if true condition
5882-
return getNarrowedTypeOfSymbol(symbol, node);
5883-
}
5884-
58855891
// Get the narrowed type of a given symbol at a given location
58865892
function getNarrowedTypeOfSymbol(symbol: Symbol, node: Node) {
58875893
let type = getTypeOfSymbol(symbol);
@@ -8510,6 +8516,9 @@ namespace ts {
85108516
if (!produceDiagnostics) {
85118517
for (let candidate of candidates) {
85128518
if (hasCorrectArity(node, args, candidate)) {
8519+
if (candidate.typeParameters && typeArguments) {
8520+
candidate = getSignatureInstantiation(candidate, map(typeArguments, getTypeFromTypeNode));
8521+
}
85138522
return candidate;
85148523
}
85158524
}
@@ -10108,7 +10117,7 @@ namespace ts {
1010810117
}
1010910118
else {
1011010119
checkTypeAssignableTo(typePredicate.type,
10111-
getTypeAtLocation(node.parameters[typePredicate.parameterIndex]),
10120+
getTypeOfNode(node.parameters[typePredicate.parameterIndex]),
1011210121
typePredicateNode.type);
1011310122
}
1011410123
}
@@ -13730,7 +13739,7 @@ namespace ts {
1373013739
return undefined;
1373113740
}
1373213741

13733-
function getSymbolInfo(node: Node) {
13742+
function getSymbolAtLocation(node: Node) {
1373413743
if (isInsideWithStatementBody(node)) {
1373513744
// We cannot answer semantic questions within a with block, do not proceed any further
1373613745
return undefined;
@@ -13750,7 +13759,7 @@ namespace ts {
1375013759
else if (node.parent.kind === SyntaxKind.BindingElement &&
1375113760
node.parent.parent.kind === SyntaxKind.ObjectBindingPattern &&
1375213761
node === (<BindingElement>node.parent).propertyName) {
13753-
let typeOfPattern = getTypeAtLocation(node.parent.parent);
13762+
let typeOfPattern = getTypeOfNode(node.parent.parent);
1375413763
let propertyDeclaration = typeOfPattern && getPropertyOfType(typeOfPattern, (<Identifier>node).text);
1375513764

1375613765
if (propertyDeclaration) {
@@ -13833,24 +13842,24 @@ namespace ts {
1383313842
}
1383413843

1383513844
if (isTypeDeclaration(node)) {
13836-
// In this case, we call getSymbolOfNode instead of getSymbolInfo because it is a declaration
13845+
// In this case, we call getSymbolOfNode instead of getSymbolAtLocation because it is a declaration
1383713846
let symbol = getSymbolOfNode(node);
1383813847
return getDeclaredTypeOfSymbol(symbol);
1383913848
}
1384013849

1384113850
if (isTypeDeclarationName(node)) {
13842-
let symbol = getSymbolInfo(node);
13851+
let symbol = getSymbolAtLocation(node);
1384313852
return symbol && getDeclaredTypeOfSymbol(symbol);
1384413853
}
1384513854

1384613855
if (isDeclaration(node)) {
13847-
// In this case, we call getSymbolOfNode instead of getSymbolInfo because it is a declaration
13856+
// In this case, we call getSymbolOfNode instead of getSymbolAtLocation because it is a declaration
1384813857
let symbol = getSymbolOfNode(node);
1384913858
return getTypeOfSymbol(symbol);
1385013859
}
1385113860

1385213861
if (isDeclarationName(node)) {
13853-
let symbol = getSymbolInfo(node);
13862+
let symbol = getSymbolAtLocation(node);
1385413863
return symbol && getTypeOfSymbol(symbol);
1385513864
}
1385613865

@@ -13859,7 +13868,7 @@ namespace ts {
1385913868
}
1386013869

1386113870
if (isInRightSideOfImportOrExportAssignment(<Identifier>node)) {
13862-
let symbol = getSymbolInfo(node);
13871+
let symbol = getSymbolAtLocation(node);
1386313872
let declaredType = symbol && getDeclaredTypeOfSymbol(symbol);
1386413873
return declaredType !== unknownType ? declaredType : getTypeOfSymbol(symbol);
1386513874
}

tests/cases/fourslash/genericCombinators2.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ goTo.marker('15');
110110
verify.quickInfoIs('var r4a: Collection<number, any>');
111111

112112
goTo.marker('17');
113-
verify.quickInfoIs('var r5a: Collection<T, V>'); // This is actually due to an error because toFixed does not return a Date
113+
verify.quickInfoIs('var r5a: Collection<number, Date>');
114114

115115
goTo.marker('18');
116116
verify.quickInfoIs('var r5b: Collection<number, Date>');
@@ -122,10 +122,10 @@ goTo.marker('20');
122122
verify.quickInfoIs('var r6b: Collection<Collection<number, number>, Date>');
123123

124124
goTo.marker('21');
125-
verify.quickInfoIs('var r7a: Collection<T, V>'); // This call is an error because y.foo() does not return a string
125+
verify.quickInfoIs('var r7a: Collection<number, string>');
126126

127127
goTo.marker('22');
128-
verify.quickInfoIs('var r7b: Collection<T, V>'); // This call is an error because y.foo() does not return a string
128+
verify.quickInfoIs('var r7b: Collection<number, string>');
129129

130130
goTo.marker('23');
131131
verify.quickInfoIs('var r8a: Collection<number, string>');

0 commit comments

Comments
 (0)