mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-06 12:57:14 +03:00
Fixed a bug that results in spurious "variable not allowed in type expression" errors when a type alias is used in a loop in both a type expression and a value expression. This addresses #9017. (#9018)
This commit is contained in:
parent
e353c9dec5
commit
c20e613319
@ -401,6 +401,28 @@ export function getCodeFlowEngine(
|
||||
flowNodeTypeCache.cache.delete(flowNode.id);
|
||||
}
|
||||
|
||||
// Cleans any "incomplete unknowns" from the specified set of entries
|
||||
// to compute the final type.
|
||||
function cleanIncompleteUnknownForCacheEntry(cacheEntry: FlowNodeTypeResult): Type | undefined {
|
||||
if (!cacheEntry.type) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!cacheEntry.incompleteSubtypes || cacheEntry.incompleteSubtypes.length === 0) {
|
||||
return cleanIncompleteUnknown(cacheEntry.type);
|
||||
}
|
||||
|
||||
const typesToCombine: Type[] = [];
|
||||
|
||||
cacheEntry.incompleteSubtypes?.forEach((entry) => {
|
||||
if (entry.type && !isIncompleteUnknown(entry.type)) {
|
||||
typesToCombine.push(cleanIncompleteUnknown(entry.type));
|
||||
}
|
||||
});
|
||||
|
||||
return combineTypes(typesToCombine);
|
||||
}
|
||||
|
||||
function evaluateAssignmentFlowNode(flowNode: FlowAssignment): TypeResult | undefined {
|
||||
// For function and class nodes, the reference node is the name
|
||||
// node, but we need to use the parent node (the FunctionNode or ClassNode)
|
||||
@ -456,7 +478,7 @@ export function getCodeFlowEngine(
|
||||
// has changed that may cause the previously-reported incomplete type to change.
|
||||
if (cachedEntry.generationCount === flowIncompleteGeneration) {
|
||||
return FlowNodeTypeResult.create(
|
||||
cachedEntry.type ? cleanIncompleteUnknown(cachedEntry.type) : undefined,
|
||||
cleanIncompleteUnknownForCacheEntry(cachedEntry),
|
||||
/* isIncomplete */ true
|
||||
);
|
||||
}
|
||||
@ -966,7 +988,7 @@ export function getCodeFlowEngine(
|
||||
// that have not been evaluated even once, treat it as incomplete. We clean
|
||||
// any incomplete unknowns from the type here to assist with type convergence.
|
||||
return FlowNodeTypeResult.create(
|
||||
cacheEntry.type ? cleanIncompleteUnknown(cacheEntry.type) : undefined,
|
||||
cleanIncompleteUnknownForCacheEntry(cacheEntry),
|
||||
/* isIncomplete */ true
|
||||
);
|
||||
}
|
||||
|
15
packages/pyright-internal/src/tests/samples/loop50.py
Normal file
15
packages/pyright-internal/src/tests/samples/loop50.py
Normal file
@ -0,0 +1,15 @@
|
||||
# This sample tests the case where a type alias is accessed within
|
||||
# a loop as both an annotation and a value expression.
|
||||
|
||||
from typing import Literal
|
||||
|
||||
|
||||
TA1 = Literal["a", "b"]
|
||||
|
||||
|
||||
def func1(values: list):
|
||||
for value in values:
|
||||
x: TA1 = value["x"]
|
||||
|
||||
if x not in TA1.__args__:
|
||||
raise ValueError()
|
@ -473,6 +473,12 @@ test('Loop49', () => {
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('Loop50', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['loop50.py']);
|
||||
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('ForLoop1', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['forLoop1.py']);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user