@@ -59,7 +59,10 @@ namespace ts {
59
59
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
60
60
getDiagnostics,
61
61
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,
63
66
getDeclaredTypeOfSymbol,
64
67
getPropertiesOfType,
65
68
getPropertyOfType,
@@ -69,7 +72,7 @@ namespace ts {
69
72
getSymbolsInScope,
70
73
getSymbolAtLocation,
71
74
getShorthandAssignmentValueSymbol,
72
- getTypeAtLocation,
75
+ getTypeAtLocation: getTypeOfNode ,
73
76
typeToString,
74
77
getSymbolDisplayBuilder,
75
78
symbolToString,
@@ -159,8 +162,9 @@ namespace ts {
159
162
let emitAwaiter = false;
160
163
let emitGenerator = false;
161
164
162
- let resolutionTargets: Object [] = [];
165
+ let resolutionTargets: TypeSystemEntity [] = [];
163
166
let resolutionResults: boolean[] = [];
167
+ let resolutionPropertyNames: TypeSystemPropertyName[] = [];
164
168
165
169
let mergedSymbols: Symbol[] = [];
166
170
let symbolLinks: SymbolLinks[] = [];
@@ -201,6 +205,15 @@ namespace ts {
201
205
let assignableRelation: Map<RelationComparisonResult> = {};
202
206
let identityRelation: Map<RelationComparisonResult> = {};
203
207
208
+ type TypeSystemEntity = Symbol | Type | Signature;
209
+
210
+ const enum TypeSystemPropertyName {
211
+ Type,
212
+ ResolvedBaseConstructorType,
213
+ DeclaredType,
214
+ ResolvedReturnType
215
+ }
216
+
204
217
initializeTypeChecker();
205
218
206
219
return checker;
@@ -2177,35 +2190,69 @@ namespace ts {
2177
2190
}
2178
2191
}
2179
2192
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;
2196
2211
}
2197
- while (i < count);
2198
2212
return false;
2199
2213
}
2200
2214
resolutionTargets.push(target);
2201
2215
resolutionResults.push(true);
2216
+ resolutionPropertyNames.push(propertyName);
2202
2217
return true;
2203
2218
}
2204
2219
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
+
2205
2251
// Pop an entry from the type resolution stack and return its associated result value. The result value will
2206
2252
// be true if no circularities were detected, or false if a circularity was found.
2207
2253
function popTypeResolution(): boolean {
2208
2254
resolutionTargets.pop();
2255
+ resolutionPropertyNames.pop();
2209
2256
return resolutionResults.pop();
2210
2257
}
2211
2258
@@ -2468,7 +2515,7 @@ namespace ts {
2468
2515
return links.type = checkExpression((<ExportAssignment>declaration).expression);
2469
2516
}
2470
2517
// Handle variable, parameter or property
2471
- if (!pushTypeResolution(symbol)) {
2518
+ if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type )) {
2472
2519
return unknownType;
2473
2520
}
2474
2521
let type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true);
@@ -2509,7 +2556,7 @@ namespace ts {
2509
2556
function getTypeOfAccessors(symbol: Symbol): Type {
2510
2557
let links = getSymbolLinks(symbol);
2511
2558
if (!links.type) {
2512
- if (!pushTypeResolution(symbol)) {
2559
+ if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type )) {
2513
2560
return unknownType;
2514
2561
}
2515
2562
let getter = <AccessorDeclaration>getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
@@ -2725,7 +2772,7 @@ namespace ts {
2725
2772
if (!baseTypeNode) {
2726
2773
return type.resolvedBaseConstructorType = undefinedType;
2727
2774
}
2728
- if (!pushTypeResolution(type)) {
2775
+ if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseConstructorType )) {
2729
2776
return unknownType;
2730
2777
}
2731
2778
let baseConstructorType = checkExpression(baseTypeNode.expression);
@@ -2852,7 +2899,7 @@ namespace ts {
2852
2899
if (!links.declaredType) {
2853
2900
// Note that we use the links object as the target here because the symbol object is used as the unique
2854
2901
// identity for resolution of the 'type' property in SymbolLinks.
2855
- if (!pushTypeResolution(links )) {
2902
+ if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType )) {
2856
2903
return unknownType;
2857
2904
}
2858
2905
let declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
@@ -3539,7 +3586,7 @@ namespace ts {
3539
3586
3540
3587
function getReturnTypeOfSignature(signature: Signature): Type {
3541
3588
if (!signature.resolvedReturnType) {
3542
- if (!pushTypeResolution(signature)) {
3589
+ if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType )) {
3543
3590
return unknownType;
3544
3591
}
3545
3592
let type: Type;
@@ -4184,7 +4231,7 @@ namespace ts {
4184
4231
// Callers should first ensure this by calling isTypeNode
4185
4232
case SyntaxKind.Identifier:
4186
4233
case SyntaxKind.QualifiedName:
4187
- let symbol = getSymbolInfo (node);
4234
+ let symbol = getSymbolAtLocation (node);
4188
4235
return symbol && getDeclaredTypeOfSymbol(symbol);
4189
4236
default:
4190
4237
return unknownType;
@@ -5841,47 +5888,6 @@ namespace ts {
5841
5888
}
5842
5889
}
5843
5890
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
-
5885
5891
// Get the narrowed type of a given symbol at a given location
5886
5892
function getNarrowedTypeOfSymbol(symbol: Symbol, node: Node) {
5887
5893
let type = getTypeOfSymbol(symbol);
@@ -8510,6 +8516,9 @@ namespace ts {
8510
8516
if (!produceDiagnostics) {
8511
8517
for (let candidate of candidates) {
8512
8518
if (hasCorrectArity(node, args, candidate)) {
8519
+ if (candidate.typeParameters && typeArguments) {
8520
+ candidate = getSignatureInstantiation(candidate, map(typeArguments, getTypeFromTypeNode));
8521
+ }
8513
8522
return candidate;
8514
8523
}
8515
8524
}
@@ -10108,7 +10117,7 @@ namespace ts {
10108
10117
}
10109
10118
else {
10110
10119
checkTypeAssignableTo(typePredicate.type,
10111
- getTypeAtLocation (node.parameters[typePredicate.parameterIndex]),
10120
+ getTypeOfNode (node.parameters[typePredicate.parameterIndex]),
10112
10121
typePredicateNode.type);
10113
10122
}
10114
10123
}
@@ -13730,7 +13739,7 @@ namespace ts {
13730
13739
return undefined;
13731
13740
}
13732
13741
13733
- function getSymbolInfo (node: Node) {
13742
+ function getSymbolAtLocation (node: Node) {
13734
13743
if (isInsideWithStatementBody(node)) {
13735
13744
// We cannot answer semantic questions within a with block, do not proceed any further
13736
13745
return undefined;
@@ -13750,7 +13759,7 @@ namespace ts {
13750
13759
else if (node.parent.kind === SyntaxKind.BindingElement &&
13751
13760
node.parent.parent.kind === SyntaxKind.ObjectBindingPattern &&
13752
13761
node === (<BindingElement>node.parent).propertyName) {
13753
- let typeOfPattern = getTypeAtLocation (node.parent.parent);
13762
+ let typeOfPattern = getTypeOfNode (node.parent.parent);
13754
13763
let propertyDeclaration = typeOfPattern && getPropertyOfType(typeOfPattern, (<Identifier>node).text);
13755
13764
13756
13765
if (propertyDeclaration) {
@@ -13833,24 +13842,24 @@ namespace ts {
13833
13842
}
13834
13843
13835
13844
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
13837
13846
let symbol = getSymbolOfNode(node);
13838
13847
return getDeclaredTypeOfSymbol(symbol);
13839
13848
}
13840
13849
13841
13850
if (isTypeDeclarationName(node)) {
13842
- let symbol = getSymbolInfo (node);
13851
+ let symbol = getSymbolAtLocation (node);
13843
13852
return symbol && getDeclaredTypeOfSymbol(symbol);
13844
13853
}
13845
13854
13846
13855
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
13848
13857
let symbol = getSymbolOfNode(node);
13849
13858
return getTypeOfSymbol(symbol);
13850
13859
}
13851
13860
13852
13861
if (isDeclarationName(node)) {
13853
- let symbol = getSymbolInfo (node);
13862
+ let symbol = getSymbolAtLocation (node);
13854
13863
return symbol && getTypeOfSymbol(symbol);
13855
13864
}
13856
13865
@@ -13859,7 +13868,7 @@ namespace ts {
13859
13868
}
13860
13869
13861
13870
if (isInRightSideOfImportOrExportAssignment(<Identifier>node)) {
13862
- let symbol = getSymbolInfo (node);
13871
+ let symbol = getSymbolAtLocation (node);
13863
13872
let declaredType = symbol && getDeclaredTypeOfSymbol(symbol);
13864
13873
return declaredType !== unknownType ? declaredType : getTypeOfSymbol(symbol);
13865
13874
}
0 commit comments