[ty] Improve diagnostics for unsupported comparison operations (#21737)

This commit is contained in:
Alex Waygood 2025-12-02 19:58:45 +00:00 committed by GitHub
parent 515de2d062
commit 392a8e4e50
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 873 additions and 192 deletions

148
crates/ty/docs/rules.md generated
View File

@ -39,7 +39,7 @@ def test(): -> "int":
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L135" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L137" target="_blank">View source</a>
</small>
@ -63,7 +63,7 @@ Calling a non-callable object will raise a `TypeError` at runtime.
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L179" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L181" target="_blank">View source</a>
</small>
@ -95,7 +95,7 @@ f(int) # error
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L205" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L207" target="_blank">View source</a>
</small>
@ -126,7 +126,7 @@ a = 1
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L230" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L232" target="_blank">View source</a>
</small>
@ -158,7 +158,7 @@ class C(A, B): ...
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L256" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L258" target="_blank">View source</a>
</small>
@ -190,7 +190,7 @@ class B(A): ...
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/1.0.0">1.0.0</a>) ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-type-alias-definition" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L282" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L284" target="_blank">View source</a>
</small>
@ -218,7 +218,7 @@ type B = A
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L343" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L345" target="_blank">View source</a>
</small>
@ -245,7 +245,7 @@ class B(A, A): ...
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.12">0.0.1-alpha.12</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-kw-only" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L364" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L366" target="_blank">View source</a>
</small>
@ -357,7 +357,7 @@ def test(): -> "Literal[5]":
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L590" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L592" target="_blank">View source</a>
</small>
@ -387,7 +387,7 @@ class C(A, B): ...
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L614" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L616" target="_blank">View source</a>
</small>
@ -413,7 +413,7 @@ t[3] # IndexError: tuple index out of range
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.12">0.0.1-alpha.12</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20instance-layout-conflict" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L396" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L398" target="_blank">View source</a>
</small>
@ -502,7 +502,7 @@ an atypical memory layout.
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L668" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L670" target="_blank">View source</a>
</small>
@ -529,7 +529,7 @@ func("foo") # error: [invalid-argument-type]
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L708" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L710" target="_blank">View source</a>
</small>
@ -557,7 +557,7 @@ a: int = ''
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1998" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2000" target="_blank">View source</a>
</small>
@ -591,7 +591,7 @@ C.instance_var = 3 # error: Cannot assign to instance variable
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.19">0.0.1-alpha.19</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-await" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L730" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L732" target="_blank">View source</a>
</small>
@ -627,7 +627,7 @@ asyncio.run(main())
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L760" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L762" target="_blank">View source</a>
</small>
@ -651,7 +651,7 @@ class A(42): ... # error: [invalid-base]
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L811" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L813" target="_blank">View source</a>
</small>
@ -678,7 +678,7 @@ with 1:
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L832" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L834" target="_blank">View source</a>
</small>
@ -707,7 +707,7 @@ a: str
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L855" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L857" target="_blank">View source</a>
</small>
@ -751,7 +751,7 @@ except ZeroDivisionError:
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.28">0.0.1-alpha.28</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-explicit-override" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1668" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1670" target="_blank">View source</a>
</small>
@ -793,7 +793,7 @@ class D(A):
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L891" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L893" target="_blank">View source</a>
</small>
@ -826,7 +826,7 @@ class C[U](Generic[T]): ...
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.17">0.0.1-alpha.17</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-key" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L635" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L637" target="_blank">View source</a>
</small>
@ -865,7 +865,7 @@ carol = Person(name="Carol", age=25) # typo!
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L917" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L919" target="_blank">View source</a>
</small>
@ -900,7 +900,7 @@ def f(t: TypeVar("U")): ...
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1014" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1016" target="_blank">View source</a>
</small>
@ -934,7 +934,7 @@ class B(metaclass=f): ...
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-method-override" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2126" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2128" target="_blank">View source</a>
</small>
@ -1041,7 +1041,7 @@ Correct use of `@override` is enforced by ty's `invalid-explicit-override` rule.
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.19">0.0.1-alpha.19</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-named-tuple" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L542" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L544" target="_blank">View source</a>
</small>
@ -1095,7 +1095,7 @@ AttributeError: Cannot overwrite NamedTuple attribute _asdict
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/1.0.0">1.0.0</a>) ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-newtype" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L990" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L992" target="_blank">View source</a>
</small>
@ -1125,7 +1125,7 @@ Baz = NewType("Baz", int | str) # error: invalid base for `typing.NewType`
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1041" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1043" target="_blank">View source</a>
</small>
@ -1175,7 +1175,7 @@ def foo(x: int) -> int: ...
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1140" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1142" target="_blank">View source</a>
</small>
@ -1201,7 +1201,7 @@ def f(a: int = ''): ...
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-paramspec" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L945" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L947" target="_blank">View source</a>
</small>
@ -1232,7 +1232,7 @@ P2 = ParamSpec("S2") # error: ParamSpec name must match the variable it's assig
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L478" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L480" target="_blank">View source</a>
</small>
@ -1266,7 +1266,7 @@ TypeError: Protocols can only inherit from other protocols, got <class 'int'>
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1160" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1162" target="_blank">View source</a>
</small>
@ -1315,7 +1315,7 @@ def g():
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L689" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L691" target="_blank">View source</a>
</small>
@ -1340,7 +1340,7 @@ def func() -> int:
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1203" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1205" target="_blank">View source</a>
</small>
@ -1398,7 +1398,7 @@ TODO #14889
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.6">0.0.1-alpha.6</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L969" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L971" target="_blank">View source</a>
</small>
@ -1425,7 +1425,7 @@ NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name mus
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.29">0.0.1-alpha.29</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-arguments" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1435" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1437" target="_blank">View source</a>
</small>
@ -1472,7 +1472,7 @@ Bar[int] # error: too few arguments
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1242" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1244" target="_blank">View source</a>
</small>
@ -1502,7 +1502,7 @@ TYPE_CHECKING = ''
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1266" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1268" target="_blank">View source</a>
</small>
@ -1532,7 +1532,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.11">0.0.1-alpha.11</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-call" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1318" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1320" target="_blank">View source</a>
</small>
@ -1566,7 +1566,7 @@ f(10) # Error
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.11">0.0.1-alpha.11</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-definition" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1290" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1292" target="_blank">View source</a>
</small>
@ -1600,7 +1600,7 @@ class C:
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1346" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1348" target="_blank">View source</a>
</small>
@ -1635,7 +1635,7 @@ T = TypeVar('T', bound=str) # valid bound TypeVar
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1375" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1377" target="_blank">View source</a>
</small>
@ -1660,7 +1660,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-typed-dict-key" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2099" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2101" target="_blank">View source</a>
</small>
@ -1693,7 +1693,7 @@ alice["age"] # KeyError
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1394" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1396" target="_blank">View source</a>
</small>
@ -1722,7 +1722,7 @@ func("string") # error: [no-matching-overload]
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1417" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1419" target="_blank">View source</a>
</small>
@ -1746,7 +1746,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1476" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1478" target="_blank">View source</a>
</small>
@ -1772,7 +1772,7 @@ for i in 34: # TypeError: 'int' object is not iterable
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.29">0.0.1-alpha.29</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20override-of-final-method" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1641" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1643" target="_blank">View source</a>
</small>
@ -1805,7 +1805,7 @@ class B(A):
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1527" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1529" target="_blank">View source</a>
</small>
@ -1832,7 +1832,7 @@ f(1, x=2) # Error raised here
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20positional-only-parameter-as-kwarg" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1852" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1854" target="_blank">View source</a>
</small>
@ -1890,7 +1890,7 @@ def test(): -> "int":
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1974" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1976" target="_blank">View source</a>
</small>
@ -1920,7 +1920,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1618" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1620" target="_blank">View source</a>
</small>
@ -1949,7 +1949,7 @@ class B(A): ... # Error raised here
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.30">0.0.1-alpha.30</a>) ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20super-call-in-named-tuple-method" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1786" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1788" target="_blank">View source</a>
</small>
@ -1983,7 +1983,7 @@ class F(NamedTuple):
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1726" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1728" target="_blank">View source</a>
</small>
@ -2010,7 +2010,7 @@ f("foo") # Error raised here
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1704" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1706" target="_blank">View source</a>
</small>
@ -2038,7 +2038,7 @@ def _(x: int):
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1747" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1749" target="_blank">View source</a>
</small>
@ -2084,7 +2084,7 @@ class A:
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1831" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1833" target="_blank">View source</a>
</small>
@ -2111,7 +2111,7 @@ f(x=1, y=2) # Error raised here
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1873" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1875" target="_blank">View source</a>
</small>
@ -2139,7 +2139,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo'
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1895" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1897" target="_blank">View source</a>
</small>
@ -2164,7 +2164,7 @@ import foo # ModuleNotFoundError: No module named 'foo'
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1914" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1916" target="_blank">View source</a>
</small>
@ -2189,7 +2189,7 @@ print(x) # NameError: name 'x' is not defined
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1496" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1498" target="_blank">View source</a>
</small>
@ -2226,7 +2226,7 @@ b1 < b2 < b1 # exception raised here
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1933" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1935" target="_blank">View source</a>
</small>
@ -2254,7 +2254,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1955" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1957" target="_blank">View source</a>
</small>
@ -2279,7 +2279,7 @@ l[1:10:0] # ValueError: slice step cannot be zero
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20ambiguous-protocol-member" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L507" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L509" target="_blank">View source</a>
</small>
@ -2320,7 +2320,7 @@ class SubProto(BaseProto, Protocol):
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.16">0.0.1-alpha.16</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20deprecated" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L322" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L324" target="_blank">View source</a>
</small>
@ -2408,7 +2408,7 @@ a = 20 / 0 # type: ignore
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-attribute" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1548" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1550" target="_blank">View source</a>
</small>
@ -2436,7 +2436,7 @@ A.c # AttributeError: type object 'A' has no attribute 'c'
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-implicit-call" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L153" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L155" target="_blank">View source</a>
</small>
@ -2468,7 +2468,7 @@ A()[0] # TypeError: 'A' object is not subscriptable
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-import" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1570" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1572" target="_blank">View source</a>
</small>
@ -2500,7 +2500,7 @@ from module import a # ImportError: cannot import name 'a' from 'module'
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2026" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2028" target="_blank">View source</a>
</small>
@ -2527,7 +2527,7 @@ cast(int, f()) # Redundant
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1813" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1815" target="_blank">View source</a>
</small>
@ -2551,7 +2551,7 @@ reveal_type(1) # NameError: name 'reveal_type' is not defined
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.15">0.0.1-alpha.15</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-global" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2047" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2049" target="_blank">View source</a>
</small>
@ -2609,7 +2609,7 @@ def g():
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.7">0.0.1-alpha.7</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-base" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L778" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L780" target="_blank">View source</a>
</small>
@ -2648,7 +2648,7 @@ class D(C): ... # error: [unsupported-base]
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20useless-overload-body" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1084" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1086" target="_blank">View source</a>
</small>
@ -2711,7 +2711,7 @@ def foo(x: int | str) -> int | str:
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a>) ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L304" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L306" target="_blank">View source</a>
</small>
@ -2735,7 +2735,7 @@ Dividing by zero raises a `ZeroDivisionError` at runtime.
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1596" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1598" target="_blank">View source</a>
</small>

View File

@ -340,7 +340,7 @@ def _(a: object, b: object, flag: bool):
else:
x = g
# error: [unsupported-operator] "Operator `>` is not supported for types `object` and `object`"
# error: [unsupported-operator] "Operator `>` is not supported between two objects of type `object`"
x(f"{'a' if a > b else 'b'}")
```

View File

@ -392,7 +392,7 @@ reveal_type(A - B) # revealed: Unknown
reveal_type(A < B) # revealed: bool
reveal_type(A > B) # revealed: bool
# error: [unsupported-operator] "Operator `<=` is not supported for types `<class 'A'>` and `<class 'B'>`"
# error: [unsupported-operator] "Operator `<=` is not supported between objects of type `<class 'A'>` and `<class 'B'>`"
reveal_type(A <= B) # revealed: Unknown
reveal_type(A[0]) # revealed: str

View File

@ -21,9 +21,9 @@ class A:
reveal_type("hello" in A()) # revealed: bool
reveal_type("hello" not in A()) # revealed: bool
# error: [unsupported-operator] "Operator `in` is not supported for types `int` and `A`, in comparing `Literal[42]` with `A`"
# error: [unsupported-operator] "Operator `in` is not supported between objects of type `Literal[42]` and `A`"
reveal_type(42 in A()) # revealed: bool
# error: [unsupported-operator] "Operator `not in` is not supported for types `int` and `A`, in comparing `Literal[42]` with `A`"
# error: [unsupported-operator] "Operator `not in` is not supported between objects of type `Literal[42]` and `A`"
reveal_type(42 not in A()) # revealed: bool
```
@ -127,9 +127,9 @@ class A:
reveal_type(CheckContains() in A()) # revealed: bool
# error: [unsupported-operator] "Operator `in` is not supported for types `CheckIter` and `A`"
# error: [unsupported-operator] "Operator `in` is not supported between objects of type `CheckIter` and `A`"
reveal_type(CheckIter() in A()) # revealed: bool
# error: [unsupported-operator] "Operator `in` is not supported for types `CheckGetItem` and `A`"
# error: [unsupported-operator] "Operator `in` is not supported between objects of type `CheckGetItem` and `A`"
reveal_type(CheckGetItem() in A()) # revealed: bool
class B:
@ -155,9 +155,9 @@ class A:
def __getitem__(self, key: str) -> str:
return "foo"
# error: [unsupported-operator] "Operator `in` is not supported for types `int` and `A`, in comparing `Literal[42]` with `A`"
# error: [unsupported-operator] "Operator `in` is not supported between objects of type `Literal[42]` and `A`"
reveal_type(42 in A()) # revealed: bool
# error: [unsupported-operator] "Operator `in` is not supported for types `str` and `A`, in comparing `Literal["hello"]` with `A`"
# error: [unsupported-operator] "Operator `in` is not supported between objects of type `Literal["hello"]` and `A`"
reveal_type("hello" in A()) # revealed: bool
```

View File

@ -309,7 +309,7 @@ reveal_type(A() != object()) # revealed: bool
reveal_type(object() == A()) # revealed: bool
reveal_type(object() != A()) # revealed: bool
# error: [unsupported-operator] "Operator `<` is not supported for types `A` and `object`"
# error: [unsupported-operator] "Operator `<` is not supported between objects of type `A` and `object`"
# revealed: Unknown
reveal_type(A() < object())
```
@ -327,13 +327,13 @@ reveal_type(1 >= 1.0) # revealed: bool
reveal_type(1 == 2j) # revealed: bool
reveal_type(1 != 2j) # revealed: bool
# error: [unsupported-operator] "Operator `<` is not supported for types `int` and `complex`, in comparing `Literal[1]` with `complex`"
# error: [unsupported-operator] "Operator `<` is not supported between objects of type `Literal[1]` and `complex`"
reveal_type(1 < 2j) # revealed: Unknown
# error: [unsupported-operator] "Operator `<=` is not supported for types `int` and `complex`, in comparing `Literal[1]` with `complex`"
# error: [unsupported-operator] "Operator `<=` is not supported between objects of type `Literal[1]` and `complex`"
reveal_type(1 <= 2j) # revealed: Unknown
# error: [unsupported-operator] "Operator `>` is not supported for types `int` and `complex`, in comparing `Literal[1]` with `complex`"
# error: [unsupported-operator] "Operator `>` is not supported between objects of type `Literal[1]` and `complex`"
reveal_type(1 > 2j) # revealed: Unknown
# error: [unsupported-operator] "Operator `>=` is not supported for types `int` and `complex`, in comparing `Literal[1]` with `complex`"
# error: [unsupported-operator] "Operator `>=` is not supported between objects of type `Literal[1]` and `complex`"
reveal_type(1 >= 2j) # revealed: Unknown
def f(x: bool, y: int):
@ -386,3 +386,29 @@ reveal_type(A() == A()) # revealed: Literal[True]
reveal_type(A() < A()) # revealed: Literal[True]
reveal_type(A() > A()) # revealed: Literal[True]
```
## Diagnostics where classes have the same name
We use the fully qualified names of classes to disambiguate them where necessary:
`a.py`:
```py
class Foo: ...
```
`b.py`:
```py
class Foo: ...
```
`main.py`:
```py
import a
import b
# error: [unsupported-operator] "Operator `<` is not supported between objects of type `a.Foo` and `b.Foo`"
a.Foo() < b.Foo()
```

View File

@ -12,7 +12,7 @@ reveal_type(1 is 1) # revealed: bool
reveal_type(1 is not 1) # revealed: bool
reveal_type(1 is 2) # revealed: Literal[False]
reveal_type(1 is not 7) # revealed: Literal[True]
# error: [unsupported-operator] "Operator `<=` is not supported for types `int` and `str`, in comparing `Literal[1]` with `Literal[""]`"
# error: [unsupported-operator] "Operator `<=` is not supported between objects of type `Literal[1]` and `Literal[""]`"
reveal_type(1 <= "" and 0 < 1) # revealed: (Unknown & ~AlwaysTruthy) | Literal[True]
```

View File

@ -109,6 +109,8 @@ def _(o: object):
### Unsupported operators for positive contributions
<!-- snapshot-diagnostics -->
Raise an error if the given operator is unsupported for all positive contributions to the
intersection type:
@ -121,7 +123,7 @@ def _(x: object):
if isinstance(x, NonContainer2):
reveal_type(x) # revealed: NonContainer1 & NonContainer2
# error: [unsupported-operator] "Operator `in` is not supported for types `int` and `NonContainer1`"
# error: [unsupported-operator] "Operator `in` is not supported between objects of type `Literal[2]` and `NonContainer1 & NonContainer2`"
reveal_type(2 in x) # revealed: bool
```
@ -149,7 +151,7 @@ def _(x: object):
if not isinstance(x, NonContainer1):
reveal_type(x) # revealed: ~NonContainer1
# error: [unsupported-operator] "Operator `in` is not supported for types `int` and `object`, in comparing `Literal[2]` with `~NonContainer1`"
# error: [unsupported-operator] "Operator `in` is not supported between objects of type `Literal[2]` and `~NonContainer1`"
reveal_type(2 in x) # revealed: bool
reveal_type(2 is x) # revealed: bool

View File

@ -79,6 +79,8 @@ def _(x: bool, y: int):
#### Comparison Unsupported
<!-- snapshot-diagnostics -->
If two tuples contain types that do not support comparison, the result may be `Unknown`. However,
`==` and `!=` are exceptions and can still provide definite results.
@ -92,14 +94,17 @@ reveal_type(a == b) # revealed: bool
# TODO: should be Literal[True], once we implement (in)equality for mismatched literals
reveal_type(a != b) # revealed: bool
# error: [unsupported-operator] "Operator `<` is not supported for types `int` and `str`, in comparing `tuple[Literal[1], Literal[2]]` with `tuple[Literal[1], Literal["hello"]]`"
# error: [unsupported-operator] "Operator `<` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Literal[1], Literal["hello"]]`"
reveal_type(a < b) # revealed: Unknown
# error: [unsupported-operator] "Operator `<=` is not supported for types `int` and `str`, in comparing `tuple[Literal[1], Literal[2]]` with `tuple[Literal[1], Literal["hello"]]`"
# error: [unsupported-operator] "Operator `<=` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Literal[1], Literal["hello"]]`"
reveal_type(a <= b) # revealed: Unknown
# error: [unsupported-operator] "Operator `>` is not supported for types `int` and `str`, in comparing `tuple[Literal[1], Literal[2]]` with `tuple[Literal[1], Literal["hello"]]`"
# error: [unsupported-operator] "Operator `>` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Literal[1], Literal["hello"]]`"
reveal_type(a > b) # revealed: Unknown
# error: [unsupported-operator] "Operator `>=` is not supported for types `int` and `str`, in comparing `tuple[Literal[1], Literal[2]]` with `tuple[Literal[1], Literal["hello"]]`"
# error: [unsupported-operator] "Operator `>=` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Literal[1], Literal["hello"]]`"
reveal_type(a >= b) # revealed: Unknown
# error: [unsupported-operator]
# error: [unsupported-operator]
reveal_type((object(),) < (object(),) < (object(),)) # revealed: Unknown
```
However, if the lexicographic comparison completes without reaching a point where str and int are
@ -257,24 +262,24 @@ comparison can clearly conclude before encountering an error, the error should n
```py
def _(n: int, s: str):
class A: ...
# error: [unsupported-operator] "Operator `<` is not supported for types `A` and `A`"
# error: [unsupported-operator] "Operator `<` is not supported between two objects of type `A`"
A() < A()
# error: [unsupported-operator] "Operator `<=` is not supported for types `A` and `A`"
# error: [unsupported-operator] "Operator `<=` is not supported between two objects of type `A`"
A() <= A()
# error: [unsupported-operator] "Operator `>` is not supported for types `A` and `A`"
# error: [unsupported-operator] "Operator `>` is not supported between two objects of type `A`"
A() > A()
# error: [unsupported-operator] "Operator `>=` is not supported for types `A` and `A`"
# error: [unsupported-operator] "Operator `>=` is not supported between two objects of type `A`"
A() >= A()
a = (0, n, A())
# error: [unsupported-operator] "Operator `<` is not supported for types `A` and `A`, in comparing `tuple[Literal[0], int, A]` with `tuple[Literal[0], int, A]`"
# error: [unsupported-operator] "Operator `<` is not supported between two objects of type `tuple[Literal[0], int, A]`"
reveal_type(a < a) # revealed: Unknown
# error: [unsupported-operator] "Operator `<=` is not supported for types `A` and `A`, in comparing `tuple[Literal[0], int, A]` with `tuple[Literal[0], int, A]`"
# error: [unsupported-operator] "Operator `<=` is not supported between two objects of type `tuple[Literal[0], int, A]`"
reveal_type(a <= a) # revealed: Unknown
# error: [unsupported-operator] "Operator `>` is not supported for types `A` and `A`, in comparing `tuple[Literal[0], int, A]` with `tuple[Literal[0], int, A]`"
# error: [unsupported-operator] "Operator `>` is not supported between two objects of type `tuple[Literal[0], int, A]`"
reveal_type(a > a) # revealed: Unknown
# error: [unsupported-operator] "Operator `>=` is not supported for types `A` and `A`, in comparing `tuple[Literal[0], int, A]` with `tuple[Literal[0], int, A]`"
# error: [unsupported-operator] "Operator `>=` is not supported between two objects of type `tuple[Literal[0], int, A]`"
reveal_type(a >= a) # revealed: Unknown
# Comparison between `a` and `b` should only involve the first elements, `Literal[0]` and `Literal[99999]`,

View File

@ -66,14 +66,29 @@ def _(flag_s: bool, flag_l: bool):
## Unsupported operations
<!-- snapshot-diagnostics -->
Make sure we emit a diagnostic if *any* of the possible comparisons is unsupported. For now, we fall
back to `bool` for the result type instead of trying to infer something more precise from the other
(supported) variants:
```py
def _(flag: bool):
x = [1, 2] if flag else 1
from typing import Literal
def _(
x: list[int] | Literal[1],
y: list[int] | Literal[1],
aa: tuple[int],
bb: tuple[int] | tuple[int, int],
cc: tuple[str] | tuple[str, str],
):
result = 1 in x # error: "Operator `in` is not supported"
reveal_type(result) # revealed: bool
result2 = y in x # error: [unsupported-operator]
reveal_type(result) # revealed: bool
result3 = aa < cc # error: [unsupported-operator]
result4 = cc < aa # error: [unsupported-operator]
result5 = bb < cc # error: [unsupported-operator]
```

View File

@ -1,32 +1,34 @@
# Comparison: Unsupported operators
<!-- snapshot-diagnostics -->
```py
def _(flag: bool, flag1: bool, flag2: bool):
class A: ...
a = 1 in 7 # error: "Operator `in` is not supported for types `Literal[1]` and `Literal[7]`"
a = 1 in 7 # error: "Operator `in` is not supported between objects of type `Literal[1]` and `Literal[7]`"
reveal_type(a) # revealed: bool
b = 0 not in 10 # error: "Operator `not in` is not supported for types `Literal[0]` and `Literal[10]`"
b = 0 not in 10 # error: "Operator `not in` is not supported between objects of type `Literal[0]` and `Literal[10]`"
reveal_type(b) # revealed: bool
# error: [unsupported-operator] "Operator `<` is not supported for types `object` and `int`, in comparing `object` with `Literal[5]`"
# error: [unsupported-operator] "Operator `<` is not supported between objects of type `object` and `Literal[5]`"
c = object() < 5
reveal_type(c) # revealed: Unknown
# error: [unsupported-operator] "Operator `<` is not supported for types `int` and `object`, in comparing `Literal[5]` with `object`"
# error: [unsupported-operator] "Operator `<` is not supported between objects of type `Literal[5]` and `object`"
d = 5 < object()
reveal_type(d) # revealed: Unknown
int_literal_or_str_literal = 1 if flag else "foo"
# error: "Operator `in` is not supported for types `Literal[42]` and `Literal[1]`, in comparing `Literal[42]` with `Literal[1, "foo"]`"
# error: "Operator `in` is not supported between objects of type `Literal[42]` and `Literal[1, "foo"]`"
e = 42 in int_literal_or_str_literal
reveal_type(e) # revealed: bool
# error: [unsupported-operator] "Operator `<` is not supported for types `int` and `str`, in comparing `tuple[Literal[1], Literal[2]]` with `tuple[Literal[1], Literal["hello"]]`"
# error: [unsupported-operator] "Operator `<` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Literal[1], Literal["hello"]]`"
f = (1, 2) < (1, "hello")
reveal_type(f) # revealed: Unknown
# error: [unsupported-operator] "Operator `<` is not supported for types `A` and `A`, in comparing `tuple[bool, A]` with `tuple[bool, A]`"
# error: [unsupported-operator] "Operator `<` is not supported between two objects of type `tuple[bool, A]`"
g = (flag1, A()) < (flag2, A())
reveal_type(g) # revealed: Unknown
```

View File

@ -0,0 +1,79 @@
---
source: crates/ty_test/src/lib.rs
expression: snapshot
---
---
mdtest name: intersections.md - Comparison: Intersections - Diagnostics - Unsupported operators for positive contributions
mdtest path: crates/ty_python_semantic/resources/mdtest/comparison/intersections.md
---
# Python source files
## mdtest_snippet.py
```
1 | class NonContainer1: ...
2 | class NonContainer2: ...
3 |
4 | def _(x: object):
5 | if isinstance(x, NonContainer1):
6 | if isinstance(x, NonContainer2):
7 | reveal_type(x) # revealed: NonContainer1 & NonContainer2
8 |
9 | # error: [unsupported-operator] "Operator `in` is not supported between objects of type `Literal[2]` and `NonContainer1 & NonContainer2`"
10 | reveal_type(2 in x) # revealed: bool
11 | class Container:
12 | def __contains__(self, x) -> bool:
13 | return False
14 |
15 | def _(x: object):
16 | if isinstance(x, NonContainer1):
17 | if isinstance(x, Container):
18 | if isinstance(x, NonContainer2):
19 | reveal_type(x) # revealed: NonContainer1 & Container & NonContainer2
20 | reveal_type(2 in x) # revealed: bool
21 | def _(x: object):
22 | if not isinstance(x, NonContainer1):
23 | reveal_type(x) # revealed: ~NonContainer1
24 |
25 | # error: [unsupported-operator] "Operator `in` is not supported between objects of type `Literal[2]` and `~NonContainer1`"
26 | reveal_type(2 in x) # revealed: bool
27 |
28 | reveal_type(2 is x) # revealed: bool
```
# Diagnostics
```
error[unsupported-operator]: Unsupported `in` operation
--> src/mdtest_snippet.py:10:25
|
9 | # error: [unsupported-operator] "Operator `in` is not supported between objects of type `Literal[2]` and `NonContainer1 & …
10 | reveal_type(2 in x) # revealed: bool
| -^^^^-
| | |
| | Has type `NonContainer1 & NonContainer2`
| Has type `Literal[2]`
11 | class Container:
12 | def __contains__(self, x) -> bool:
|
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `in` operation
--> src/mdtest_snippet.py:26:21
|
25 | # error: [unsupported-operator] "Operator `in` is not supported between objects of type `Literal[2]` and `~NonContainer1`"
26 | reveal_type(2 in x) # revealed: bool
| -^^^^-
| | |
| | Has type `~NonContainer1`
| Has type `Literal[2]`
27 |
28 | reveal_type(2 is x) # revealed: bool
|
info: rule `unsupported-operator` is enabled by default
```

View File

@ -0,0 +1,157 @@
---
source: crates/ty_test/src/lib.rs
expression: snapshot
---
---
mdtest name: tuples.md - Comparison: Tuples - Heterogeneous - Value Comparisons - Comparison Unsupported
mdtest path: crates/ty_python_semantic/resources/mdtest/comparison/tuples.md
---
# Python source files
## mdtest_snippet.py
```
1 | a = (1, 2)
2 | b = (1, "hello")
3 |
4 | # TODO: should be Literal[False], once we implement (in)equality for mismatched literals
5 | reveal_type(a == b) # revealed: bool
6 |
7 | # TODO: should be Literal[True], once we implement (in)equality for mismatched literals
8 | reveal_type(a != b) # revealed: bool
9 |
10 | # error: [unsupported-operator] "Operator `<` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Literal[1], Literal["hello"]]`"
11 | reveal_type(a < b) # revealed: Unknown
12 | # error: [unsupported-operator] "Operator `<=` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Literal[1], Literal["hello"]]`"
13 | reveal_type(a <= b) # revealed: Unknown
14 | # error: [unsupported-operator] "Operator `>` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Literal[1], Literal["hello"]]`"
15 | reveal_type(a > b) # revealed: Unknown
16 | # error: [unsupported-operator] "Operator `>=` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Literal[1], Literal["hello"]]`"
17 | reveal_type(a >= b) # revealed: Unknown
18 | # error: [unsupported-operator]
19 | # error: [unsupported-operator]
20 | reveal_type((object(),) < (object(),) < (object(),)) # revealed: Unknown
21 | a = (1, 2)
22 | b = (999999, "hello")
23 |
24 | reveal_type(a == b) # revealed: Literal[False]
25 | reveal_type(a != b) # revealed: Literal[True]
26 | reveal_type(a < b) # revealed: Literal[True]
27 | reveal_type(a <= b) # revealed: Literal[True]
28 | reveal_type(a > b) # revealed: Literal[False]
29 | reveal_type(a >= b) # revealed: Literal[False]
```
# Diagnostics
```
error[unsupported-operator]: Unsupported `<` operation
--> src/mdtest_snippet.py:11:13
|
10 | # error: [unsupported-operator] "Operator `<` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Lite…
11 | reveal_type(a < b) # revealed: Unknown
| -^^^-
| | |
| | Has type `tuple[Literal[1], Literal["hello"]]`
| Has type `tuple[Literal[1], Literal[2]]`
12 | # error: [unsupported-operator] "Operator `<=` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Lit…
13 | reveal_type(a <= b) # revealed: Unknown
|
info: Operation fails because operator `<` is not supported between the tuple elements at index 2 (of type `Literal[2]` and `Literal["hello"]`)
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `<=` operation
--> src/mdtest_snippet.py:13:13
|
11 | reveal_type(a < b) # revealed: Unknown
12 | # error: [unsupported-operator] "Operator `<=` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Lit…
13 | reveal_type(a <= b) # revealed: Unknown
| -^^^^-
| | |
| | Has type `tuple[Literal[1], Literal["hello"]]`
| Has type `tuple[Literal[1], Literal[2]]`
14 | # error: [unsupported-operator] "Operator `>` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Lite…
15 | reveal_type(a > b) # revealed: Unknown
|
info: Operation fails because operator `<=` is not supported between the tuple elements at index 2 (of type `Literal[2]` and `Literal["hello"]`)
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `>` operation
--> src/mdtest_snippet.py:15:13
|
13 | reveal_type(a <= b) # revealed: Unknown
14 | # error: [unsupported-operator] "Operator `>` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Lite…
15 | reveal_type(a > b) # revealed: Unknown
| -^^^-
| | |
| | Has type `tuple[Literal[1], Literal["hello"]]`
| Has type `tuple[Literal[1], Literal[2]]`
16 | # error: [unsupported-operator] "Operator `>=` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Lit…
17 | reveal_type(a >= b) # revealed: Unknown
|
info: Operation fails because operator `>` is not supported between the tuple elements at index 2 (of type `Literal[2]` and `Literal["hello"]`)
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `>=` operation
--> src/mdtest_snippet.py:17:13
|
15 | reveal_type(a > b) # revealed: Unknown
16 | # error: [unsupported-operator] "Operator `>=` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Lit…
17 | reveal_type(a >= b) # revealed: Unknown
| -^^^^-
| | |
| | Has type `tuple[Literal[1], Literal["hello"]]`
| Has type `tuple[Literal[1], Literal[2]]`
18 | # error: [unsupported-operator]
19 | # error: [unsupported-operator]
|
info: Operation fails because operator `>=` is not supported between the tuple elements at index 2 (of type `Literal[2]` and `Literal["hello"]`)
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `<` operation
--> src/mdtest_snippet.py:20:13
|
18 | # error: [unsupported-operator]
19 | # error: [unsupported-operator]
20 | reveal_type((object(),) < (object(),) < (object(),)) # revealed: Unknown
| -----------^^^-----------
| |
| Both operands have type `tuple[object]`
21 | a = (1, 2)
22 | b = (999999, "hello")
|
info: Operation fails because operator `<` is not supported between the tuple elements at index 1 (both of type `object`)
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `<` operation
--> src/mdtest_snippet.py:20:27
|
18 | # error: [unsupported-operator]
19 | # error: [unsupported-operator]
20 | reveal_type((object(),) < (object(),) < (object(),)) # revealed: Unknown
| -----------^^^-----------
| |
| Both operands have type `tuple[object]`
21 | a = (1, 2)
22 | b = (999999, "hello")
|
info: Operation fails because operator `<` is not supported between the tuple elements at index 1 (both of type `object`)
info: rule `unsupported-operator` is enabled by default
```

View File

@ -0,0 +1,123 @@
---
source: crates/ty_test/src/lib.rs
expression: snapshot
---
---
mdtest name: unions.md - Comparison: Unions - Unsupported operations
mdtest path: crates/ty_python_semantic/resources/mdtest/comparison/unions.md
---
# Python source files
## mdtest_snippet.py
```
1 | from typing import Literal
2 |
3 | def _(
4 | x: list[int] | Literal[1],
5 | y: list[int] | Literal[1],
6 | aa: tuple[int],
7 | bb: tuple[int] | tuple[int, int],
8 | cc: tuple[str] | tuple[str, str],
9 | ):
10 | result = 1 in x # error: "Operator `in` is not supported"
11 | reveal_type(result) # revealed: bool
12 |
13 | result2 = y in x # error: [unsupported-operator]
14 | reveal_type(result) # revealed: bool
15 |
16 | result3 = aa < cc # error: [unsupported-operator]
17 | result4 = cc < aa # error: [unsupported-operator]
18 | result5 = bb < cc # error: [unsupported-operator]
```
# Diagnostics
```
error[unsupported-operator]: Unsupported `in` operation
--> src/mdtest_snippet.py:10:14
|
8 | cc: tuple[str] | tuple[str, str],
9 | ):
10 | result = 1 in x # error: "Operator `in` is not supported"
| -^^^^-
| | |
| | Has type `list[int] | Literal[1]`
| Has type `Literal[1]`
11 | reveal_type(result) # revealed: bool
|
info: Operation fails because operator `in` is not supported between two objects of type `Literal[1]`
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `in` operation
--> src/mdtest_snippet.py:13:15
|
11 | reveal_type(result) # revealed: bool
12 |
13 | result2 = y in x # error: [unsupported-operator]
| -^^^^-
| |
| Both operands have type `list[int] | Literal[1]`
14 | reveal_type(result) # revealed: bool
|
info: Operation fails because operator `in` is not supported between objects of type `list[int]` and `Literal[1]`
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `<` operation
--> src/mdtest_snippet.py:16:15
|
14 | reveal_type(result) # revealed: bool
15 |
16 | result3 = aa < cc # error: [unsupported-operator]
| --^^^--
| | |
| | Has type `tuple[str] | tuple[str, str]`
| Has type `tuple[int]`
17 | result4 = cc < aa # error: [unsupported-operator]
18 | result5 = bb < cc # error: [unsupported-operator]
|
info: Operation fails because operator `<` is not supported between objects of type `int` and `str`
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `<` operation
--> src/mdtest_snippet.py:17:15
|
16 | result3 = aa < cc # error: [unsupported-operator]
17 | result4 = cc < aa # error: [unsupported-operator]
| --^^^--
| | |
| | Has type `tuple[int]`
| Has type `tuple[str] | tuple[str, str]`
18 | result5 = bb < cc # error: [unsupported-operator]
|
info: Operation fails because operator `<` is not supported between objects of type `str` and `int`
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `<` operation
--> src/mdtest_snippet.py:18:15
|
16 | result3 = aa < cc # error: [unsupported-operator]
17 | result4 = cc < aa # error: [unsupported-operator]
18 | result5 = bb < cc # error: [unsupported-operator]
| --^^^--
| | |
| | Has type `tuple[str] | tuple[str, str]`
| Has type `tuple[int] | tuple[int, int]`
|
info: Operation fails because operator `<` is not supported between objects of type `int` and `str`
info: rule `unsupported-operator` is enabled by default
```

View File

@ -0,0 +1,162 @@
---
source: crates/ty_test/src/lib.rs
expression: snapshot
---
---
mdtest name: unsupported.md - Comparison: Unsupported operators
mdtest path: crates/ty_python_semantic/resources/mdtest/comparison/unsupported.md
---
# Python source files
## mdtest_snippet.py
```
1 | def _(flag: bool, flag1: bool, flag2: bool):
2 | class A: ...
3 | a = 1 in 7 # error: "Operator `in` is not supported between objects of type `Literal[1]` and `Literal[7]`"
4 | reveal_type(a) # revealed: bool
5 |
6 | b = 0 not in 10 # error: "Operator `not in` is not supported between objects of type `Literal[0]` and `Literal[10]`"
7 | reveal_type(b) # revealed: bool
8 |
9 | # error: [unsupported-operator] "Operator `<` is not supported between objects of type `object` and `Literal[5]`"
10 | c = object() < 5
11 | reveal_type(c) # revealed: Unknown
12 |
13 | # error: [unsupported-operator] "Operator `<` is not supported between objects of type `Literal[5]` and `object`"
14 | d = 5 < object()
15 | reveal_type(d) # revealed: Unknown
16 |
17 | int_literal_or_str_literal = 1 if flag else "foo"
18 | # error: "Operator `in` is not supported between objects of type `Literal[42]` and `Literal[1, "foo"]`"
19 | e = 42 in int_literal_or_str_literal
20 | reveal_type(e) # revealed: bool
21 |
22 | # error: [unsupported-operator] "Operator `<` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[Literal[1], Literal["hello"]]`"
23 | f = (1, 2) < (1, "hello")
24 | reveal_type(f) # revealed: Unknown
25 |
26 | # error: [unsupported-operator] "Operator `<` is not supported between two objects of type `tuple[bool, A]`"
27 | g = (flag1, A()) < (flag2, A())
28 | reveal_type(g) # revealed: Unknown
```
# Diagnostics
```
error[unsupported-operator]: Unsupported `in` operation
--> src/mdtest_snippet.py:3:9
|
1 | def _(flag: bool, flag1: bool, flag2: bool):
2 | class A: ...
3 | a = 1 in 7 # error: "Operator `in` is not supported between objects of type `Literal[1]` and `Literal[7]`"
| -^^^^-
| | |
| | Has type `Literal[7]`
| Has type `Literal[1]`
4 | reveal_type(a) # revealed: bool
|
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `not in` operation
--> src/mdtest_snippet.py:6:9
|
4 | reveal_type(a) # revealed: bool
5 |
6 | b = 0 not in 10 # error: "Operator `not in` is not supported between objects of type `Literal[0]` and `Literal[10]`"
| -^^^^^^^^--
| | |
| | Has type `Literal[10]`
| Has type `Literal[0]`
7 | reveal_type(b) # revealed: bool
|
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `<` operation
--> src/mdtest_snippet.py:10:9
|
9 | # error: [unsupported-operator] "Operator `<` is not supported between objects of type `object` and `Literal[5]`"
10 | c = object() < 5
| --------^^^-
| | |
| | Has type `Literal[5]`
| Has type `object`
11 | reveal_type(c) # revealed: Unknown
|
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `<` operation
--> src/mdtest_snippet.py:14:9
|
13 | # error: [unsupported-operator] "Operator `<` is not supported between objects of type `Literal[5]` and `object`"
14 | d = 5 < object()
| -^^^--------
| | |
| | Has type `object`
| Has type `Literal[5]`
15 | reveal_type(d) # revealed: Unknown
|
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `in` operation
--> src/mdtest_snippet.py:19:9
|
17 | int_literal_or_str_literal = 1 if flag else "foo"
18 | # error: "Operator `in` is not supported between objects of type `Literal[42]` and `Literal[1, "foo"]`"
19 | e = 42 in int_literal_or_str_literal
| --^^^^--------------------------
| | |
| | Has type `Literal[1, "foo"]`
| Has type `Literal[42]`
20 | reveal_type(e) # revealed: bool
|
info: Operation fails because operator `in` is not supported between objects of type `Literal[42]` and `Literal[1]`
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `<` operation
--> src/mdtest_snippet.py:23:9
|
22 | # error: [unsupported-operator] "Operator `<` is not supported between objects of type `tuple[Literal[1], Literal[2]]` and `tuple[…
23 | f = (1, 2) < (1, "hello")
| ------^^^------------
| | |
| | Has type `tuple[Literal[1], Literal["hello"]]`
| Has type `tuple[Literal[1], Literal[2]]`
24 | reveal_type(f) # revealed: Unknown
|
info: Operation fails because operator `<` is not supported between the tuple elements at index 2 (of type `Literal[2]` and `Literal["hello"]`)
info: rule `unsupported-operator` is enabled by default
```
```
error[unsupported-operator]: Unsupported `<` operation
--> src/mdtest_snippet.py:27:9
|
26 | # error: [unsupported-operator] "Operator `<` is not supported between two objects of type `tuple[bool, A]`"
27 | g = (flag1, A()) < (flag2, A())
| ------------^^^------------
| |
| Both operands have type `tuple[bool, A]`
28 | reveal_type(g) # revealed: Unknown
|
info: Operation fails because operator `<` is not supported between the tuple elements at index 2 (both of type `A`)
info: rule `unsupported-operator` is enabled by default
```

View File

@ -18,12 +18,14 @@ use crate::types::class::{
CodeGeneratorKind, DisjointBase, DisjointBaseKind, Field, MethodDecorator,
};
use crate::types::function::{FunctionDecorators, FunctionType, KnownFunction, OverloadLiteral};
use crate::types::infer::UnsupportedComparisonError;
use crate::types::overrides::MethodKind;
use crate::types::string_annotation::{
BYTE_STRING_TYPE_ANNOTATION, ESCAPE_CHARACTER_IN_FORWARD_ANNOTATION, FSTRING_TYPE_ANNOTATION,
IMPLICIT_CONCATENATED_STRING_TYPE_ANNOTATION, INVALID_SYNTAX_IN_FORWARD_ANNOTATION,
RAW_STRING_TYPE_ANNOTATION,
};
use crate::types::tuple::TupleSpec;
use crate::types::{
BoundTypeVarInstance, ClassType, DynamicType, LintDiagnosticGuard, Protocol,
ProtocolInstanceType, SpecialFormType, SubclassOfInner, Type, TypeContext, binding_type,
@ -2410,7 +2412,7 @@ pub(super) fn report_invalid_assignment<'db>(
}
let settings =
DisplaySettings::from_possibly_ambiguous_type_pair(context.db(), target_ty, value_ty);
DisplaySettings::from_possibly_ambiguous_types(context.db(), [target_ty, value_ty]);
let diagnostic_range = if let Some(value_node) = value_node {
// Expand the range to include parentheses around the value, if any. This allows
@ -2548,7 +2550,7 @@ pub(super) fn report_invalid_return_type(
};
let settings =
DisplaySettings::from_possibly_ambiguous_type_pair(context.db(), expected_ty, actual_ty);
DisplaySettings::from_possibly_ambiguous_types(context.db(), [expected_ty, actual_ty]);
let return_type_span = context.span(return_type_range);
let mut diag = builder.into_diagnostic("Return type does not match returned value");
@ -4054,6 +4056,112 @@ pub(super) fn report_overridden_final_method<'db>(
}
}
pub(super) fn report_unsupported_comparison<'db>(
context: &InferContext<'db, '_>,
error: &UnsupportedComparisonError<'db>,
range: TextRange,
left: &ast::Expr,
right: &ast::Expr,
left_ty: Type<'db>,
right_ty: Type<'db>,
) {
let db = context.db();
let Some(diagnostic_builder) = context.report_lint(&UNSUPPORTED_OPERATOR, range) else {
return;
};
let display_settings = DisplaySettings::from_possibly_ambiguous_types(
db,
[error.left_ty, error.right_ty, left_ty, right_ty],
);
let mut diagnostic =
diagnostic_builder.into_diagnostic(format_args!("Unsupported `{}` operation", error.op));
if left_ty == right_ty {
diagnostic.set_primary_message(format_args!(
"Both operands have type `{}`",
left_ty.display_with(db, display_settings.clone())
));
diagnostic.annotate(context.secondary(left));
diagnostic.annotate(context.secondary(right));
diagnostic.set_concise_message(format_args!(
"Operator `{}` is not supported between two objects of type `{}`",
error.op,
left_ty.display_with(db, display_settings.clone())
));
} else {
for (ty, expr) in [(left_ty, left), (right_ty, right)] {
diagnostic.annotate(context.secondary(expr).message(format_args!(
"Has type `{}`",
ty.display_with(db, display_settings.clone())
)));
}
diagnostic.set_concise_message(format_args!(
"Operator `{}` is not supported between objects of type `{}` and `{}`",
error.op,
left_ty.display_with(db, display_settings.clone()),
right_ty.display_with(db, display_settings.clone())
));
}
// For non-atomic types like unions and tuples, we now provide context
// on the underlying elements that caused the error.
// If we're emitting a diagnostic for something like `(1, "foo") < (2, 3)`:
//
// - `left_ty` is `tuple[Literal[1], Literal["foo"]]`
// - `right_ty` is `tuple[Literal[2], Literal[3]]
// - `error.left_ty` is `Literal["foo"]`
// - `error.right_ty` is `Literal[3]`
if (error.left_ty, error.right_ty) != (left_ty, right_ty) {
if let Some(TupleSpec::Fixed(lhs_spec)) = left_ty.tuple_instance_spec(db).as_deref()
&& let Some(TupleSpec::Fixed(rhs_spec)) = right_ty.tuple_instance_spec(db).as_deref()
&& lhs_spec.len() == rhs_spec.len()
&& let Some(position) = lhs_spec
.elements()
.zip(rhs_spec.elements())
.position(|tup| tup == (&error.left_ty, &error.right_ty))
{
if error.left_ty == error.right_ty {
diagnostic.info(format_args!(
"Operation fails because operator `{}` is not supported between \
the tuple elements at index {} (both of type `{}`)",
error.op,
position + 1,
error.left_ty.display_with(db, display_settings),
));
} else {
diagnostic.info(format_args!(
"Operation fails because operator `{}` is not supported between \
the tuple elements at index {} (of type `{}` and `{}`)",
error.op,
position + 1,
error.left_ty.display_with(db, display_settings.clone()),
error.right_ty.display_with(db, display_settings),
));
}
} else {
if error.left_ty == error.right_ty {
diagnostic.info(format_args!(
"Operation fails because operator `{}` is not supported \
between two objects of type `{}`",
error.op,
error.left_ty.display_with(db, display_settings),
));
} else {
diagnostic.info(format_args!(
"Operation fails because operator `{}` is not supported \
between objects of type `{}` and `{}`",
error.op,
error.left_ty.display_with(db, display_settings.clone()),
error.right_ty.display_with(db, display_settings)
));
}
}
}
}
/// This function receives an unresolved `from foo import bar` import,
/// where `foo` can be resolved to a module but that module does not
/// have a `bar` member or submodule.

