PY-21474 Fixed: Type checking confused by None default argument

PyTypeAssertionEvaluator: Mark reference which is used as condition in PyConditionalExpression as non-None
This commit is contained in:
Semyon Proshev
2016-11-25 19:10:02 +03:00
parent 54a5e386f4
commit a9ecefe927
3 changed files with 23 additions and 7 deletions
@@ -83,7 +83,7 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
@Override
public void visitPyReferenceExpression(final PyReferenceExpression node) {
if (node.getParent() instanceof PyIfPart) {
if (isUnderIf(node)) {
pushAssertion(node, !myPositive, context -> PyNoneType.INSTANCE);
return;
}
@@ -195,6 +195,12 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
myStack.push(new Assertion(target, typeCallback));
}
private static boolean isUnderIf(@NotNull PyReferenceExpression node) {
final PsiElement parent = node.getParent();
return parent instanceof PyIfPart ||
parent instanceof PyConditionalExpression && node == ((PyConditionalExpression)parent).getCondition();
}
static class Assertion {
private final PyReferenceExpression element;
private InstructionTypeCallback myFunction;
@@ -8,9 +8,9 @@
7(8) WRITE ACCESS: c
8(9) element: PyAssignmentStatement
9(10) element: PyConditionalExpression
10(11,12) READ ACCESS: c
11(13) READ ACCESS: x
12(13) READ ACCESS: y
13(14) WRITE ACCESS: z
14() element: null
10(11,13) READ ACCESS: c
11(12) ASSERTTYPE ACCESS: c
12(14) READ ACCESS: x
13(14) READ ACCESS: y
14(15) WRITE ACCESS: z
15() element: null
@@ -1504,6 +1504,16 @@ public class PyTypeTest extends PyTestCase {
"expr = foo(a=1, b=\"2\")");
}
// PY-21474
public void testReassigningOptionalListWithDefaultValue() {
doTest("Union[List[str], list]",
"def x(things):\n" +
" \"\"\"\n" +
" :type things: None | list[str]\n" +
" \"\"\"\n" +
" expr = things if things else []");
}
private static List<TypeEvalContext> getTypeEvalContexts(@NotNull PyExpression element) {
return ImmutableList.of(TypeEvalContext.codeAnalysis(element.getProject(), element.getContainingFile()).withTracing(),
TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()).withTracing());