Skip to content

Commit 47e6a0a

Browse files
committed
Better handling of Any types
1 parent da033a3 commit 47e6a0a

File tree

1 file changed

+19
-14
lines changed

1 file changed

+19
-14
lines changed

mypy/checker.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -658,22 +658,24 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
658658
# Perform a reduced visit just to infer the actual setter type.
659659
self.visit_decorator_inner(defn.items[1], skip_first_item=True)
660660
setter_type = get_proper_type(defn.items[1].var.type)
661-
if not isinstance(setter_type, CallableType) or len(setter_type.arg_types) != 2:
661+
# Check if the setter can accept two positional arguments.
662+
any_type = AnyType(TypeOfAny.special_form)
663+
fallback_setter_type = CallableType(
664+
arg_types=[any_type, any_type],
665+
arg_kinds=[ARG_POS, ARG_POS],
666+
arg_names=[None, None],
667+
ret_type=any_type,
668+
fallback=self.named_type("builtins.function"),
669+
)
670+
if setter_type and not is_subtype(setter_type, fallback_setter_type):
662671
self.fail("Invalid property setter signature", defn.items[1].func)
663-
any_type = AnyType(TypeOfAny.from_error)
664-
fallback_setter_type = self.function_type(defn.items[1].func)
665-
assert isinstance(fallback_setter_type, CallableType)
666-
setter_type = fallback_setter_type.copy_modified(
667-
arg_types=[any_type, any_type],
668-
arg_kinds=[ARG_POS, ARG_POS],
669-
arg_names=[None, None],
670-
)
672+
if not isinstance(setter_type, CallableType) or len(setter_type.arg_types) != 2:
673+
# TODO: keep precise type for callables with tricky but valid signatures.
674+
setter_type = fallback_setter_type
671675
defn.items[0].var.setter_type = setter_type
672676
for fdef in defn.items:
673677
assert isinstance(fdef, Decorator)
674-
if defn.is_property:
675-
self.check_func_item(fdef.func, name=fdef.func.name, allow_empty=True)
676-
else:
678+
if not defn.is_property:
677679
# Perform full check for real overloads to infer type of all decorated
678680
# overload variants.
679681
self.visit_decorator_inner(fdef, allow_empty=True)
@@ -5296,6 +5298,7 @@ def visit_decorator_inner(
52965298
# Process decorators from the inside out to determine decorated signature, which
52975299
# may be different from the declared signature.
52985300
sig: Type = self.function_type(e.func)
5301+
non_trivial_decorator = False
52995302
# For settable properties skip the first decorator (that is @foo.setter).
53005303
for d in reversed(e.decorators[1:] if skip_first_item else e.decorators):
53015304
if refers_to_fullname(d, "abc.abstractmethod"):
@@ -5306,12 +5309,13 @@ def visit_decorator_inner(
53065309
if not allow_empty:
53075310
self.fail(message_registry.MULTIPLE_OVERLOADS_REQUIRED, e)
53085311
continue
5312+
non_trivial_decorator = True
53095313
dec = self.expr_checker.accept(d)
53105314
temp = self.temp_node(sig, context=d)
53115315
fullname = None
53125316
if isinstance(d, RefExpr):
53135317
fullname = d.fullname or None
5314-
# if this is a expression like @b.a where b is an object, get the type of b
5318+
# if this is an expression like @b.a where b is an object, get the type of b,
53155319
# so we can pass it the method hook in the plugins
53165320
object_type: Type | None = None
53175321
if fullname is None and isinstance(d, MemberExpr) and self.has_type(d.expr):
@@ -5321,7 +5325,8 @@ def visit_decorator_inner(
53215325
sig, t2 = self.expr_checker.check_call(
53225326
dec, [temp], [nodes.ARG_POS], e, callable_name=fullname, object_type=object_type
53235327
)
5324-
self.check_untyped_after_decorator(sig, e.func)
5328+
if non_trivial_decorator:
5329+
self.check_untyped_after_decorator(sig, e.func)
53255330
sig = set_callable_name(sig, e.func)
53265331
e.var.type = sig
53275332
e.var.is_ready = True

0 commit comments

Comments
 (0)