From eddc8d7644ee1d9f31b5891c1d10a2ce0ca0eb84 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 30 Oct 2024 14:22:34 -0400 Subject: [PATCH] Add failing tests for augmented assignments with partial binding (#14002) ## Summary These cases aren't handled correctly yet -- some of them are waiting on refactors to `Unbound` before fixing. Part of #12699. --------- Co-authored-by: Carl Meyer Co-authored-by: Alex Waygood --- .../resources/mdtest/assignment/augmented.md | 107 +++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/assignment/augmented.md b/crates/red_knot_python_semantic/resources/mdtest/assignment/augmented.md index fb202c0ab9..1f53b75714 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/assignment/augmented.md +++ b/crates/red_knot_python_semantic/resources/mdtest/assignment/augmented.md @@ -25,7 +25,7 @@ reveal_type(x) # revealed: str class C: def __iadd__(self, other: str) -> float: - return "Hello, world!" + return 1.0 x = C() x += "Hello" @@ -45,3 +45,108 @@ x -= 1 # TODO: should error, once operand type check is implemented reveal_type(x) # revealed: int ``` + +## Method union + +```py +def bool_instance() -> bool: + return True + +flag = bool_instance() + +class Foo: + if bool_instance(): + def __iadd__(self, other: int) -> str: + return "Hello, world!" + else: + def __iadd__(self, other: int) -> int: + return 42 + +f = Foo() +f += 12 + +reveal_type(f) # revealed: str | int +``` + +## Partially bound `__iadd__` + +```py +def bool_instance() -> bool: + return True + +class Foo: + if bool_instance(): + def __iadd__(self, other: str) -> int: + return 42 + +f = Foo() +f += "Hello, world!" + +# TODO should emit a diagnostic warning that `Foo` might not have an `__iadd__` method +reveal_type(f) # revealed: int +``` + +## Partially bound with `__add__` + +```py +def bool_instance() -> bool: + return True + +class Foo: + def __add__(self, other: str) -> str: + return "Hello, world!" + if bool_instance(): + def __iadd__(self, other: str) -> int: + return 42 + +f = Foo() +f += "Hello, world!" + +# TODO(charlie): This should be `int | str`, since `__iadd__` may be unbound. +reveal_type(f) # revealed: int +``` + +## Partially bound target union + +```py +def bool_instance() -> bool: + return True + +class Foo: + def __add__(self, other: int) -> str: + return "Hello, world!" + if bool_instance(): + def __iadd__(self, other: int) -> int: + return 42 + +if bool_instance(): + f = Foo() +else: + f = 42.0 +f += 12 + +# TODO(charlie): This should be `str | int | float` +reveal_type(f) # revealed: @Todo +``` + +## Target union + +```py +def bool_instance() -> bool: + return True + +flag = bool_instance() + +class Foo: + def __iadd__(self, other: int) -> str: + return "Hello, world!" + +if flag: + f = Foo() +else: + f = 42.0 +f += 12 + +# TODO(charlie): This should be `str | float`. +reveal_type(f) # revealed: @Todo +```