Skip to content

Commit 2792614

Browse files
committed
Improved circularity detection for types
1 parent 8600fef commit 2792614

File tree

1 file changed

+88
-65
lines changed

1 file changed

+88
-65
lines changed

src/compiler/checker.ts

Lines changed: 88 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ module ts {
9393
let emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
9494
let anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
9595
let noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
96-
96+
9797
let anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, false, false);
9898
let unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, false, false);
9999

@@ -118,14 +118,18 @@ module ts {
118118
let getGlobalParameterDecoratorType: () => ObjectType;
119119
let getGlobalPropertyDecoratorType: () => ObjectType;
120120
let getGlobalMethodDecoratorType: () => ObjectType;
121-
121+
122122
let tupleTypes: Map<TupleType> = {};
123123
let unionTypes: Map<UnionType> = {};
124124
let stringLiteralTypes: Map<StringLiteralType> = {};
125125
let emitExtends = false;
126126
let emitDecorate = false;
127127
let emitParam = false;
128128

129+
let resolutionTargets: Object[] = [];
130+
let resolutionResults: boolean[] = [];
131+
let resolutionCount = 0;
132+
129133
let mergedSymbols: Symbol[] = [];
130134
let symbolLinks: SymbolLinks[] = [];
131135
let nodeLinks: NodeLinks[] = [];
@@ -1980,7 +1984,7 @@ module ts {
19801984
}
19811985
}
19821986

1983-
function collectLinkedAliases(node: Identifier): Node[]{
1987+
function collectLinkedAliases(node: Identifier): Node[] {
19841988
var exportSymbol: Symbol;
19851989
if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) {
19861990
exportSymbol = resolveName(node.parent, node.text, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, Diagnostics.Cannot_find_name_0, node);
@@ -2014,6 +2018,34 @@ module ts {
20142018
}
20152019
}
20162020

2021+
// Push an entry on the type resolution stack. If an entry with the given target is not already on the stack,
2022+
// a new entry with that target and an associated result value of true is pushed on the stack, and the value
2023+
// true is returned. Otherwise, a circularity has occurred and the result values of the existing entry and
2024+
// all entries pushed after it are changed to false, and the value false is returned. The target object has
2025+
// no significance other than to provide a unique identity for a particular type resolution result.
2026+
function pushTypeResolution(target: Object): boolean {
2027+
for (let i = 0; i < resolutionCount; i++) {
2028+
if (resolutionTargets[i] === target) {
2029+
do {
2030+
resolutionResults[i++] = false;
2031+
}
2032+
while (i < resolutionCount);
2033+
return false;
2034+
}
2035+
}
2036+
resolutionTargets[resolutionCount] = target;
2037+
resolutionResults[resolutionCount] = true;
2038+
resolutionCount++;
2039+
return true;
2040+
}
2041+
2042+
// Pop an entry from the type resolution stack and return its associated result value. The result value will
2043+
// be true if no circularities were detected, or false if a circularity was found.
2044+
function popTypeResolution(): boolean {
2045+
resolutionTargets[--resolutionCount] = undefined;
2046+
return resolutionResults[resolutionCount];
2047+
}
2048+
20172049
function getRootDeclaration(node: Node): Node {
20182050
while (node.kind === SyntaxKind.BindingElement) {
20192051
node = node.parent.parent;
@@ -2271,27 +2303,27 @@ module ts {
22712303
return links.type = checkExpression((<ExportAssignment>declaration).expression);
22722304
}
22732305
// Handle variable, parameter or property
2274-
links.type = resolvingType;
2275-
let type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true);
2276-
if (links.type === resolvingType) {
2277-
links.type = type;
2278-
}
2279-
}
2280-
else if (links.type === resolvingType) {
2281-
if ((<VariableLikeDeclaration>symbol.valueDeclaration).type) {
2282-
// Variable has type annotation that circularly references the variable itself
2283-
links.type = unknownType;
2284-
error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation,
2285-
symbolToString(symbol));
2306+
if (!pushTypeResolution(symbol)) {
2307+
return unknownType;
22862308
}
2287-
else {
2288-
// Variable has initializer that circularly references the variable itself
2289-
links.type = anyType;
2290-
if (compilerOptions.noImplicitAny) {
2291-
error(symbol.valueDeclaration, Diagnostics._0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer,
2309+
let type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true);
2310+
if (!popTypeResolution()) {
2311+
if ((<VariableLikeDeclaration>symbol.valueDeclaration).type) {
2312+
// Variable has type annotation that circularly references the variable itself
2313+
type = unknownType;
2314+
error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation,
22922315
symbolToString(symbol));
22932316
}
2317+
else {
2318+
// Variable has initializer that circularly references the variable itself
2319+
type = anyType;
2320+
if (compilerOptions.noImplicitAny) {
2321+
error(symbol.valueDeclaration, Diagnostics._0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer,
2322+
symbolToString(symbol));
2323+
}
2324+
}
22942325
}
2326+
links.type = type;
22952327
}
22962328
return links.type;
22972329
}
@@ -2315,19 +2347,13 @@ module ts {
23152347

23162348
function getTypeOfAccessors(symbol: Symbol): Type {
23172349
let links = getSymbolLinks(symbol);
2318-
checkAndStoreTypeOfAccessors(symbol, links);
2319-
return links.type;
2320-
}
2321-
2322-
function checkAndStoreTypeOfAccessors(symbol: Symbol, links?: SymbolLinks) {
2323-
links = links || getSymbolLinks(symbol);
23242350
if (!links.type) {
2325-
links.type = resolvingType;
2351+
if (!pushTypeResolution(symbol)) {
2352+
return unknownType;
2353+
}
23262354
let getter = <AccessorDeclaration>getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
23272355
let setter = <AccessorDeclaration>getDeclarationOfKind(symbol, SyntaxKind.SetAccessor);
2328-
23292356
let type: Type;
2330-
23312357
// First try to see if the user specified a return type on the get-accessor.
23322358
let getterReturnType = getAnnotatedAccessorType(getter);
23332359
if (getterReturnType) {
@@ -2349,23 +2375,20 @@ module ts {
23492375
if (compilerOptions.noImplicitAny) {
23502376
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbolToString(symbol));
23512377
}
2352-
23532378
type = anyType;
23542379
}
23552380
}
23562381
}
2357-
2358-
if (links.type === resolvingType) {
2359-
links.type = type;
2360-
}
2361-
}
2362-
else if (links.type === resolvingType) {
2363-
links.type = anyType;
2364-
if (compilerOptions.noImplicitAny) {
2365-
let getter = <AccessorDeclaration>getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
2366-
error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol));
2382+
if (!popTypeResolution()) {
2383+
type = anyType;
2384+
if (compilerOptions.noImplicitAny) {
2385+
let getter = <AccessorDeclaration>getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
2386+
error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol));
2387+
}
23672388
}
2389+
links.type = type;
23682390
}
2391+
return links.type;
23692392
}
23702393

