@@ -146,3 +146,40 @@ class C2:
146146
147147C2().method_decorated(1 )
148148```
149+
150+ Note that we currently only apply this heuristic when calling a function such as ` memoize ` via the
151+ decorator syntax. This is inconsistent, of course, because the above * should* be equivalent to the
152+ following, but here we emit errors:
153+
154+ ``` py
155+ def memoize3 (f : Callable[[C3, int ], str ]) -> Callable[[C3, int ], str ]:
156+ raise NotImplementedError
157+
158+ class C3 :
159+ def method (self , x : int ) -> str :
160+ return str (x)
161+
162+ method_decorated = memoize3(method)
163+
164+ # error: [missing-argument]
165+ # error: [invalid-argument-type]
166+ C3().method_decorated(1 )
167+ ```
168+
169+ The reason for this is that the heuristic is problematic. We don't * know* that the ` Callable ` in the
170+ return type of ` memoize ` is actually related to the method that we pass in. But when ` memoize ` is
171+ applied as a decorator, it is reasonable to assume so. In general, a function call might however
172+ return a ` Callable ` that is unrelated to the argument passed in. And here, it seems more
173+ reasonable/safe to treat the ` Callable ` as a non-descriptor:
174+
175+ ``` py
176+ def convert_int_function (c : Callable[[int ], int ]) -> Callable[[int ], str ]:
177+ return lambda x : str (c(x))
178+
179+ class C4 :
180+ abs = convert_int_function(abs )
181+ round = convert_int_function(round )
182+
183+ reveal_type(C4().abs) # revealed: Unknown | ((int, /) -> str)
184+ reveal_type(C4().round) # revealed: Unknown | ((int, /) -> str)
185+ ```
0 commit comments