ruff/crates/red_knot_python_semantic/resources/mdtest
David Peter d2e034adcd
[red-knot] Method calls and the descriptor protocol (#16121)
## Summary

This PR achieves the following:

* Add support for checking method calls, and inferring return types from
method calls. For example:
  ```py
  reveal_type("abcde".find("abc"))  # revealed: int
  reveal_type("foo".encode(encoding="utf-8"))  # revealed: bytes
  
  "abcde".find(123)  # error: [invalid-argument-type]
  
  class C:
      def f(self) -> int:
          pass
  
  reveal_type(C.f)  # revealed: <function `f`>
  reveal_type(C().f)  # revealed: <bound method: `f` of `C`>
  
  C.f()  # error: [missing-argument]
  reveal_type(C().f())  # revealed: int
  ```
* Implement the descriptor protocol, i.e. properly call the `__get__`
method when a descriptor object is accessed through a class object or an
instance of a class. For example:
  ```py
  from typing import Literal
  
  class Ten:
def __get__(self, instance: object, owner: type | None = None) ->
Literal[10]:
          return 10
  
  class C:
      ten: Ten = Ten()
  
  reveal_type(C.ten)  # revealed: Literal[10]
  reveal_type(C().ten)  # revealed: Literal[10]
  ```
* Add support for member lookup on intersection types.
* Support type inference for `inspect.getattr_static(obj, attr)` calls.
This was mostly used as a debugging tool during development, but seems
more generally useful. It can be used to bypass the descriptor protocol.
For the example above:
  ```py
  from inspect import getattr_static
  
  reveal_type(getattr_static(C, "ten"))  # revealed: Ten
  ```
* Add a new `Type::Callable(…)` variant with the following sub-variants:
* `Type::Callable(CallableType::BoundMethod(…))` — represents bound
method objects, e.g. `C().f` above
* `Type::Callable(CallableType::MethodWrapperDunderGet(…))` — represents
`f.__get__` where `f` is a function
* `Type::Callable(WrapperDescriptorDunderGet)` — represents
`FunctionType.__get__`
* Add new known classes:
  * `types.MethodType`
  * `types.MethodWrapperType`
  * `types.WrapperDescriptorType`
  * `builtins.range`

## Performance analysis

On this branch, we do more work. We need to do more call checking, since
we now check all method calls. We also need to do ~twice as many member
lookups, because we need to check if a `__get__` attribute exists on
accessed members.

A brief analysis on `tomllib` shows that we now call `Type::call` 1780
times, compared to 612 calls before.

## Limitations

* Data descriptors are not yet supported, i.e. we do not infer correct
types for descriptor attribute accesses in `Store` context and do not
check writes to descriptor attributes. I felt like this was something
that could be split out as a follow-up without risking a major
architectural change.
* We currently distinguish between `Type::member` (with descriptor
protocol) and `Type::static_member` (without descriptor protocol). The
former corresponds to `obj.attr`, the latter corresponds to
`getattr_static(obj, "attr")`. However, to model some details correctly,
we would also need to distinguish between a static member lookup *with*
and *without* instance variables. The lookup without instance variables
corresponds to `find_name_in_mro`
[here](https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance).
We currently approximate both using `member_static`, which leads to two
open TODOs. Changing this would be a larger refactoring of
`Type::own_instance_member`, so I chose to leave it out of this PR.

## Test Plan

* New `call/methods.md` test suite for method calls
* New tests in `descriptor_protocol.md`
* New `call/getattr_static.md` test suite for `inspect.getattr_static`
* Various updated tests
2025-02-20 23:22:26 +01:00
..
annotations [red-knot] Method calls and the descriptor protocol (#16121) 2025-02-20 23:22:26 +01:00
assignment Refactor CallOutcome to Result (#16161) 2025-02-18 13:34:39 +01:00
binary [red-knot] update TODO comment in mdtest (#16242) 2025-02-18 20:52:17 +00:00
boolean [red-knot] Statically known branches (#15019) 2024-12-21 11:33:10 +01:00
boundness_declaredness [red-knot] Enforce specifying paths for mdtest code blocks in a separate preceding line (#15890) 2025-02-04 08:27:17 +01:00
call [red-knot] Method calls and the descriptor protocol (#16121) 2025-02-20 23:22:26 +01:00
comparison [red-knot] MDTest: Use custom class names instead of builtins (#16269) 2025-02-20 12:25:55 +00:00
comprehensions [red-knot] Resolve references in eager nested scopes eagerly (#16079) 2025-02-19 10:22:30 -05:00
conditional [red-knot] fix control flow for assignment expressions in elif tests (#15274) 2025-01-05 18:35:29 +00:00
declaration [red-knot] Avoid undeclared path when raising conflicting declarations (#14958) 2024-12-17 09:49:39 +05:30
diagnostics red_knot_python_semantic: improve diagnostic message for "invalid argument type" 2025-02-19 08:24:19 -05:00
directives [red-knot] Add missing imports in mdtests (#15869) 2025-02-03 09:27:29 +00:00
doc [red-knot] Document 'public type of undeclared symbols' behavior (#16096) 2025-02-12 08:52:11 +01:00
exception [red-knot] MDTest: Use custom class names instead of builtins (#16269) 2025-02-20 12:25:55 +00:00
expression [red-knot] Enforce specifying paths for mdtest code blocks in a separate preceding line (#15890) 2025-02-04 08:27:17 +01:00
function [red-knot] function parameter types (#14802) 2024-12-06 12:55:56 -08:00
import [red-knot] Support re-export conventions for stub files (#16073) 2025-02-14 15:17:51 +05:30
literal [red-knot] Migrate bool/str/repr unit tests to Markdown tests (#15534) 2025-01-16 11:21:56 -08:00
loops [red-knot] MDTest: Use custom class names instead of builtins (#16269) 2025-02-20 12:25:55 +00:00
narrow [red-knot] Recognize ... as a singleton (#16184) 2025-02-16 22:01:02 +00:00
regression [red-knot] Enforce specifying paths for mdtest code blocks in a separate preceding line (#15890) 2025-02-04 08:27:17 +01:00
scopes [red-knot] Method calls and the descriptor protocol (#16121) 2025-02-20 23:22:26 +01:00
shadowing [red-knot] Merge Markdown code blocks inside a single section (#15950) 2025-02-05 22:26:15 +01:00
snapshots red_knot_python_semantic: improve diagnostic message for "invalid argument type" 2025-02-19 08:24:19 -05:00
stubs [red-knot] Enforce specifying paths for mdtest code blocks in a separate preceding line (#15890) 2025-02-04 08:27:17 +01:00
subscript [red-knot] Add missing imports in mdtests (#15869) 2025-02-03 09:27:29 +00:00
suppressions [red-knot] Merge Markdown code blocks inside a single section (#15950) 2025-02-05 22:26:15 +01:00
type_of [red-knot] Method calls and the descriptor protocol (#16121) 2025-02-20 23:22:26 +01:00
type_properties [red-knot] Method calls and the descriptor protocol (#16121) 2025-02-20 23:22:26 +01:00
type_qualifiers [red-knot] Add missing imports in mdtests (#15869) 2025-02-03 09:27:29 +00:00
unary [red-knot] Fix Stack overflow in Type::bool (#15843) 2025-02-04 12:40:07 -08:00
with Refactor CallOutcome to Result (#16161) 2025-02-18 13:34:39 +01:00
.mdformat.toml [red-knot] have mdformat wrap mdtest files to 100 columns (#14020) 2024-10-31 21:00:51 +00:00
attributes.md [red-knot] Method calls and the descriptor protocol (#16121) 2025-02-20 23:22:26 +01:00
descriptor_protocol.md [red-knot] Method calls and the descriptor protocol (#16121) 2025-02-20 23:22:26 +01:00
final.md [red-knot] Add support for @final classes (#15070) 2024-12-19 21:02:14 +00:00
generics.md [red-knot] Enforce specifying paths for mdtest code blocks in a separate preceding line (#15890) 2025-02-04 08:27:17 +01:00
intersection_types.md [red-knot] Add missing imports in mdtests (#15869) 2025-02-03 09:27:29 +00:00
invalid_syntax.md [red-knot] Separate invalid syntax code snippets (#14803) 2024-12-06 02:41:33 +00:00
known_constants.md [red-knot] Enforce specifying paths for mdtest code blocks in a separate preceding line (#15890) 2025-02-04 08:27:17 +01:00
mdtest_config.md [red-knot] Add missing imports in mdtests (#15869) 2025-02-03 09:27:29 +00:00
mdtest_custom_typeshed.md [red-knot] Enforce specifying paths for mdtest code blocks in a separate preceding line (#15890) 2025-02-04 08:27:17 +01:00
metaclass.md [red-knot] Enforce specifying paths for mdtest code blocks in a separate preceding line (#15890) 2025-02-04 08:27:17 +01:00
mro.md [red-knot] Enforce specifying paths for mdtest code blocks in a separate preceding line (#15890) 2025-02-04 08:27:17 +01:00
pep695_type_aliases.md [red-knot] Move type_alias_types test to Markdown (#15607) 2025-01-20 09:55:54 +01:00
protocols.md [red-knot] Method calls and the descriptor protocol (#16121) 2025-02-20 23:22:26 +01:00
slots.md [red-knot] Use Unknown | T_inferred for undeclared public symbols (#15674) 2025-01-24 12:47:48 +01:00
statically_known_branches.md [red-knot] Litate tests: minor follow-up (#15987) 2025-02-06 07:15:26 +00:00
sys_platform.md [red-knot] Method calls and the descriptor protocol (#16121) 2025-02-20 23:22:26 +01:00
sys_version_info.md [red-knot] Merge Markdown code blocks inside a single section (#15950) 2025-02-05 22:26:15 +01:00
terminal_statements.md [red-knot] Combine terminal statement support with statically known branches (#15817) 2025-02-05 17:47:49 -05:00
type_api.md [red-knot] Merge Markdown code blocks inside a single section (#15950) 2025-02-05 22:26:15 +01:00
union_types.md [red-knot] add special case for float/complex (#16166) 2025-02-14 12:24:10 -08:00
unpacking.md [red-knot] Add missing imports in mdtests (#15869) 2025-02-03 09:27:29 +00:00