mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-28 21:05:08 +00:00
[ty] Do not carry the generic context of Protocol
or Generic
in the ClassBase
enum (#17989)
Some checks failed
CI / Determine changes (push) Has been cancelled
CI / cargo fmt (push) Has been cancelled
CI / cargo build (release) (push) Has been cancelled
CI / mkdocs (push) Has been cancelled
CI / python package (push) Has been cancelled
CI / pre-commit (push) Has been cancelled
[ty Playground] Release / publish (push) Has been cancelled
CI / cargo clippy (push) Has been cancelled
CI / cargo test (linux) (push) Has been cancelled
CI / cargo test (linux, release) (push) Has been cancelled
CI / cargo test (windows) (push) Has been cancelled
CI / cargo test (wasm) (push) Has been cancelled
CI / cargo build (msrv) (push) Has been cancelled
CI / cargo fuzz build (push) Has been cancelled
CI / fuzz parser (push) Has been cancelled
CI / test scripts (push) Has been cancelled
CI / ecosystem (push) Has been cancelled
CI / Fuzz for new ty panics (push) Has been cancelled
CI / cargo shear (push) Has been cancelled
CI / formatter instabilities and black similarity (push) Has been cancelled
CI / test ruff-lsp (push) Has been cancelled
CI / check playground (push) Has been cancelled
CI / benchmarks (push) Has been cancelled
Some checks failed
CI / Determine changes (push) Has been cancelled
CI / cargo fmt (push) Has been cancelled
CI / cargo build (release) (push) Has been cancelled
CI / mkdocs (push) Has been cancelled
CI / python package (push) Has been cancelled
CI / pre-commit (push) Has been cancelled
[ty Playground] Release / publish (push) Has been cancelled
CI / cargo clippy (push) Has been cancelled
CI / cargo test (linux) (push) Has been cancelled
CI / cargo test (linux, release) (push) Has been cancelled
CI / cargo test (windows) (push) Has been cancelled
CI / cargo test (wasm) (push) Has been cancelled
CI / cargo build (msrv) (push) Has been cancelled
CI / cargo fuzz build (push) Has been cancelled
CI / fuzz parser (push) Has been cancelled
CI / test scripts (push) Has been cancelled
CI / ecosystem (push) Has been cancelled
CI / Fuzz for new ty panics (push) Has been cancelled
CI / cargo shear (push) Has been cancelled
CI / formatter instabilities and black similarity (push) Has been cancelled
CI / test ruff-lsp (push) Has been cancelled
CI / check playground (push) Has been cancelled
CI / benchmarks (push) Has been cancelled
## Summary It doesn't seem to be necessary for our generics implementation to carry the `GenericContext` in the `ClassBase` variants. Removing it simplifies the code, fixes many TODOs about `Generic` or `Protocol` appearing multiple times in MROs when each should only appear at most once, and allows us to more accurately detect runtime errors that occur due to `Generic` or `Protocol` appearing multiple times in a class's bases. In order to remove the `GenericContext` from the `ClassBase` variant, it turns out to be necessary to emulate `typing._GenericAlias.__mro_entries__`, or we end up with a large number of false-positive `inconsistent-mro` errors. This PR therefore also does that. Lastly, this PR fixes the inferred MROs of PEP-695 generic classes, which implicitly inherit from `Generic` even if they have no explicit bases. ## Test Plan mdtests
This commit is contained in:
parent
6c0a59ea78
commit
d02c9ada5d
15 changed files with 271 additions and 215 deletions
108
crates/ty/docs/rules.md
generated
108
crates/ty/docs/rules.md
generated
|
@ -50,7 +50,7 @@ Calling a non-callable object will raise a `TypeError` at runtime.
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L90)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L91)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `conflicting-argument-forms`
|
## `conflicting-argument-forms`
|
||||||
|
@ -81,7 +81,7 @@ f(int) # error
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L134)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L135)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `conflicting-declarations`
|
## `conflicting-declarations`
|
||||||
|
@ -111,7 +111,7 @@ a = 1
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L160)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L161)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `conflicting-metaclass`
|
## `conflicting-metaclass`
|
||||||
|
@ -142,7 +142,7 @@ class C(A, B): ...
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L185)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L186)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `cyclic-class-definition`
|
## `cyclic-class-definition`
|
||||||
|
@ -173,7 +173,7 @@ class B(A): ...
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L211)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L212)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `duplicate-base`
|
## `duplicate-base`
|
||||||
|
@ -199,7 +199,7 @@ class B(A, A): ...
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L255)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L256)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `escape-character-in-forward-annotation`
|
## `escape-character-in-forward-annotation`
|
||||||
|
@ -336,7 +336,7 @@ TypeError: multiple bases have instance lay-out conflict
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20incompatible-slots)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20incompatible-slots)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L276)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L277)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `inconsistent-mro`
|
## `inconsistent-mro`
|
||||||
|
@ -365,7 +365,7 @@ class C(A, B): ...
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L362)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L363)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `index-out-of-bounds`
|
## `index-out-of-bounds`
|
||||||
|
@ -390,7 +390,7 @@ t[3] # IndexError: tuple index out of range
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L386)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L387)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-argument-type`
|
## `invalid-argument-type`
|
||||||
|
@ -416,7 +416,7 @@ func("foo") # error: [invalid-argument-type]
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L406)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L407)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-assignment`
|
## `invalid-assignment`
|
||||||
|
@ -443,7 +443,7 @@ a: int = ''
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L446)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L447)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-attribute-access`
|
## `invalid-attribute-access`
|
||||||
|
@ -476,7 +476,7 @@ C.instance_var = 3 # error: Cannot assign to instance variable
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1394)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1395)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-base`
|
## `invalid-base`
|
||||||
|
@ -499,7 +499,7 @@ class A(42): ... # error: [invalid-base]
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L468)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L469)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-context-manager`
|
## `invalid-context-manager`
|
||||||
|
@ -525,7 +525,7 @@ with 1:
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L519)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L520)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-declaration`
|
## `invalid-declaration`
|
||||||
|
@ -553,7 +553,7 @@ a: str
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L540)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L541)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-exception-caught`
|
## `invalid-exception-caught`
|
||||||
|
@ -594,7 +594,7 @@ except ZeroDivisionError:
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L563)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L564)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-generic-class`
|
## `invalid-generic-class`
|
||||||
|
@ -625,7 +625,7 @@ class C[U](Generic[T]): ...
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L599)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L600)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-legacy-type-variable`
|
## `invalid-legacy-type-variable`
|
||||||
|
@ -658,7 +658,7 @@ def f(t: TypeVar("U")): ...
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L625)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L626)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-metaclass`
|
## `invalid-metaclass`
|
||||||
|
@ -690,7 +690,7 @@ class B(metaclass=f): ...
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L674)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L675)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-overload`
|
## `invalid-overload`
|
||||||
|
@ -738,7 +738,7 @@ def foo(x: int) -> int: ...
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L701)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L702)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-parameter-default`
|
## `invalid-parameter-default`
|
||||||
|
@ -763,7 +763,7 @@ def f(a: int = ''): ...
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L744)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L745)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-protocol`
|
## `invalid-protocol`
|
||||||
|
@ -796,7 +796,7 @@ TypeError: Protocols can only inherit from other protocols, got <class 'int'>
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L334)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L335)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-raise`
|
## `invalid-raise`
|
||||||
|
@ -844,7 +844,7 @@ def g():
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L764)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L765)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-return-type`
|
## `invalid-return-type`
|
||||||
|
@ -868,7 +868,7 @@ def func() -> int:
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L427)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L428)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-super-argument`
|
## `invalid-super-argument`
|
||||||
|
@ -912,7 +912,7 @@ super(B, A) # error: `A` does not satisfy `issubclass(A, B)`
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L807)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L808)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-syntax-in-forward-annotation`
|
## `invalid-syntax-in-forward-annotation`
|
||||||
|
@ -952,7 +952,7 @@ NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name mus
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L653)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L654)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-type-checking-constant`
|
## `invalid-type-checking-constant`
|
||||||
|
@ -981,7 +981,7 @@ TYPE_CHECKING = ''
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L846)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L847)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-type-form`
|
## `invalid-type-form`
|
||||||
|
@ -1010,7 +1010,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L870)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L871)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-type-variable-constraints`
|
## `invalid-type-variable-constraints`
|
||||||
|
@ -1044,7 +1044,7 @@ T = TypeVar('T', bound=str) # valid bound TypeVar
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L894)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L895)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `missing-argument`
|
## `missing-argument`
|
||||||
|
@ -1068,7 +1068,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L923)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L924)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `no-matching-overload`
|
## `no-matching-overload`
|
||||||
|
@ -1096,7 +1096,7 @@ func("string") # error: [no-matching-overload]
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L942)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L943)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `non-subscriptable`
|
## `non-subscriptable`
|
||||||
|
@ -1119,7 +1119,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L965)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L966)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `not-iterable`
|
## `not-iterable`
|
||||||
|
@ -1144,7 +1144,7 @@ for i in 34: # TypeError: 'int' object is not iterable
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L983)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L984)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `parameter-already-assigned`
|
## `parameter-already-assigned`
|
||||||
|
@ -1170,7 +1170,7 @@ f(1, x=2) # Error raised here
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1034)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1035)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `raw-string-type-annotation`
|
## `raw-string-type-annotation`
|
||||||
|
@ -1229,7 +1229,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1370)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1371)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `subclass-of-final-class`
|
## `subclass-of-final-class`
|
||||||
|
@ -1257,7 +1257,7 @@ class B(A): ... # Error raised here
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1125)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1126)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `too-many-positional-arguments`
|
## `too-many-positional-arguments`
|
||||||
|
@ -1283,7 +1283,7 @@ f("foo") # Error raised here
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1170)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1171)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `type-assertion-failure`
|
## `type-assertion-failure`
|
||||||
|
@ -1310,7 +1310,7 @@ def _(x: int):
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1148)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1149)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `unavailable-implicit-super-arguments`
|
## `unavailable-implicit-super-arguments`
|
||||||
|
@ -1354,7 +1354,7 @@ class A:
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1191)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1192)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `unknown-argument`
|
## `unknown-argument`
|
||||||
|
@ -1380,7 +1380,7 @@ f(x=1, y=2) # Error raised here
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1248)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1249)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `unresolved-attribute`
|
## `unresolved-attribute`
|
||||||
|
@ -1407,7 +1407,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo'
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1269)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1270)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `unresolved-import`
|
## `unresolved-import`
|
||||||
|
@ -1431,7 +1431,7 @@ import foo # ModuleNotFoundError: No module named 'foo'
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1291)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1292)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `unresolved-reference`
|
## `unresolved-reference`
|
||||||
|
@ -1455,7 +1455,7 @@ print(x) # NameError: name 'x' is not defined
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1310)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1311)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `unsupported-bool-conversion`
|
## `unsupported-bool-conversion`
|
||||||
|
@ -1491,7 +1491,7 @@ b1 < b2 < b1 # exception raised here
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1003)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1004)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `unsupported-operator`
|
## `unsupported-operator`
|
||||||
|
@ -1518,7 +1518,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1329)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1330)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `zero-stepsize-in-slice`
|
## `zero-stepsize-in-slice`
|
||||||
|
@ -1542,7 +1542,7 @@ l[1:10:0] # ValueError: slice step cannot be zero
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1351)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1352)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `invalid-ignore-comment`
|
## `invalid-ignore-comment`
|
||||||
|
@ -1598,7 +1598,7 @@ A.c # AttributeError: type object 'A' has no attribute 'c'
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-attribute)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-attribute)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1055)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1056)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `possibly-unbound-implicit-call`
|
## `possibly-unbound-implicit-call`
|
||||||
|
@ -1629,7 +1629,7 @@ A()[0] # TypeError: 'A' object is not subscriptable
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-implicit-call)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-implicit-call)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L108)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L109)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `possibly-unbound-import`
|
## `possibly-unbound-import`
|
||||||
|
@ -1660,7 +1660,7 @@ from module import a # ImportError: cannot import name 'a' from 'module'
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-import)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-import)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1077)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1078)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `redundant-cast`
|
## `redundant-cast`
|
||||||
|
@ -1686,7 +1686,7 @@ cast(int, f()) # Redundant
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1422)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1423)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `undefined-reveal`
|
## `undefined-reveal`
|
||||||
|
@ -1709,7 +1709,7 @@ reveal_type(1) # NameError: name 'reveal_type' is not defined
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1230)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1231)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `unknown-rule`
|
## `unknown-rule`
|
||||||
|
@ -1777,7 +1777,7 @@ class D(C): ... # error: [unsupported-base]
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-base)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-base)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L486)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L487)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `division-by-zero`
|
## `division-by-zero`
|
||||||
|
@ -1800,7 +1800,7 @@ Dividing by zero raises a `ZeroDivisionError` at runtime.
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L237)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L238)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `possibly-unresolved-reference`
|
## `possibly-unresolved-reference`
|
||||||
|
@ -1827,7 +1827,7 @@ print(x) # NameError: name 'x' is not defined
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference)
|
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference)
|
||||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1103)
|
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1104)
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## `unused-ignore-comment`
|
## `unused-ignore-comment`
|
||||||
|
|
|
@ -81,23 +81,22 @@ import typing
|
||||||
|
|
||||||
class ListSubclass(typing.List): ...
|
class ListSubclass(typing.List): ...
|
||||||
|
|
||||||
# revealed: tuple[<class 'ListSubclass'>, <class 'list[Unknown]'>, <class 'MutableSequence[Unknown]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
# revealed: tuple[<class 'ListSubclass'>, <class 'list[Unknown]'>, <class 'MutableSequence[Unknown]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
reveal_type(ListSubclass.__mro__)
|
reveal_type(ListSubclass.__mro__)
|
||||||
|
|
||||||
class DictSubclass(typing.Dict): ...
|
class DictSubclass(typing.Dict): ...
|
||||||
|
|
||||||
# TODO: should not have multiple `Generic[]` elements
|
# revealed: tuple[<class 'DictSubclass'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
# revealed: tuple[<class 'DictSubclass'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], <class 'object'>]
|
|
||||||
reveal_type(DictSubclass.__mro__)
|
reveal_type(DictSubclass.__mro__)
|
||||||
|
|
||||||
class SetSubclass(typing.Set): ...
|
class SetSubclass(typing.Set): ...
|
||||||
|
|
||||||
# revealed: tuple[<class 'SetSubclass'>, <class 'set[Unknown]'>, <class 'MutableSet[Unknown]'>, <class 'AbstractSet[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
# revealed: tuple[<class 'SetSubclass'>, <class 'set[Unknown]'>, <class 'MutableSet[Unknown]'>, <class 'AbstractSet[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
reveal_type(SetSubclass.__mro__)
|
reveal_type(SetSubclass.__mro__)
|
||||||
|
|
||||||
class FrozenSetSubclass(typing.FrozenSet): ...
|
class FrozenSetSubclass(typing.FrozenSet): ...
|
||||||
|
|
||||||
# revealed: tuple[<class 'FrozenSetSubclass'>, <class 'frozenset[Unknown]'>, <class 'AbstractSet[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
# revealed: tuple[<class 'FrozenSetSubclass'>, <class 'frozenset[Unknown]'>, <class 'AbstractSet[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
reveal_type(FrozenSetSubclass.__mro__)
|
reveal_type(FrozenSetSubclass.__mro__)
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
@ -106,30 +105,26 @@ reveal_type(FrozenSetSubclass.__mro__)
|
||||||
|
|
||||||
class ChainMapSubclass(typing.ChainMap): ...
|
class ChainMapSubclass(typing.ChainMap): ...
|
||||||
|
|
||||||
# TODO: should not have multiple `Generic[]` elements
|
# revealed: tuple[<class 'ChainMapSubclass'>, <class 'ChainMap[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
# revealed: tuple[<class 'ChainMapSubclass'>, <class 'ChainMap[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], <class 'object'>]
|
|
||||||
reveal_type(ChainMapSubclass.__mro__)
|
reveal_type(ChainMapSubclass.__mro__)
|
||||||
|
|
||||||
class CounterSubclass(typing.Counter): ...
|
class CounterSubclass(typing.Counter): ...
|
||||||
|
|
||||||
# TODO: Should have one `Generic[]` element, not three(!)
|
# revealed: tuple[<class 'CounterSubclass'>, <class 'Counter[Unknown]'>, <class 'dict[Unknown, int]'>, <class 'MutableMapping[Unknown, int]'>, <class 'Mapping[Unknown, int]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
# revealed: tuple[<class 'CounterSubclass'>, <class 'Counter[Unknown]'>, <class 'dict[Unknown, int]'>, <class 'MutableMapping[Unknown, int]'>, <class 'Mapping[Unknown, int]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], typing.Generic[_T], <class 'object'>]
|
|
||||||
reveal_type(CounterSubclass.__mro__)
|
reveal_type(CounterSubclass.__mro__)
|
||||||
|
|
||||||
class DefaultDictSubclass(typing.DefaultDict): ...
|
class DefaultDictSubclass(typing.DefaultDict): ...
|
||||||
|
|
||||||
# TODO: Should not have multiple `Generic[]` elements
|
# revealed: tuple[<class 'DefaultDictSubclass'>, <class 'defaultdict[Unknown, Unknown]'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
# revealed: tuple[<class 'DefaultDictSubclass'>, <class 'defaultdict[Unknown, Unknown]'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], <class 'object'>]
|
|
||||||
reveal_type(DefaultDictSubclass.__mro__)
|
reveal_type(DefaultDictSubclass.__mro__)
|
||||||
|
|
||||||
class DequeSubclass(typing.Deque): ...
|
class DequeSubclass(typing.Deque): ...
|
||||||
|
|
||||||
# revealed: tuple[<class 'DequeSubclass'>, <class 'deque[Unknown]'>, <class 'MutableSequence[Unknown]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
# revealed: tuple[<class 'DequeSubclass'>, <class 'deque[Unknown]'>, <class 'MutableSequence[Unknown]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
reveal_type(DequeSubclass.__mro__)
|
reveal_type(DequeSubclass.__mro__)
|
||||||
|
|
||||||
class OrderedDictSubclass(typing.OrderedDict): ...
|
class OrderedDictSubclass(typing.OrderedDict): ...
|
||||||
|
|
||||||
# TODO: Should not have multiple `Generic[]` elements
|
# revealed: tuple[<class 'OrderedDictSubclass'>, <class 'OrderedDict[Unknown, Unknown]'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
# revealed: tuple[<class 'OrderedDictSubclass'>, <class 'OrderedDict[Unknown, Unknown]'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], <class 'object'>]
|
|
||||||
reveal_type(OrderedDictSubclass.__mro__)
|
reveal_type(OrderedDictSubclass.__mro__)
|
||||||
```
|
```
|
||||||
|
|
|
@ -24,9 +24,7 @@ class:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
class Bad(Generic[T], Generic[T]): ... # error: [duplicate-base]
|
class Bad(Generic[T], Generic[T]): ... # error: [duplicate-base]
|
||||||
|
class AlsoBad(Generic[T], Generic[S]): ... # error: [duplicate-base]
|
||||||
# TODO: should emit an error (fails at runtime)
|
|
||||||
class AlsoBad(Generic[T], Generic[S]): ...
|
|
||||||
```
|
```
|
||||||
|
|
||||||
You cannot use the same typevar more than once.
|
You cannot use the same typevar more than once.
|
||||||
|
|
|
@ -527,6 +527,45 @@ reveal_type(unknown_object) # revealed: Unknown
|
||||||
reveal_type(unknown_object.__mro__) # revealed: Unknown
|
reveal_type(unknown_object.__mro__) # revealed: Unknown
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## MROs of classes that use multiple inheritance with generic aliases and subscripted `Generic`
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import Generic, TypeVar, Iterator
|
||||||
|
|
||||||
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
class peekable(Generic[T], Iterator[T]): ...
|
||||||
|
|
||||||
|
# revealed: tuple[<class 'peekable[Unknown]'>, <class 'Iterator[T]'>, <class 'Iterable[T]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
|
reveal_type(peekable.__mro__)
|
||||||
|
|
||||||
|
class peekable2(Iterator[T], Generic[T]): ...
|
||||||
|
|
||||||
|
# revealed: tuple[<class 'peekable2[Unknown]'>, <class 'Iterator[T]'>, <class 'Iterable[T]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
|
reveal_type(peekable2.__mro__)
|
||||||
|
|
||||||
|
class Base: ...
|
||||||
|
class Intermediate(Base, Generic[T]): ...
|
||||||
|
class Sub(Intermediate[T], Base): ...
|
||||||
|
|
||||||
|
# revealed: tuple[<class 'Sub[Unknown]'>, <class 'Intermediate[T]'>, <class 'Base'>, typing.Generic, <class 'object'>]
|
||||||
|
reveal_type(Sub.__mro__)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Unresolvable MROs involving generics have the original bases reported in the error message, not the resolved bases
|
||||||
|
|
||||||
|
<!-- snapshot-diagnostics -->
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing_extensions import Protocol, TypeVar, Generic
|
||||||
|
|
||||||
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
class Foo(Protocol): ...
|
||||||
|
class Bar(Protocol[T]): ...
|
||||||
|
class Baz(Protocol[T], Foo, Bar[T]): ... # error: [inconsistent-mro]
|
||||||
|
```
|
||||||
|
|
||||||
## Classes that inherit from themselves
|
## Classes that inherit from themselves
|
||||||
|
|
||||||
These are invalid, but we need to be able to handle them gracefully without panicking.
|
These are invalid, but we need to be able to handle them gracefully without panicking.
|
||||||
|
|
|
@ -67,12 +67,10 @@ It's an error to include both bare `Protocol` and subscripted `Protocol[]` in th
|
||||||
simultaneously:
|
simultaneously:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
# TODO: should emit a `[duplicate-bases]` error here:
|
class DuplicateBases(Protocol, Protocol[T]): # error: [duplicate-base]
|
||||||
class DuplicateBases(Protocol, Protocol[T]):
|
|
||||||
x: T
|
x: T
|
||||||
|
|
||||||
# TODO: should not have `Protocol` or `Generic` multiple times
|
# revealed: tuple[<class 'DuplicateBases[Unknown]'>, Unknown, <class 'object'>]
|
||||||
# revealed: tuple[<class 'DuplicateBases[Unknown]'>, typing.Protocol, typing.Generic, typing.Protocol[T], typing.Generic[T], <class 'object'>]
|
|
||||||
reveal_type(DuplicateBases.__mro__)
|
reveal_type(DuplicateBases.__mro__)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: mro.md - Method Resolution Order tests - Unresolvable MROs involving generics have the original bases reported in the error message, not the resolved bases
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/mro.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | from typing_extensions import Protocol, TypeVar, Generic
|
||||||
|
2 |
|
||||||
|
3 | T = TypeVar("T")
|
||||||
|
4 |
|
||||||
|
5 | class Foo(Protocol): ...
|
||||||
|
6 | class Bar(Protocol[T]): ...
|
||||||
|
7 | class Baz(Protocol[T], Foo, Bar[T]): ... # error: [inconsistent-mro]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[inconsistent-mro]: Cannot create a consistent method resolution order (MRO) for class `Baz` with bases list `[typing.Protocol[T], <class 'Foo'>, <class 'Bar[T]'>]`
|
||||||
|
--> src/mdtest_snippet.py:7:1
|
||||||
|
|
|
||||||
|
5 | class Foo(Protocol): ...
|
||||||
|
6 | class Bar(Protocol[T]): ...
|
||||||
|
7 | class Baz(Protocol[T], Foo, Bar[T]): ... # error: [inconsistent-mro]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
info: rule `inconsistent-mro` is enabled by default
|
||||||
|
|
||||||
|
```
|
|
@ -16,7 +16,7 @@ class Foo[T]: ...
|
||||||
class Bar(Foo[Bar]): ...
|
class Bar(Foo[Bar]): ...
|
||||||
|
|
||||||
reveal_type(Bar) # revealed: <class 'Bar'>
|
reveal_type(Bar) # revealed: <class 'Bar'>
|
||||||
reveal_type(Bar.__mro__) # revealed: tuple[<class 'Bar'>, <class 'Foo[Bar]'>, <class 'object'>]
|
reveal_type(Bar.__mro__) # revealed: tuple[<class 'Bar'>, <class 'Foo[Bar]'>, typing.Generic, <class 'object'>]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Access to attributes declared in stubs
|
## Access to attributes declared in stubs
|
||||||
|
|
|
@ -83,7 +83,7 @@ python-version = "3.9"
|
||||||
```py
|
```py
|
||||||
class A(tuple[int, str]): ...
|
class A(tuple[int, str]): ...
|
||||||
|
|
||||||
# revealed: tuple[<class 'A'>, <class 'tuple[@Todo(Generic tuple specializations), ...]'>, <class 'Sequence[@Todo(Generic tuple specializations)]'>, <class 'Reversible[@Todo(Generic tuple specializations)]'>, <class 'Collection[@Todo(Generic tuple specializations)]'>, <class 'Iterable[@Todo(Generic tuple specializations)]'>, <class 'Container[@Todo(Generic tuple specializations)]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
# revealed: tuple[<class 'A'>, <class 'tuple[@Todo(Generic tuple specializations), ...]'>, <class 'Sequence[@Todo(Generic tuple specializations)]'>, <class 'Reversible[@Todo(Generic tuple specializations)]'>, <class 'Collection[@Todo(Generic tuple specializations)]'>, <class 'Iterable[@Todo(Generic tuple specializations)]'>, <class 'Container[@Todo(Generic tuple specializations)]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
reveal_type(A.__mro__)
|
reveal_type(A.__mro__)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -114,6 +114,6 @@ from typing import Tuple
|
||||||
|
|
||||||
class C(Tuple): ...
|
class C(Tuple): ...
|
||||||
|
|
||||||
# revealed: tuple[<class 'C'>, <class 'tuple[Unknown, ...]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
# revealed: tuple[<class 'C'>, <class 'tuple[Unknown, ...]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
reveal_type(C.__mro__)
|
reveal_type(C.__mro__)
|
||||||
```
|
```
|
||||||
|
|
|
@ -598,6 +598,10 @@ impl<'db> Type<'db> {
|
||||||
matches!(self, Type::Dynamic(DynamicType::Todo(_)))
|
matches!(self, Type::Dynamic(DynamicType::Todo(_)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn is_generic_alias(&self) -> bool {
|
||||||
|
matches!(self, Type::GenericAlias(_))
|
||||||
|
}
|
||||||
|
|
||||||
/// Replace references to the class `class` with a self-reference marker. This is currently
|
/// Replace references to the class `class` with a self-reference marker. This is currently
|
||||||
/// used for recursive protocols, but could probably be extended to self-referential type-
|
/// used for recursive protocols, but could probably be extended to self-referential type-
|
||||||
/// aliases and similar.
|
/// aliases and similar.
|
||||||
|
|
|
@ -223,6 +223,10 @@ impl<'db> ClassType<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) const fn is_generic(self) -> bool {
|
||||||
|
matches!(self, Self::Generic(_))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the class literal and specialization for this class. For a non-generic class, this
|
/// Returns the class literal and specialization for this class. For a non-generic class, this
|
||||||
/// is the class itself. For a generic alias, this is the alias's origin.
|
/// is the class itself. For a generic alias, this is the alias's origin.
|
||||||
pub(crate) fn class_literal(
|
pub(crate) fn class_literal(
|
||||||
|
@ -352,7 +356,7 @@ impl<'db> ClassType<'db> {
|
||||||
ClassBase::Dynamic(_) => false,
|
ClassBase::Dynamic(_) => false,
|
||||||
|
|
||||||
// Protocol and Generic are not represented by a ClassType.
|
// Protocol and Generic are not represented by a ClassType.
|
||||||
ClassBase::Protocol(_) | ClassBase::Generic(_) => false,
|
ClassBase::Protocol | ClassBase::Generic => false,
|
||||||
|
|
||||||
ClassBase::Class(base) => match (base, other) {
|
ClassBase::Class(base) => match (base, other) {
|
||||||
(ClassType::NonGeneric(base), ClassType::NonGeneric(other)) => base == other,
|
(ClassType::NonGeneric(base), ClassType::NonGeneric(other)) => base == other,
|
||||||
|
@ -390,7 +394,7 @@ impl<'db> ClassType<'db> {
|
||||||
ClassBase::Dynamic(_) => false,
|
ClassBase::Dynamic(_) => false,
|
||||||
|
|
||||||
// Protocol and Generic are not represented by a ClassType.
|
// Protocol and Generic are not represented by a ClassType.
|
||||||
ClassBase::Protocol(_) | ClassBase::Generic(_) => false,
|
ClassBase::Protocol | ClassBase::Generic => false,
|
||||||
|
|
||||||
ClassBase::Class(base) => match (base, other) {
|
ClassBase::Class(base) => match (base, other) {
|
||||||
(ClassType::NonGeneric(base), ClassType::NonGeneric(other)) => base == other,
|
(ClassType::NonGeneric(base), ClassType::NonGeneric(other)) => base == other,
|
||||||
|
@ -602,11 +606,6 @@ impl<'db> ClassLiteral<'db> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if this class represents the builtin class `object`
|
|
||||||
pub(crate) fn is_object(self, db: &'db dyn Db) -> bool {
|
|
||||||
self.is_known(db, KnownClass::Object)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn file(self, db: &dyn Db) -> File {
|
fn file(self, db: &dyn Db) -> File {
|
||||||
self.body_scope(db).file(db)
|
self.body_scope(db).file(db)
|
||||||
}
|
}
|
||||||
|
@ -1068,7 +1067,7 @@ impl<'db> ClassLiteral<'db> {
|
||||||
|
|
||||||
for superclass in mro_iter {
|
for superclass in mro_iter {
|
||||||
match superclass {
|
match superclass {
|
||||||
ClassBase::Generic(_) | ClassBase::Protocol(_) => {
|
ClassBase::Generic | ClassBase::Protocol => {
|
||||||
// Skip over these very special class bases that aren't really classes.
|
// Skip over these very special class bases that aren't really classes.
|
||||||
}
|
}
|
||||||
ClassBase::Dynamic(_) => {
|
ClassBase::Dynamic(_) => {
|
||||||
|
@ -1427,7 +1426,7 @@ impl<'db> ClassLiteral<'db> {
|
||||||
|
|
||||||
for superclass in self.iter_mro(db, specialization) {
|
for superclass in self.iter_mro(db, specialization) {
|
||||||
match superclass {
|
match superclass {
|
||||||
ClassBase::Generic(_) | ClassBase::Protocol(_) => {
|
ClassBase::Generic | ClassBase::Protocol => {
|
||||||
// Skip over these very special class bases that aren't really classes.
|
// Skip over these very special class bases that aren't really classes.
|
||||||
}
|
}
|
||||||
ClassBase::Dynamic(_) => {
|
ClassBase::Dynamic(_) => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
use crate::types::generics::{GenericContext, Specialization};
|
use crate::types::generics::Specialization;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
ClassType, DynamicType, KnownClass, KnownInstanceType, MroError, MroIterator, Type,
|
ClassType, DynamicType, KnownClass, KnownInstanceType, MroError, MroIterator, Type,
|
||||||
TypeMapping, todo_type,
|
TypeMapping, todo_type,
|
||||||
|
@ -19,11 +19,11 @@ pub enum ClassBase<'db> {
|
||||||
Class(ClassType<'db>),
|
Class(ClassType<'db>),
|
||||||
/// Although `Protocol` is not a class in typeshed's stubs, it is at runtime,
|
/// Although `Protocol` is not a class in typeshed's stubs, it is at runtime,
|
||||||
/// and can appear in the MRO of a class.
|
/// and can appear in the MRO of a class.
|
||||||
Protocol(Option<GenericContext<'db>>),
|
Protocol,
|
||||||
/// Bare `Generic` cannot be subclassed directly in user code,
|
/// Bare `Generic` cannot be subclassed directly in user code,
|
||||||
/// but nonetheless appears in the MRO of classes that inherit from `Generic[T]`,
|
/// but nonetheless appears in the MRO of classes that inherit from `Generic[T]`,
|
||||||
/// `Protocol[T]`, or bare `Protocol`.
|
/// `Protocol[T]`, or bare `Protocol`.
|
||||||
Generic(Option<GenericContext<'db>>),
|
Generic,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> ClassBase<'db> {
|
impl<'db> ClassBase<'db> {
|
||||||
|
@ -35,60 +35,18 @@ impl<'db> ClassBase<'db> {
|
||||||
match self {
|
match self {
|
||||||
Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()),
|
Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()),
|
||||||
Self::Class(class) => Self::Class(class.normalized(db)),
|
Self::Class(class) => Self::Class(class.normalized(db)),
|
||||||
Self::Protocol(generic_context) => {
|
Self::Protocol | Self::Generic => self,
|
||||||
Self::Protocol(generic_context.map(|context| context.normalized(db)))
|
|
||||||
}
|
|
||||||
Self::Generic(generic_context) => {
|
|
||||||
Self::Generic(generic_context.map(|context| context.normalized(db)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn display(self, db: &'db dyn Db) -> impl std::fmt::Display + 'db {
|
|
||||||
struct Display<'db> {
|
|
||||||
base: ClassBase<'db>,
|
|
||||||
db: &'db dyn Db,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Display<'_> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self.base {
|
|
||||||
ClassBase::Dynamic(dynamic) => dynamic.fmt(f),
|
|
||||||
ClassBase::Class(class @ ClassType::NonGeneric(_)) => {
|
|
||||||
write!(f, "<class '{}'>", class.name(self.db))
|
|
||||||
}
|
|
||||||
ClassBase::Class(ClassType::Generic(alias)) => {
|
|
||||||
write!(f, "<class '{}'>", alias.display(self.db))
|
|
||||||
}
|
|
||||||
ClassBase::Protocol(generic_context) => {
|
|
||||||
f.write_str("typing.Protocol")?;
|
|
||||||
if let Some(generic_context) = generic_context {
|
|
||||||
generic_context.display(self.db).fmt(f)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
ClassBase::Generic(generic_context) => {
|
|
||||||
f.write_str("typing.Generic")?;
|
|
||||||
if let Some(generic_context) = generic_context {
|
|
||||||
generic_context.display(self.db).fmt(f)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Display { base: self, db }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn name(self, db: &'db dyn Db) -> &'db str {
|
pub(crate) fn name(self, db: &'db dyn Db) -> &'db str {
|
||||||
match self {
|
match self {
|
||||||
ClassBase::Class(class) => class.name(db),
|
ClassBase::Class(class) => class.name(db),
|
||||||
ClassBase::Dynamic(DynamicType::Any) => "Any",
|
ClassBase::Dynamic(DynamicType::Any) => "Any",
|
||||||
ClassBase::Dynamic(DynamicType::Unknown) => "Unknown",
|
ClassBase::Dynamic(DynamicType::Unknown) => "Unknown",
|
||||||
ClassBase::Dynamic(DynamicType::Todo(_) | DynamicType::TodoPEP695ParamSpec) => "@Todo",
|
ClassBase::Dynamic(DynamicType::Todo(_) | DynamicType::TodoPEP695ParamSpec) => "@Todo",
|
||||||
ClassBase::Protocol(_) => "Protocol",
|
ClassBase::Protocol => "Protocol",
|
||||||
ClassBase::Generic(_) => "Generic",
|
ClassBase::Generic => "Generic",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,12 +213,8 @@ impl<'db> ClassBase<'db> {
|
||||||
KnownInstanceType::Callable => {
|
KnownInstanceType::Callable => {
|
||||||
Self::try_from_type(db, todo_type!("Support for Callable as a base class"))
|
Self::try_from_type(db, todo_type!("Support for Callable as a base class"))
|
||||||
}
|
}
|
||||||
KnownInstanceType::Protocol(generic_context) => {
|
KnownInstanceType::Protocol(_) => Some(ClassBase::Protocol),
|
||||||
Some(ClassBase::Protocol(generic_context))
|
KnownInstanceType::Generic(_) => Some(ClassBase::Generic),
|
||||||
}
|
|
||||||
KnownInstanceType::Generic(generic_context) => {
|
|
||||||
Some(ClassBase::Generic(generic_context))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,14 +222,14 @@ impl<'db> ClassBase<'db> {
|
||||||
pub(super) fn into_class(self) -> Option<ClassType<'db>> {
|
pub(super) fn into_class(self) -> Option<ClassType<'db>> {
|
||||||
match self {
|
match self {
|
||||||
Self::Class(class) => Some(class),
|
Self::Class(class) => Some(class),
|
||||||
Self::Dynamic(_) | Self::Generic(_) | Self::Protocol(_) => None,
|
Self::Dynamic(_) | Self::Generic | Self::Protocol => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_type_mapping<'a>(self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self {
|
fn apply_type_mapping<'a>(self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Class(class) => Self::Class(class.apply_type_mapping(db, type_mapping)),
|
Self::Class(class) => Self::Class(class.apply_type_mapping(db, type_mapping)),
|
||||||
Self::Dynamic(_) | Self::Generic(_) | Self::Protocol(_) => self,
|
Self::Dynamic(_) | Self::Generic | Self::Protocol => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +253,7 @@ impl<'db> ClassBase<'db> {
|
||||||
.try_mro(db, specialization)
|
.try_mro(db, specialization)
|
||||||
.is_err_and(MroError::is_cycle)
|
.is_err_and(MroError::is_cycle)
|
||||||
}
|
}
|
||||||
ClassBase::Dynamic(_) | ClassBase::Generic(_) | ClassBase::Protocol(_) => false,
|
ClassBase::Dynamic(_) | ClassBase::Generic | ClassBase::Protocol => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,12 +264,8 @@ impl<'db> ClassBase<'db> {
|
||||||
additional_specialization: Option<Specialization<'db>>,
|
additional_specialization: Option<Specialization<'db>>,
|
||||||
) -> impl Iterator<Item = ClassBase<'db>> {
|
) -> impl Iterator<Item = ClassBase<'db>> {
|
||||||
match self {
|
match self {
|
||||||
ClassBase::Protocol(context) => {
|
ClassBase::Protocol => ClassBaseMroIterator::length_3(db, self, ClassBase::Generic),
|
||||||
ClassBaseMroIterator::length_3(db, self, ClassBase::Generic(context))
|
ClassBase::Dynamic(_) | ClassBase::Generic => ClassBaseMroIterator::length_2(db, self),
|
||||||
}
|
|
||||||
ClassBase::Dynamic(_) | ClassBase::Generic(_) => {
|
|
||||||
ClassBaseMroIterator::length_2(db, self)
|
|
||||||
}
|
|
||||||
ClassBase::Class(class) => {
|
ClassBase::Class(class) => {
|
||||||
ClassBaseMroIterator::from_class(db, class, additional_specialization)
|
ClassBaseMroIterator::from_class(db, class, additional_specialization)
|
||||||
}
|
}
|
||||||
|
@ -338,12 +288,8 @@ impl<'db> From<ClassBase<'db>> for Type<'db> {
|
||||||
match value {
|
match value {
|
||||||
ClassBase::Dynamic(dynamic) => Type::Dynamic(dynamic),
|
ClassBase::Dynamic(dynamic) => Type::Dynamic(dynamic),
|
||||||
ClassBase::Class(class) => class.into(),
|
ClassBase::Class(class) => class.into(),
|
||||||
ClassBase::Protocol(generic_context) => {
|
ClassBase::Protocol => Type::KnownInstance(KnownInstanceType::Protocol(None)),
|
||||||
Type::KnownInstance(KnownInstanceType::Protocol(generic_context))
|
ClassBase::Generic => Type::KnownInstance(KnownInstanceType::Generic(None)),
|
||||||
}
|
|
||||||
ClassBase::Generic(generic_context) => {
|
|
||||||
Type::KnownInstance(KnownInstanceType::Generic(generic_context))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ use crate::types::string_annotation::{
|
||||||
};
|
};
|
||||||
use crate::types::{KnownFunction, KnownInstanceType, Type, protocol_class::ProtocolClassLiteral};
|
use crate::types::{KnownFunction, KnownInstanceType, Type, protocol_class::ProtocolClassLiteral};
|
||||||
use crate::{Program, PythonVersionWithSource, declare_lint};
|
use crate::{Program, PythonVersionWithSource, declare_lint};
|
||||||
|
use itertools::Itertools;
|
||||||
use ruff_db::diagnostic::{Annotation, Diagnostic, Severity, Span, SubDiagnostic};
|
use ruff_db::diagnostic::{Annotation, Diagnostic, Severity, Span, SubDiagnostic};
|
||||||
use ruff_db::files::system_path_to_file;
|
use ruff_db::files::system_path_to_file;
|
||||||
use ruff_python_ast::{self as ast, AnyNodeRef};
|
use ruff_python_ast::{self as ast, AnyNodeRef};
|
||||||
|
@ -1698,10 +1699,7 @@ pub(super) fn report_implicit_return_type(
|
||||||
let Some(class) = enclosing_class_of_method else {
|
let Some(class) = enclosing_class_of_method else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if class
|
if class.iter_mro(db, None).contains(&ClassBase::Protocol) {
|
||||||
.iter_mro(db, None)
|
|
||||||
.any(|base| matches!(base, ClassBase::Protocol(_)))
|
|
||||||
{
|
|
||||||
diagnostic.info(
|
diagnostic.info(
|
||||||
"Only functions in stub files, methods on protocol classes, \
|
"Only functions in stub files, methods on protocol classes, \
|
||||||
or methods with `@abstractmethod` are permitted to have empty bodies",
|
or methods with `@abstractmethod` are permitted to have empty bodies",
|
||||||
|
|
|
@ -7529,7 +7529,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
if !value_ty.into_class_literal().is_some_and(|class| {
|
if !value_ty.into_class_literal().is_some_and(|class| {
|
||||||
class
|
class
|
||||||
.iter_mro(self.db(), None)
|
.iter_mro(self.db(), None)
|
||||||
.any(|base| matches!(base, ClassBase::Generic(_)))
|
.contains(&ClassBase::Generic)
|
||||||
}) {
|
}) {
|
||||||
report_non_subscriptable(
|
report_non_subscriptable(
|
||||||
&self.context,
|
&self.context,
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rustc_hash::FxBuildHasher;
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
use crate::types::class_base::ClassBase;
|
use crate::types::class_base::ClassBase;
|
||||||
use crate::types::generics::Specialization;
|
use crate::types::generics::Specialization;
|
||||||
use crate::types::{ClassLiteral, ClassType, Type};
|
use crate::types::{ClassLiteral, ClassType, KnownInstanceType, Type};
|
||||||
|
|
||||||
/// The inferred method resolution order of a given class.
|
/// The inferred method resolution order of a given class.
|
||||||
///
|
///
|
||||||
|
@ -48,12 +48,12 @@ impl<'db> Mro<'db> {
|
||||||
/// [`super::infer::TypeInferenceBuilder::infer_region_scope`].)
|
/// [`super::infer::TypeInferenceBuilder::infer_region_scope`].)
|
||||||
pub(super) fn of_class(
|
pub(super) fn of_class(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
class: ClassLiteral<'db>,
|
class_literal: ClassLiteral<'db>,
|
||||||
specialization: Option<Specialization<'db>>,
|
specialization: Option<Specialization<'db>>,
|
||||||
) -> Result<Self, MroError<'db>> {
|
) -> Result<Self, MroError<'db>> {
|
||||||
Self::of_class_impl(db, class, specialization).map_err(|err| {
|
let class = class_literal.apply_optional_specialization(db, specialization);
|
||||||
err.into_mro_error(db, class.apply_optional_specialization(db, specialization))
|
Self::of_class_impl(db, class, class_literal.explicit_bases(db), specialization)
|
||||||
})
|
.map_err(|err| err.into_mro_error(db, class))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn from_error(db: &'db dyn Db, class: ClassType<'db>) -> Self {
|
pub(super) fn from_error(db: &'db dyn Db, class: ClassType<'db>) -> Self {
|
||||||
|
@ -66,17 +66,16 @@ impl<'db> Mro<'db> {
|
||||||
|
|
||||||
fn of_class_impl(
|
fn of_class_impl(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
class: ClassLiteral<'db>,
|
class: ClassType<'db>,
|
||||||
|
bases: &[Type<'db>],
|
||||||
specialization: Option<Specialization<'db>>,
|
specialization: Option<Specialization<'db>>,
|
||||||
) -> Result<Self, MroErrorKind<'db>> {
|
) -> Result<Self, MroErrorKind<'db>> {
|
||||||
let class_type = class.apply_optional_specialization(db, specialization);
|
match bases {
|
||||||
|
|
||||||
match class.explicit_bases(db) {
|
|
||||||
// `builtins.object` is the special case:
|
// `builtins.object` is the special case:
|
||||||
// the only class in Python that has an MRO with length <2
|
// the only class in Python that has an MRO with length <2
|
||||||
[] if class.is_object(db) => Ok(Self::from([
|
[] if class.is_object(db) => Ok(Self::from([
|
||||||
// object is not generic, so the default specialization should be a no-op
|
// object is not generic, so the default specialization should be a no-op
|
||||||
ClassBase::Class(class_type),
|
ClassBase::Class(class),
|
||||||
])),
|
])),
|
||||||
|
|
||||||
// All other classes in Python have an MRO with length >=2.
|
// All other classes in Python have an MRO with length >=2.
|
||||||
|
@ -92,44 +91,82 @@ impl<'db> Mro<'db> {
|
||||||
// >>> Foo.__mro__
|
// >>> Foo.__mro__
|
||||||
// (<class '__main__.Foo'>, <class 'object'>)
|
// (<class '__main__.Foo'>, <class 'object'>)
|
||||||
// ```
|
// ```
|
||||||
[] => Ok(Self::from([
|
[] => {
|
||||||
ClassBase::Class(class_type),
|
// e.g. `class Foo[T]: ...` implicitly has `Generic` inserted into its bases
|
||||||
ClassBase::object(db),
|
if class.is_generic() {
|
||||||
])),
|
Ok(Self::from([
|
||||||
|
ClassBase::Class(class),
|
||||||
|
ClassBase::Generic,
|
||||||
|
ClassBase::object(db),
|
||||||
|
]))
|
||||||
|
} else {
|
||||||
|
Ok(Self::from([ClassBase::Class(class), ClassBase::object(db)]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fast path for a class that has only a single explicit base.
|
// Fast path for a class that has only a single explicit base.
|
||||||
//
|
//
|
||||||
// This *could* theoretically be handled by the final branch below,
|
// This *could* theoretically be handled by the final branch below,
|
||||||
// but it's a common case (i.e., worth optimizing for),
|
// but it's a common case (i.e., worth optimizing for),
|
||||||
// and the `c3_merge` function requires lots of allocations.
|
// and the `c3_merge` function requires lots of allocations.
|
||||||
[single_base] => ClassBase::try_from_type(db, *single_base).map_or_else(
|
[single_base]
|
||||||
|| Err(MroErrorKind::InvalidBases(Box::from([(0, *single_base)]))),
|
if !matches!(
|
||||||
|single_base| {
|
single_base,
|
||||||
if single_base.has_cyclic_mro(db) {
|
Type::GenericAlias(_)
|
||||||
Err(MroErrorKind::InheritanceCycle)
|
| Type::KnownInstance(
|
||||||
} else {
|
KnownInstanceType::Generic(_) | KnownInstanceType::Protocol(_)
|
||||||
Ok(std::iter::once(ClassBase::Class(
|
)
|
||||||
class.apply_optional_specialization(db, specialization),
|
) =>
|
||||||
))
|
{
|
||||||
.chain(single_base.mro(db, specialization))
|
ClassBase::try_from_type(db, *single_base).map_or_else(
|
||||||
.collect())
|
|| Err(MroErrorKind::InvalidBases(Box::from([(0, *single_base)]))),
|
||||||
}
|
|single_base| {
|
||||||
},
|
if single_base.has_cyclic_mro(db) {
|
||||||
),
|
Err(MroErrorKind::InheritanceCycle)
|
||||||
|
} else {
|
||||||
|
Ok(std::iter::once(ClassBase::Class(class))
|
||||||
|
.chain(single_base.mro(db, specialization))
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// The class has multiple explicit bases.
|
// The class has multiple explicit bases.
|
||||||
//
|
//
|
||||||
// We'll fallback to a full implementation of the C3-merge algorithm to determine
|
// We'll fallback to a full implementation of the C3-merge algorithm to determine
|
||||||
// what MRO Python will give this class at runtime
|
// what MRO Python will give this class at runtime
|
||||||
// (if an MRO is indeed resolvable at all!)
|
// (if an MRO is indeed resolvable at all!)
|
||||||
multiple_bases => {
|
original_bases => {
|
||||||
let mut valid_bases = vec![];
|
let mut resolved_bases = vec![];
|
||||||
let mut invalid_bases = vec![];
|
let mut invalid_bases = vec![];
|
||||||
|
|
||||||
for (i, base) in multiple_bases.iter().enumerate() {
|
for (i, base) in original_bases.iter().enumerate() {
|
||||||
match ClassBase::try_from_type(db, *base) {
|
// This emulates the behavior of `typing._GenericAlias.__mro_entries__` at
|
||||||
Some(valid_base) => valid_bases.push(valid_base),
|
// <https://github.com/python/cpython/blob/ad42dc1909bdf8ec775b63fb22ed48ff42797a17/Lib/typing.py#L1487-L1500>.
|
||||||
None => invalid_bases.push((i, *base)),
|
//
|
||||||
|
// Note that emit a diagnostic for inheriting from bare (unsubscripted) `Generic` elsewhere
|
||||||
|
// (see `infer::TypeInferenceBuilder::check_class_definitions`),
|
||||||
|
// which is why we only care about `KnownInstanceType::Generic(Some(_))`,
|
||||||
|
// not `KnownInstanceType::Generic(None)`.
|
||||||
|
if let Type::KnownInstance(KnownInstanceType::Generic(Some(_))) = base {
|
||||||
|
if original_bases
|
||||||
|
.contains(&Type::KnownInstance(KnownInstanceType::Protocol(None)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if original_bases[i + 1..]
|
||||||
|
.iter()
|
||||||
|
.any(|b| b.is_generic_alias() && b != base)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
resolved_bases.push(ClassBase::Generic);
|
||||||
|
} else {
|
||||||
|
match ClassBase::try_from_type(db, *base) {
|
||||||
|
Some(valid_base) => resolved_bases.push(valid_base),
|
||||||
|
None => invalid_bases.push((i, *base)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,15 +174,15 @@ impl<'db> Mro<'db> {
|
||||||
return Err(MroErrorKind::InvalidBases(invalid_bases.into_boxed_slice()));
|
return Err(MroErrorKind::InvalidBases(invalid_bases.into_boxed_slice()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut seqs = vec![VecDeque::from([ClassBase::Class(class_type)])];
|
let mut seqs = vec![VecDeque::from([ClassBase::Class(class)])];
|
||||||
for base in &valid_bases {
|
for base in &resolved_bases {
|
||||||
if base.has_cyclic_mro(db) {
|
if base.has_cyclic_mro(db) {
|
||||||
return Err(MroErrorKind::InheritanceCycle);
|
return Err(MroErrorKind::InheritanceCycle);
|
||||||
}
|
}
|
||||||
seqs.push(base.mro(db, specialization).collect());
|
seqs.push(base.mro(db, specialization).collect());
|
||||||
}
|
}
|
||||||
seqs.push(
|
seqs.push(
|
||||||
valid_bases
|
resolved_bases
|
||||||
.iter()
|
.iter()
|
||||||
.map(|base| base.apply_optional_specialization(db, specialization))
|
.map(|base| base.apply_optional_specialization(db, specialization))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -161,8 +198,20 @@ impl<'db> Mro<'db> {
|
||||||
let mut base_to_indices: IndexMap<ClassBase<'db>, Vec<usize>, FxBuildHasher> =
|
let mut base_to_indices: IndexMap<ClassBase<'db>, Vec<usize>, FxBuildHasher> =
|
||||||
IndexMap::default();
|
IndexMap::default();
|
||||||
|
|
||||||
for (index, base) in valid_bases.iter().enumerate() {
|
// We need to iterate over `original_bases` here rather than `resolved_bases`
|
||||||
base_to_indices.entry(*base).or_default().push(index);
|
// so that we get the correct index of the duplicate bases if there were any
|
||||||
|
// (`resolved_bases` may be a longer list than `original_bases`!). However, we
|
||||||
|
// need to use a `ClassBase` rather than a `Type` as the key type for the
|
||||||
|
// `base_to_indices` map so that a class such as
|
||||||
|
// `class Foo(Protocol[T], Protocol): ...` correctly causes us to emit a
|
||||||
|
// `duplicate-base` diagnostic (matching the runtime behaviour) rather than an
|
||||||
|
// `inconsistent-mro` diagnostic (which would be accurate -- but not nearly as
|
||||||
|
// precise!).
|
||||||
|
for (index, base) in original_bases.iter().enumerate() {
|
||||||
|
let Some(base) = ClassBase::try_from_type(db, *base) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
base_to_indices.entry(base).or_default().push(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut errors = vec![];
|
let mut errors = vec![];
|
||||||
|
@ -175,9 +224,7 @@ impl<'db> Mro<'db> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match base {
|
match base {
|
||||||
ClassBase::Class(_)
|
ClassBase::Class(_) | ClassBase::Generic | ClassBase::Protocol => {
|
||||||
| ClassBase::Generic(_)
|
|
||||||
| ClassBase::Protocol(_) => {
|
|
||||||
errors.push(DuplicateBaseError {
|
errors.push(DuplicateBaseError {
|
||||||
duplicate_base: base,
|
duplicate_base: base,
|
||||||
first_index: *first_index,
|
first_index: *first_index,
|
||||||
|
@ -193,13 +240,10 @@ impl<'db> Mro<'db> {
|
||||||
|
|
||||||
if duplicate_bases.is_empty() {
|
if duplicate_bases.is_empty() {
|
||||||
if duplicate_dynamic_bases {
|
if duplicate_dynamic_bases {
|
||||||
Ok(Mro::from_error(
|
Ok(Mro::from_error(db, class))
|
||||||
db,
|
|
||||||
class.apply_optional_specialization(db, specialization),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Err(MroErrorKind::UnresolvableMro {
|
Err(MroErrorKind::UnresolvableMro {
|
||||||
bases_list: valid_bases.into_boxed_slice(),
|
bases_list: original_bases.iter().copied().collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -378,7 +422,7 @@ pub(super) enum MroErrorKind<'db> {
|
||||||
/// The MRO is otherwise unresolvable through the C3-merge algorithm.
|
/// The MRO is otherwise unresolvable through the C3-merge algorithm.
|
||||||
///
|
///
|
||||||
/// See [`c3_merge`] for more details.
|
/// See [`c3_merge`] for more details.
|
||||||
UnresolvableMro { bases_list: Box<[ClassBase<'db>]> },
|
UnresolvableMro { bases_list: Box<[Type<'db>]> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> MroErrorKind<'db> {
|
impl<'db> MroErrorKind<'db> {
|
||||||
|
|
|
@ -152,13 +152,11 @@ pub(super) fn union_or_intersection_elements_ordering<'db>(
|
||||||
(ClassBase::Class(_), _) => Ordering::Less,
|
(ClassBase::Class(_), _) => Ordering::Less,
|
||||||
(_, ClassBase::Class(_)) => Ordering::Greater,
|
(_, ClassBase::Class(_)) => Ordering::Greater,
|
||||||
|
|
||||||
(ClassBase::Protocol(left), ClassBase::Protocol(right)) => left.cmp(&right),
|
(ClassBase::Protocol, _) => Ordering::Less,
|
||||||
(ClassBase::Protocol(_), _) => Ordering::Less,
|
(_, ClassBase::Protocol) => Ordering::Greater,
|
||||||
(_, ClassBase::Protocol(_)) => Ordering::Greater,
|
|
||||||
|
|
||||||
(ClassBase::Generic(left), ClassBase::Generic(right)) => left.cmp(&right),
|
(ClassBase::Generic, _) => Ordering::Less,
|
||||||
(ClassBase::Generic(_), _) => Ordering::Less,
|
(_, ClassBase::Generic) => Ordering::Greater,
|
||||||
(_, ClassBase::Generic(_)) => Ordering::Greater,
|
|
||||||
|
|
||||||
(ClassBase::Dynamic(left), ClassBase::Dynamic(right)) => {
|
(ClassBase::Dynamic(left), ClassBase::Dynamic(right)) => {
|
||||||
dynamic_elements_ordering(left, right)
|
dynamic_elements_ordering(left, right)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue