mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-20 04:37:57 +03:00
Simplified function recursion check.
This commit is contained in:
parent
31b6116650
commit
bf2003ad17
@ -287,22 +287,11 @@ interface SymbolResolutionStackEntry {
|
|||||||
partialType?: Type;
|
partialType?: Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TypeResolutionStackEntry {
|
|
||||||
// The name or member access expression being evaluated
|
|
||||||
// within the code flow engine or the function node being
|
|
||||||
// evaluated for its inferred return type.
|
|
||||||
reference: NameNode | MemberAccessNode | FunctionNode;
|
|
||||||
|
|
||||||
// Initially true, it's set to false if a recursion is
|
|
||||||
// detected.
|
|
||||||
isResultValid: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
||||||
let isSpeculativeMode = false;
|
let isSpeculativeMode = false;
|
||||||
const symbolResolutionStack: SymbolResolutionStackEntry[] = [];
|
const symbolResolutionStack: SymbolResolutionStackEntry[] = [];
|
||||||
const typeResolutionStack: TypeResolutionStackEntry[] = [];
|
|
||||||
const isReachableRecursionMap = new Map<number, true>();
|
const isReachableRecursionMap = new Map<number, true>();
|
||||||
|
const functionRecursionMap = new Map<number, true>();
|
||||||
const callIsNoReturnCache = new Map<number, boolean>();
|
const callIsNoReturnCache = new Map<number, boolean>();
|
||||||
const codeFlowAnalyzerCache = new Map<number, CodeFlowAnalyzer>();
|
const codeFlowAnalyzerCache = new Map<number, CodeFlowAnalyzer>();
|
||||||
const typeCache = new Map<number, TypeCacheEntry>();
|
const typeCache = new Map<number, TypeCacheEntry>();
|
||||||
@ -383,28 +372,6 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushTypeResolution(reference: NameNode | MemberAccessNode | FunctionNode) {
|
|
||||||
const index = typeResolutionStack.findIndex(entry => entry.reference === reference);
|
|
||||||
if (index >= 0) {
|
|
||||||
// Mark all of the entries between these two as invalid.
|
|
||||||
for (let i = index + 1; i < typeResolutionStack.length; i++) {
|
|
||||||
typeResolutionStack[i].isResultValid = false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
typeResolutionStack.push({
|
|
||||||
reference,
|
|
||||||
isResultValid: true
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function popTypeResolution(reference: NameNode | MemberAccessNode | FunctionNode) {
|
|
||||||
const poppedNode = typeResolutionStack.pop()!;
|
|
||||||
assert(poppedNode.reference === reference);
|
|
||||||
return poppedNode.isResultValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrapper around getTypeOfExpression for callers who are interested in
|
// Wrapper around getTypeOfExpression for callers who are interested in
|
||||||
// only the type and not the additional information returned in TypeResult.
|
// only the type and not the additional information returned in TypeResult.
|
||||||
function getType(node: ExpressionNode, expectedType?: Type, flags = EvaluatorFlags.None): Type {
|
function getType(node: ExpressionNode, expectedType?: Type, flags = EvaluatorFlags.None): Type {
|
||||||
@ -6026,7 +5993,9 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
return inferredReturnType;
|
return inferredReturnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pushTypeResolution(node)) {
|
if (!functionRecursionMap.has(node.id)) {
|
||||||
|
functionRecursionMap.set(node.id, true);
|
||||||
|
|
||||||
const functionDecl = AnalyzerNodeInfo.getDeclaration(node) as FunctionDeclaration;
|
const functionDecl = AnalyzerNodeInfo.getDeclaration(node) as FunctionDeclaration;
|
||||||
|
|
||||||
// Is it a generator?
|
// Is it a generator?
|
||||||
@ -6108,16 +6077,8 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
// before being returned.
|
// before being returned.
|
||||||
inferredReturnType = removeUnboundFromUnion(inferredReturnType);
|
inferredReturnType = removeUnboundFromUnion(inferredReturnType);
|
||||||
|
|
||||||
if (!popTypeResolution(node)) {
|
|
||||||
addDiagnostic(
|
|
||||||
getFileInfo(node).diagnosticSettings.reportUnknownParameterType,
|
|
||||||
DiagnosticRule.reportUnknownParameterType,
|
|
||||||
`Return type could not be inferred because of recursion`,
|
|
||||||
node.name);
|
|
||||||
inferredReturnType = UnknownType.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
writeTypeCache(node.suite, inferredReturnType);
|
writeTypeCache(node.suite, inferredReturnType);
|
||||||
|
functionRecursionMap.delete(node.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return inferredReturnType;
|
return inferredReturnType;
|
||||||
|
Loading…
Reference in New Issue
Block a user