You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor visit_conditional_expr to fix ternary behavior (python#19563)
- Fixespython#18817
- added unit test `testTernaryOperatorWithDefault`
- Fixespython#19561
- added unit tests `testLambdaTernary{, IndirectAttribute,
DoubleIndirectAttribute}`
- Fixespython#19534
- added unit tests `test{List, Set, Dict}ComprehensionTernary`
- Fixespython#19998
Option ① from
python#19561 (comment)
which does not allow `MemberExpr` elements to the nested binder, hence
ternaries like `f(x.attr) if x.attr else g(x.attr)` will not consider
the narrowed type of `x.attr`
Option ②: python#19562
The current implementation of `visit_conditional_expr` seemed to some
rather complicated things, I found that if there is no context, we can
simply use the union of the types produced when considering the branches
context-free as an artificial context that leads to the desired behavior
in the unification test cases.
from typing import TypeVar, Union, Callable, reveal_type
3028
+
3029
+
NOOP = lambda: None
3030
+
class A: pass
3031
+
class B:
3032
+
attr: Union[A, None]
3033
+
3034
+
def test_static_with_attr(x: B) -> None:
3035
+
def foo(t: A) -> None: ...
3036
+
3037
+
l1: Callable[[], None] = (lambda: foo(x.attr)) if x.attr is not None else NOOP # E: Argument 1 to "foo" has incompatible type "Optional[A]"; expected "A"
3038
+
r1: Callable[[], None] = NOOP if x.attr is None else (lambda: foo(x.attr)) # E: Argument 1 to "foo" has incompatible type "Optional[A]"; expected "A"
3039
+
l2 = (lambda: foo(x.attr)) if x.attr is not None else NOOP # E: Argument 1 to "foo" has incompatible type "Optional[A]"; expected "A"
3040
+
r2 = NOOP if x.attr is None else (lambda: foo(x.attr)) # E: Argument 1 to "foo" has incompatible type "Optional[A]"; expected "A"
3041
+
reveal_type(l2) # N: Revealed type is "def ()"
3042
+
reveal_type(r2) # N: Revealed type is "def ()"
3043
+
3044
+
def test_generic_with_attr(x: B) -> None:
3045
+
T = TypeVar("T")
3046
+
def bar(t: T) -> T: return t
3047
+
3048
+
l1: Callable[[], None] = (lambda: bar(x.attr)) if x.attr is None else NOOP # E: Incompatible types in assignment (expression has type "Callable[[], Optional[A]]", variable has type "Callable[[], None]")
3049
+
r1: Callable[[], None] = NOOP if x.attr is not None else (lambda: bar(x.attr)) # E: Incompatible types in assignment (expression has type "Callable[[], Optional[A]]", variable has type "Callable[[], None]")
3050
+
l2 = (lambda: bar(x.attr)) if x.attr is None else NOOP
3051
+
r2 = NOOP if x.attr is not None else (lambda: bar(x.attr))
3052
+
reveal_type(l2) # N: Revealed type is "def () -> Union[__main__.A, None]"
3053
+
reveal_type(r2) # N: Revealed type is "def () -> Union[__main__.A, None]"
3054
+
3055
+
[case testLambdaTernaryDoubleIndirectAttribute]
3056
+
# fails due to binder issue inside `check_func_def`
from typing import TypeVar, Union, Callable, reveal_type
3059
+
3060
+
NOOP = lambda: None
3061
+
class A: pass
3062
+
class B:
3063
+
attr: Union[A, None]
3064
+
class C:
3065
+
attr: B
3066
+
3067
+
def test_static_with_attr(x: C) -> None:
3068
+
def foo(t: A) -> None: ...
3069
+
3070
+
l1: Callable[[], None] = (lambda: foo(x.attr.attr)) if x.attr.attr is not None else NOOP # E: Argument 1 to "foo" has incompatible type "Optional[A]"; expected "A"
3071
+
r1: Callable[[], None] = NOOP if x.attr.attr is None else (lambda: foo(x.attr.attr)) # E: Argument 1 to "foo" has incompatible type "Optional[A]"; expected "A"
3072
+
l2 = (lambda: foo(x.attr.attr)) if x.attr.attr is not None else NOOP # E: Argument 1 to "foo" has incompatible type "Optional[A]"; expected "A"
3073
+
r2 = NOOP if x.attr.attr is None else (lambda: foo(x.attr.attr)) # E: Argument 1 to "foo" has incompatible type "Optional[A]"; expected "A"
3074
+
reveal_type(l2) # N: Revealed type is "def ()"
3075
+
reveal_type(r2) # N: Revealed type is "def ()"
3076
+
3077
+
def test_generic_with_attr(x: C) -> None:
3078
+
T = TypeVar("T")
3079
+
def bar(t: T) -> T: return t
3080
+
3081
+
l1: Callable[[], None] = (lambda: bar(x.attr.attr)) if x.attr.attr is None else NOOP # E: Incompatible types in assignment (expression has type "Callable[[], Optional[A]]", variable has type "Callable[[], None]")
3082
+
r1: Callable[[], None] = NOOP if x.attr.attr is not None else (lambda: bar(x.attr.attr)) # E: Incompatible types in assignment (expression has type "Callable[[], Optional[A]]", variable has type "Callable[[], None]")
3083
+
l2 = (lambda: bar(x.attr.attr)) if x.attr.attr is None else NOOP
3084
+
r2 = NOOP if x.attr.attr is not None else (lambda: bar(x.attr.attr))
3085
+
reveal_type(l2) # N: Revealed type is "def () -> Union[__main__.A, None]"
3086
+
reveal_type(r2) # N: Revealed type is "def () -> Union[__main__.A, None]"
0 commit comments