ruff/crates
Alex Waygood bab688b76c
[ty] Retain the function-like-ness of Callable types when binding self (#21614)
## Summary

For something like this:

```py
from typing import Callable

def my_lossy_decorator(fn: Callable[..., int]) -> Callable[..., int]:
    return fn

class MyClass:
    @my_lossy_decorator
    def method(self) -> int:
        return 42
```

we will currently infer the type of `MyClass.method` as a function-like
`Callable`, but we will infer the type of `MyClass().method` as a
`Callable` that is _not_ function-like. That's because a `CallableType`
currently "forgets" whether it was function-like or not during the
`bound_self` transformation:


a57e291311/crates/ty_python_semantic/src/types.rs (L10985-L10987)

This seems incorrect, and it's quite different to what we do when
binding the `self` parameter of `FunctionLiteral` types: `BoundMethod`
types are all seen as subtypes of function-like `Callable` supertypes --
here's `BoundMethodType::into_callable_type`:


a57e291311/crates/ty_python_semantic/src/types.rs (L10844-L10860)

The bug here is also causing lots of false positives in the ecosystem
report on https://github.com/astral-sh/ruff/pull/21611: a decorated
method on a subclass is currently not seen as validly overriding an
undecorated method with the same signature on a superclass, because the
undecorated superclass method is seen as function-like after binding
`self` whereas the decorated subclass method is not.

Fixing the bug required adding a new API in `protocol_class.rs`, because
it turns out that for our purposes in protocol subtyping/assignability,
we really do want a callable type to forget its function-like-ness when
binding `self`.

I initially tried out this change without changing anything in
`protocol_class.rs`. However, it resulted in many ecosystem false
positives and new false positives on the typing conformance test suite.
This is because it would mean that no protocol with a `__call__` method
would ever be seen as a subtype of a `Callable` type, since the
`__call__` method on the protocol would be seen as being function-like
whereas the `Callable` type would not be seen as function-like.

## Test Plan

Added an mdtest that fails on `main`
2025-11-24 21:14:03 +00:00
..
ruff Bump 0.14.6 (#21558) 2025-11-21 09:00:56 -05:00
ruff_annotate_snippets Only render hyperlinks for terminals known to support them (#21519) 2025-11-19 10:02:58 +01:00
ruff_benchmark Fix cargo shear in CI (#21609) 2025-11-24 05:35:34 +00:00
ruff_cache
ruff_db Only render hyperlinks for terminals known to support them (#21519) 2025-11-19 10:02:58 +01:00
ruff_dev Update Rust toolchain to 1.91 (#21179) 2025-11-01 01:50:58 +00:00
ruff_diagnostics
ruff_formatter [ty] Use "cannot" consistently over "can not" (#21255) 2025-11-03 10:38:20 -05:00
ruff_graph analyze: Add option to skip over imports in TYPE_CHECKING blocks (#21472) 2025-11-16 12:30:24 +00:00
ruff_index
ruff_linter [flake8-implicit-str-concat] Avoid invalid fix generated by autofix (ISC003) (#21517) 2025-11-21 17:22:35 -08:00
ruff_macros
ruff_memory_usage
ruff_notebook [ty] Respect notebook cell boundaries when adding an auto import (#21322) 2025-11-13 18:58:08 +01:00
ruff_options_metadata
ruff_python_ast [ty] Fix panic for unclosed string literal in type annotation position (#21592) 2025-11-23 16:51:58 +01:00
ruff_python_ast_integration_tests
ruff_python_codegen Configurable "unparse mode" for ruff_python_codegen::Generator (#21041) 2025-10-24 15:44:48 +00:00
ruff_python_formatter Respect fmt: skip for compound statements on single line (#20633) 2025-11-18 12:02:09 -06:00
ruff_python_importer [ty] Respect notebook cell boundaries when adding an auto import (#21322) 2025-11-13 18:58:08 +01:00
ruff_python_index
ruff_python_literal
ruff_python_parser [parser] Fix panic when parsing IPython escape command expressions (#21480) 2025-11-24 05:40:27 +00:00
ruff_python_semantic [pyflakes] Revert to stable behavior if imports for module lie in alternate branches for F401 (#20878) 2025-10-27 10:23:36 -05:00
ruff_python_stdlib
ruff_python_trivia
ruff_python_trivia_integration_tests
ruff_server Set severity for non-rule diagnostics (#21559) 2025-11-21 17:42:35 +01:00
ruff_source_file
ruff_text_size [ty] Fix subtraction overflow bug 2025-11-21 15:07:37 -05:00
ruff_wasm Bump 0.14.6 (#21558) 2025-11-21 09:00:56 -05:00
ruff_workspace analyze: Add option to skip over imports in TYPE_CHECKING blocks (#21472) 2025-11-16 12:30:24 +00:00
ty [ty] Add hint about resolved Python version when a user attempts to import a member added on a newer version (#21615) 2025-11-24 15:12:01 +00:00
ty_combine
ty_completion_eval [ty] Don't suggest things that aren't subclasses of BaseException after raise 2025-11-24 12:55:30 -05:00
ty_ide [ty] Double click to insert inlay hint (#21600) 2025-11-24 19:48:30 +00:00
ty_project [ty] Fix --exclude and src.exclude merging (#21341) 2025-11-10 12:52:45 +01:00
ty_python_semantic [ty] Retain the function-like-ness of Callable types when binding self (#21614) 2025-11-24 21:14:03 +00:00
ty_server [ty] Double click to insert inlay hint (#21600) 2025-11-24 19:48:30 +00:00
ty_static
ty_test [ty] Provide proper error on dangling revealed (#21416) 2025-11-16 08:34:54 +00:00
ty_vendored [ty] Create a specialization from a constraint set (#21414) 2025-11-19 14:20:33 -05:00
ty_wasm [ty] Inlay hint call argument location (#20349) 2025-11-17 11:33:09 +01:00