23712394
function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
@@ -2458,7 +2481,7 @@ module ts {
24582481
return result;
24592482
}
24602483

2461-
function getBaseTypes(type: InterfaceType): ObjectType[]{
2484+
function getBaseTypes(type: InterfaceType): ObjectType[] {
24622485
let typeWithBaseTypes = <InterfaceTypeWithBaseTypes>type;
24632486
if (!typeWithBaseTypes.baseTypes) {
24642487
if (type.symbol.flags & SymbolFlags.Class) {
@@ -2543,17 +2566,18 @@ module ts {
25432566
function getDeclaredTypeOfTypeAlias(symbol: Symbol): Type {
25442567
let links = getSymbolLinks(symbol);
25452568
if (!links.declaredType) {
2546-
links.declaredType = resolvingType;
2569+
// Note that we use the links object as the target here because the symbol object is used as the unique
2570+
// identity for resolution of the 'type' property in SymbolLinks.
2571+
if (!pushTypeResolution(links)) {
2572+
return unknownType;
2573+
}
25472574
let declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
25482575
let type = getTypeFromTypeNode(declaration.type);
2549-
if (links.declaredType === resolvingType) {
2550-
links.declaredType = type;
2576+
if (!popTypeResolution()) {
2577+
type = unknownType;
2578+
error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol));
25512579
}
2552-
}
2553-
else if (links.declaredType === resolvingType) {
2554-
links.declaredType = unknownType;
2555-
let declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
2556-
error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol));
2580+
links.declaredType = type;
25572581
}
25582582
return links.declaredType;
25592583
}
@@ -3157,7 +3181,9 @@ module ts {
31573181

31583182
function getReturnTypeOfSignature(signature: Signature): Type {
31593183
if (!signature.resolvedReturnType) {
3160-
signature.resolvedReturnType = resolvingType;
3184+
if (!pushTypeResolution(signature)) {
3185+
return unknownType;
3186+
}
31613187
let type: Type;
31623188
if (signature.target) {
31633189
type = instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper);
@@ -3168,21 +3194,19 @@ module ts {
31683194
else {
31693195
type = getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration);
31703196
}
3171-
if (signature.resolvedReturnType === resolvingType) {
3172-
signature.resolvedReturnType = type;
3173-
}
3174-
}
3175-
else if (signature.resolvedReturnType === resolvingType) {
3176-
signature.resolvedReturnType = anyType;
3177-
if (compilerOptions.noImplicitAny) {
3178-
let declaration = <Declaration>signature.declaration;
3179-
if (declaration.name) {
3180-
error(declaration.name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, declarationNameToString(declaration.name));
3181-
}
3182-
else {
3183-
error(declaration, Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions);
3197+
if (!popTypeResolution()) {
3198+
type = anyType;
3199+
if (compilerOptions.noImplicitAny) {
3200+
let declaration = <Declaration>signature.declaration;
3201+
if (declaration.name) {
3202+
error(declaration.name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, declarationNameToString(declaration.name));
3203+
}
3204+
else {
3205+
error(declaration, Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions);
3206+
}
31843207
}
31853208
}
3209+
signature.resolvedReturnType = type;
31863210
}
31873211
return signature.resolvedReturnType;
31883212
}
@@ -8366,8 +8390,7 @@ module ts {
83668390
}
83678391
}
83688392
}
8369-
8370-
checkAndStoreTypeOfAccessors(getSymbolOfNode(node));
8393+
getTypeOfAccessors(getSymbolOfNode(node));
83718394
}
83728395

83738396
checkFunctionLikeDeclaration(node);

0 commit comments

Comments
 (0)