Skip to content

Commit d45f93c

Browse files
committed
Alway visit deleter bodies; more tests
1 parent 47e6a0a commit d45f93c

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

mypy/checker.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,7 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
654654
assert isinstance(defn.items[0], Decorator)
655655
self.visit_decorator(defn.items[0])
656656
if defn.items[0].var.is_settable_property:
657+
# TODO: here and elsewhere we assume setter immediately follows getter.
657658
assert isinstance(defn.items[1], Decorator)
658659
# Perform a reduced visit just to infer the actual setter type.
659660
self.visit_decorator_inner(defn.items[1], skip_first_item=True)
@@ -673,9 +674,15 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
673674
# TODO: keep precise type for callables with tricky but valid signatures.
674675
setter_type = fallback_setter_type
675676
defn.items[0].var.setter_type = setter_type
676-
for fdef in defn.items:
677+
for i, fdef in enumerate(defn.items):
677678
assert isinstance(fdef, Decorator)
678-
if not defn.is_property:
679+
if defn.is_property:
680+
assert isinstance(defn.items[0], Decorator)
681+
settable = defn.items[0].var.is_settable_property
682+
# Do not visit the second time the items we checked above.
683+
if (settable and i > 1) or (not settable and i > 0):
684+
self.check_func_item(fdef.func, name=fdef.func.name, allow_empty=True)
685+
else:
679686
# Perform full check for real overloads to infer type of all decorated
680687
# overload variants.
681688
self.visit_decorator_inner(fdef, allow_empty=True)

test-data/unit/check-classes.test

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8508,6 +8508,33 @@ class C(B):
85088508
@deco
85098509
def bar(self, x: int, y: int) -> None: ...
85108510

8511+
@property
8512+
def baz(self) -> int: ...
8513+
@baz.setter
8514+
@deco_untyped
8515+
def baz(self, x: int) -> None: ...
8516+
8517+
c: C
8518+
c.baz = "yes" # OK, because of untyped decorator
8519+
85118520
T = TypeVar("T")
85128521
def deco(fn: Callable[[T, int, int], None]) -> Callable[[T, int], None]: ...
8522+
def deco_untyped(fn): ...
8523+
[builtins fixtures/property.pyi]
8524+
8525+
[case testPropertyDeleterBodyChecked]
8526+
class C:
8527+
@property
8528+
def foo(self) -> int: ...
8529+
@foo.deleter
8530+
def foo(self) -> None:
8531+
1() # E: "int" not callable
8532+
8533+
@property
8534+
def bar(self) -> int: ...
8535+
@bar.setter
8536+
def bar(self, x: str) -> None: ...
8537+
@bar.deleter
8538+
def bar(self) -> None:
8539+
1() # E: "int" not callable
85138540
[builtins fixtures/property.pyi]

0 commit comments

Comments
 (0)