View File

@ -72,14 +72,15 @@ impl<'db> DisplaySettings<'db> {
}
#[must_use]
pub fn from_possibly_ambiguous_type_pair(
pub fn from_possibly_ambiguous_types(
db: &'db dyn Db,
type_1: Type<'db>,
type_2: Type<'db>,
types: impl IntoIterator<Item = Type<'db>>,
) -> Self {
let collector = AmbiguousClassCollector::default();
collector.visit_type(db, type_1);
collector.visit_type(db, type_2);
for ty in types {
collector.visit_type(db, ty);
}
Self {
qualified: Rc::new(

View File

@ -57,6 +57,7 @@ use crate::types::{
};
use crate::unpack::Unpack;
use builder::TypeInferenceBuilder;
pub(super) use builder::UnsupportedComparisonError;
mod builder;
#[cfg(test)]

View File

@ -79,7 +79,7 @@ use crate::types::diagnostic::{
report_invalid_type_checking_constant, report_named_tuple_field_with_leading_underscore,
report_namedtuple_field_without_default_after_field_with_default, report_non_subscriptable,
report_possibly_missing_attribute, report_possibly_unresolved_reference,
report_rebound_typevar, report_slice_step_size_zero,
report_rebound_typevar, report_slice_step_size_zero, report_unsupported_comparison,
};
use crate::types::function::{
FunctionDecorators, FunctionLiteral, FunctionType, KnownFunction, OverloadLiteral,
@ -158,7 +158,7 @@ impl<'db> DeclaredAndInferredType<'db> {
type BinaryComparisonVisitor<'db> = CycleDetector<
ast::CmpOp,
(Type<'db>, ast::CmpOp, Type<'db>),
Result<Type<'db>, CompareUnsupportedError<'db>>,
Result<Type<'db>, UnsupportedComparisonError<'db>>,
>;
/// We currently store one dataclass field-specifiers inline, because that covers standard
@ -10056,26 +10056,15 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
&BinaryComparisonVisitor::new(Ok(Type::BooleanLiteral(true))),
)
.unwrap_or_else(|error| {
if let Some(diagnostic_builder) =
builder.context.report_lint(&UNSUPPORTED_OPERATOR, range)
{
// Handle unsupported operators (diagnostic, `bool`/`Unknown` outcome)
diagnostic_builder.into_diagnostic(format_args!(
"Operator `{}` is not supported for types `{}` and `{}`{}",
error.op,
error.left_ty.display(builder.db()),
error.right_ty.display(builder.db()),
if (left_ty, right_ty) == (error.left_ty, error.right_ty) {
String::new()
} else {
format!(
", in comparing `{}` with `{}`",
left_ty.display(builder.db()),
right_ty.display(builder.db())
)
}
));
}
report_unsupported_comparison(
&builder.context,
&error,
range,
left,
right,
left_ty,
right_ty,
);
match op {
// `in, not in, is, is not` always return bool instances
@ -10101,13 +10090,13 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
intersection_on: IntersectionOn,
range: TextRange,
visitor: &BinaryComparisonVisitor<'db>,
) -> Result<Type<'db>, CompareUnsupportedError<'db>> {
) -> Result<Type<'db>, UnsupportedComparisonError<'db>> {
enum State<'db> {
// We have not seen any positive elements (yet)
NoPositiveElements,
// The operator was unsupported on all elements that we have seen so far.
// Contains the first error we encountered.
UnsupportedOnAllElements(CompareUnsupportedError<'db>),
UnsupportedOnAllElements(UnsupportedComparisonError<'db>),
// The operator was supported on at least one positive element.
Supported,
}
@ -10263,7 +10252,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
right: Type<'db>,
range: TextRange,
visitor: &BinaryComparisonVisitor<'db>,
) -> Result<Type<'db>, CompareUnsupportedError<'db>> {
) -> Result<Type<'db>, UnsupportedComparisonError<'db>> {
// Note: identity (is, is not) for equal builtin types is unreliable and not part of the
// language spec.
// - `[ast::CompOp::Is]`: return `false` if unequal, `bool` if equal
@ -10335,7 +10324,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
IntersectionOn::Left,
range,
visitor,
))
).map_err(|err|UnsupportedComparisonError { op, left_ty: left, right_ty: err.right_ty }))
}
(left, Type::Intersection(intersection)) => {
Some(self.infer_binary_intersection_type_comparison(
@ -10345,7 +10334,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
IntersectionOn::Right,
range,
visitor,
))
).map_err(|err|UnsupportedComparisonError { op, left_ty: err.left_ty, right_ty: right }))
}
(Type::TypeAlias(alias), right) => Some(
@ -10392,7 +10381,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
}
}
// Undefined for (int, int)
ast::CmpOp::In | ast::CmpOp::NotIn => Err(CompareUnsupportedError {
ast::CmpOp::In | ast::CmpOp::NotIn => Err(UnsupportedComparisonError {
op,
left_ty: left,
right_ty: right,
@ -10405,7 +10394,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
right,
range,
visitor,
))
).map_err(|_| UnsupportedComparisonError {op, left_ty: left, right_ty: right}))
}
(Type::NominalInstance(_), Type::IntLiteral(_)) => {
Some(self.infer_binary_type_comparison(
@ -10414,7 +10403,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
KnownClass::Int.to_instance(self.db()),
range,
visitor,
))
).map_err(|_|UnsupportedComparisonError { op, left_ty: left, right_ty: right }))
}
// Booleans are coded as integers (False = 0, True = 1)
@ -10425,7 +10414,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
Type::IntLiteral(i64::from(b)),
range,
visitor,
))
).map_err(|_|UnsupportedComparisonError {op, left_ty: left, right_ty: right}))
}
(Type::BooleanLiteral(b), Type::IntLiteral(m)) => {
Some(self.infer_binary_type_comparison(
@ -10434,7 +10423,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
Type::IntLiteral(m),
range,
visitor,
))
).map_err(|_|UnsupportedComparisonError {op, left_ty: left, right_ty: right}))
}
(Type::BooleanLiteral(a), Type::BooleanLiteral(b)) => {
Some(self.infer_binary_type_comparison(
@ -10443,37 +10432,37 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
Type::IntLiteral(i64::from(b)),
range,
visitor,
))
).map_err(|_|UnsupportedComparisonError {op, left_ty: left, right_ty: right}))
}
(Type::StringLiteral(salsa_s1), Type::StringLiteral(salsa_s2)) => {
let s1 = salsa_s1.value(self.db());
let s2 = salsa_s2.value(self.db());
let result = match op {
ast::CmpOp::Eq => Ok(Type::BooleanLiteral(s1 == s2)),
ast::CmpOp::NotEq => Ok(Type::BooleanLiteral(s1 != s2)),
ast::CmpOp::Lt => Ok(Type::BooleanLiteral(s1 < s2)),
ast::CmpOp::LtE => Ok(Type::BooleanLiteral(s1 <= s2)),
ast::CmpOp::Gt => Ok(Type::BooleanLiteral(s1 > s2)),
ast::CmpOp::GtE => Ok(Type::BooleanLiteral(s1 >= s2)),
ast::CmpOp::In => Ok(Type::BooleanLiteral(s2.contains(s1))),
ast::CmpOp::NotIn => Ok(Type::BooleanLiteral(!s2.contains(s1))),
ast::CmpOp::Eq => Type::BooleanLiteral(s1 == s2),
ast::CmpOp::NotEq => Type::BooleanLiteral(s1 != s2),
ast::CmpOp::Lt => Type::BooleanLiteral(s1 < s2),
ast::CmpOp::LtE => Type::BooleanLiteral(s1 <= s2),
ast::CmpOp::Gt => Type::BooleanLiteral(s1 > s2),
ast::CmpOp::GtE => Type::BooleanLiteral(s1 >= s2),
ast::CmpOp::In => Type::BooleanLiteral(s2.contains(s1)),
ast::CmpOp::NotIn => Type::BooleanLiteral(!s2.contains(s1)),
ast::CmpOp::Is => {
if s1 == s2 {
Ok(KnownClass::Bool.to_instance(self.db()))
KnownClass::Bool.to_instance(self.db())
} else {
Ok(Type::BooleanLiteral(false))
Type::BooleanLiteral(false)
}
}
ast::CmpOp::IsNot => {
if s1 == s2 {
Ok(KnownClass::Bool.to_instance(self.db()))
KnownClass::Bool.to_instance(self.db())
} else {
Ok(Type::BooleanLiteral(true))
Type::BooleanLiteral(true)
}
}
};
Some(result)
Some(Ok(result))
}
(Type::StringLiteral(_), _) => Some(self.infer_binary_type_comparison(
KnownClass::Str.to_instance(self.db()),
@ -10481,14 +10470,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
right,
range,
visitor,
)),
).map_err(|err|UnsupportedComparisonError {op, left_ty: left, right_ty: err.right_ty})),
(_, Type::StringLiteral(_)) => Some(self.infer_binary_type_comparison(
left,
op,
KnownClass::Str.to_instance(self.db()),
range,
visitor,
)),
).map_err(|err|UnsupportedComparisonError {op, left_ty: err.left_ty, right_ty: right})),
(Type::LiteralString, _) => Some(self.infer_binary_type_comparison(
KnownClass::Str.to_instance(self.db()),
@ -10496,47 +10485,47 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
right,
range,
visitor,
)),
).map_err(|err|UnsupportedComparisonError {op, left_ty: left, right_ty: err.right_ty})),
(_, Type::LiteralString) => Some(self.infer_binary_type_comparison(
left,
op,
KnownClass::Str.to_instance(self.db()),
range,
visitor,
)),
).map_err(|err|UnsupportedComparisonError {op, left_ty: err.left_ty, right_ty: right})),
(Type::BytesLiteral(salsa_b1), Type::BytesLiteral(salsa_b2)) => {
let b1 = salsa_b1.value(self.db());
let b2 = salsa_b2.value(self.db());
let result = match op {
ast::CmpOp::Eq => Ok(Type::BooleanLiteral(b1 == b2)),
ast::CmpOp::NotEq => Ok(Type::BooleanLiteral(b1 != b2)),
ast::CmpOp::Lt => Ok(Type::BooleanLiteral(b1 < b2)),
ast::CmpOp::LtE => Ok(Type::BooleanLiteral(b1 <= b2)),
ast::CmpOp::Gt => Ok(Type::BooleanLiteral(b1 > b2)),
ast::CmpOp::GtE => Ok(Type::BooleanLiteral(b1 >= b2)),
ast::CmpOp::Eq => Type::BooleanLiteral(b1 == b2),
ast::CmpOp::NotEq => Type::BooleanLiteral(b1 != b2),
ast::CmpOp::Lt => Type::BooleanLiteral(b1 < b2),
ast::CmpOp::LtE => Type::BooleanLiteral(b1 <= b2),
ast::CmpOp::Gt => Type::BooleanLiteral(b1 > b2),
ast::CmpOp::GtE => Type::BooleanLiteral(b1 >= b2),
ast::CmpOp::In => {
Ok(Type::BooleanLiteral(memchr::memmem::find(b2, b1).is_some()))
Type::BooleanLiteral(memchr::memmem::find(b2, b1).is_some())
}
ast::CmpOp::NotIn => {
Ok(Type::BooleanLiteral(memchr::memmem::find(b2, b1).is_none()))
Type::BooleanLiteral(memchr::memmem::find(b2, b1).is_none())
}
ast::CmpOp::Is => {
if b1 == b2 {
Ok(KnownClass::Bool.to_instance(self.db()))
KnownClass::Bool.to_instance(self.db())
} else {
Ok(Type::BooleanLiteral(false))
Type::BooleanLiteral(false)
}
}
ast::CmpOp::IsNot => {
if b1 == b2 {
Ok(KnownClass::Bool.to_instance(self.db()))
KnownClass::Bool.to_instance(self.db())
} else {
Ok(Type::BooleanLiteral(true))
Type::BooleanLiteral(true)
}
}
};
Some(result)
Some(Ok(result))
}
(Type::BytesLiteral(_), _) => Some(self.infer_binary_type_comparison(
KnownClass::Bytes.to_instance(self.db()),
@ -10544,14 +10533,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
right,
range,
visitor,
)),
).map_err(|err| UnsupportedComparisonError { op, left_ty: left, right_ty: err.right_ty })),
(_, Type::BytesLiteral(_)) => Some(self.infer_binary_type_comparison(
left,
op,
KnownClass::Bytes.to_instance(self.db()),
range,
visitor,
)),
).map_err(|err| UnsupportedComparisonError { op, left_ty: err.left_ty, right_ty: right })),
(Type::EnumLiteral(literal_1), Type::EnumLiteral(literal_2))
if op == ast::CmpOp::Eq =>
@ -10683,7 +10672,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
right: Type<'db>,
op: RichCompareOperator,
policy: MemberLookupPolicy,
) -> Result<Type<'db>, CompareUnsupportedError<'db>> {
) -> Result<Type<'db>, UnsupportedComparisonError<'db>> {
let db = self.db();
// The following resource has details about the rich comparison algorithm:
// https://snarky.ca/unravelling-rich-comparison-operators/
@ -10719,7 +10708,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
None
}
})
.ok_or_else(|| CompareUnsupportedError {
.ok_or_else(|| UnsupportedComparisonError {
op: op.into(),
left_ty: left,
right_ty: right,
@ -10736,7 +10725,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
right: Type<'db>,
op: MembershipTestCompareOperator,
range: TextRange,
) -> Result<Type<'db>, CompareUnsupportedError<'db>> {
) -> Result<Type<'db>, UnsupportedComparisonError<'db>> {
let db = self.db();
let contains_dunder = right.class_member(db, "__contains__".into()).place;
@ -10773,7 +10762,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
MembershipTestCompareOperator::NotIn => truthiness.negate().into_type(db),
}
})
.ok_or_else(|| CompareUnsupportedError {
.ok_or_else(|| UnsupportedComparisonError {
op: op.into(),
left_ty: left,
right_ty: right,
@ -10792,7 +10781,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
right: &TupleSpec<'db>,
range: TextRange,
visitor: &BinaryComparisonVisitor<'db>,
) -> Result<Type<'db>, CompareUnsupportedError<'db>> {
) -> Result<Type<'db>, UnsupportedComparisonError<'db>> {
// If either tuple is variable length, we can make no assumptions about the relative
// lengths of the tuples, and therefore neither about how they compare lexicographically.
// TODO: Consider comparing the prefixes of the tuples, since that could give a comparison
@ -12382,11 +12371,22 @@ impl From<MembershipTestCompareOperator> for ast::CmpOp {
}
}
/// Context for a failed comparison operation.
///
/// `left_ty` and `right_ty` are the "low-level" types
/// that cannot be compared using `op`. For example,
/// when evaluating `(1, "foo") < (2, 3)`, the "high-level"
/// types of the operands are `tuple[Literal[1], Literal["foo"]]`
/// and `tuple[Literal[2], Literal[3]]`. Those aren't captured
/// in this struct, but the "low-level" types that mean that
/// the high-level types cannot be compared *are* captured in
/// this struct. In this case, those would be `Literal["foo"]`
/// and `Literal[3]`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct CompareUnsupportedError<'db> {
op: ast::CmpOp,
left_ty: Type<'db>,
right_ty: Type<'db>,
pub(crate) struct UnsupportedComparisonError<'db> {
pub(crate) op: ast::CmpOp,
pub(crate) left_ty: Type<'db>,
pub(crate) right_ty: Type<'db>,
}
fn format_import_from_module(level: u32, module: Option<&str>) -> String {