@@ -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