Compare commits
7 Commits
alex/into_
...
shifts
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dec1d2e8fc | ||
|
|
3aa91a853e | ||
|
|
59570beb57 | ||
|
|
78e51e8601 | ||
|
|
0006df9292 | ||
|
|
14aa8bb871 | ||
|
|
2882840abc |
2
.github/mypy-primer-ty.toml
vendored
2
.github/mypy-primer-ty.toml
vendored
@@ -5,4 +5,4 @@
|
||||
[rules]
|
||||
possibly-unresolved-reference = "warn"
|
||||
unused-ignore-comment = "warn"
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
|
||||
2
crates/ty/docs/configuration.md
generated
2
crates/ty/docs/configuration.md
generated
@@ -23,7 +23,7 @@ Valid severities are:
|
||||
```toml
|
||||
[tool.ty.rules]
|
||||
possibly-unresolved-reference = "warn"
|
||||
division-by-zero = "ignore"
|
||||
literal-math-error = "ignore"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
117
crates/ty/docs/rules.md
generated
117
crates/ty/docs/rules.md
generated
@@ -177,7 +177,7 @@ class B(A): ...
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L263)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L266)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -202,7 +202,7 @@ class B(A, A): ...
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-kw-only) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L284)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L287)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -306,7 +306,7 @@ def test(): -> "Literal[5]":
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L426)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L429)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -334,7 +334,7 @@ class C(A, B): ...
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L450)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L453)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -358,7 +358,7 @@ t[3] # IndexError: tuple index out of range
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20instance-layout-conflict) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L316)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L319)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -445,7 +445,7 @@ an atypical memory layout.
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L470)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L473)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -470,7 +470,7 @@ func("foo") # error: [invalid-argument-type]
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L510)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L513)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -496,7 +496,7 @@ a: int = ''
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1514)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1517)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -528,7 +528,7 @@ C.instance_var = 3 # error: Cannot assign to instance variable
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L532)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L535)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -550,7 +550,7 @@ class A(42): ... # error: [invalid-base]
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L583)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L586)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -575,7 +575,7 @@ with 1:
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L604)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L607)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -602,7 +602,7 @@ a: str
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L627)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L630)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -644,7 +644,7 @@ except ZeroDivisionError:
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L663)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L666)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -675,7 +675,7 @@ class C[U](Generic[T]): ...
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L689)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L692)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -708,7 +708,7 @@ def f(t: TypeVar("U")): ...
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L738)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L741)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -740,7 +740,7 @@ class B(metaclass=f): ...
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L765)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L768)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -788,7 +788,7 @@ def foo(x: int) -> int: ...
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L808)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L811)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -812,7 +812,7 @@ def f(a: int = ''): ...
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L398)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L401)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -844,7 +844,7 @@ TypeError: Protocols can only inherit from other protocols, got <class 'int'>
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L828)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L831)
|
||||
</small>
|
||||
|
||||
Checks for `raise` statements that raise non-exceptions or use invalid
|
||||
@@ -891,7 +891,7 @@ def g():
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L491)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L494)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -914,7 +914,7 @@ def func() -> int:
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L871)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L874)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -968,7 +968,7 @@ TODO #14889
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L717)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L720)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -993,7 +993,7 @@ NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name mus
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L910)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L913)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1021,7 +1021,7 @@ TYPE_CHECKING = ''
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L934)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L937)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1049,7 +1049,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-call) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L986)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L989)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1081,7 +1081,7 @@ f(10) # Error
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-definition) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L958)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L961)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1113,7 +1113,7 @@ class C:
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1014)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1017)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1146,7 +1146,7 @@ T = TypeVar('T', bound=str) # valid bound TypeVar
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1043)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1046)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1169,7 +1169,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1062)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1065)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1196,7 +1196,7 @@ func("string") # error: [no-matching-overload]
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1085)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1088)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1218,7 +1218,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1103)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1106)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1242,7 +1242,7 @@ for i in 34: # TypeError: 'int' object is not iterable
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1154)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1157)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1296,7 +1296,7 @@ def test(): -> "int":
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1490)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1493)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1324,7 +1324,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1245)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1248)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1351,7 +1351,7 @@ class B(A): ... # Error raised here
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1290)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1293)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1376,7 +1376,7 @@ f("foo") # Error raised here
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1268)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1271)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1402,7 +1402,7 @@ def _(x: int):
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1311)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1314)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1446,7 +1446,7 @@ class A:
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1368)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1371)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1471,7 +1471,7 @@ f(x=1, y=2) # Error raised here
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1389)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1392)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1497,7 +1497,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo'
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1411)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1414)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1520,7 +1520,7 @@ import foo # ModuleNotFoundError: No module named 'foo'
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1430)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1433)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1543,7 +1543,7 @@ print(x) # NameError: name 'x' is not defined
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1123)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1126)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1578,7 +1578,7 @@ b1 < b2 < b1 # exception raised here
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1449)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1452)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1604,7 +1604,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
|
||||
<small>
|
||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1471)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1474)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1655,7 +1655,7 @@ a = 20 / 0 # type: ignore
|
||||
<small>
|
||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-attribute) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1175)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1178)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1711,7 +1711,7 @@ A()[0] # TypeError: 'A' object is not subscriptable
|
||||
<small>
|
||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-import) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1197)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1200)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1741,7 +1741,7 @@ from module import a # ImportError: cannot import name 'a' from 'module'
|
||||
<small>
|
||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1542)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1545)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1766,7 +1766,7 @@ cast(int, f()) # Redundant
|
||||
<small>
|
||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1350)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1353)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1809,7 +1809,7 @@ a = 20 / 0 # ty: ignore[division-by-zer]
|
||||
Use instead:
|
||||
|
||||
```py
|
||||
a = 20 / 0 # ty: ignore[division-by-zero]
|
||||
a = 20 / 0 # ty: ignore[literal-math-error]
|
||||
```
|
||||
|
||||
## `unsupported-base`
|
||||
@@ -1817,7 +1817,7 @@ a = 20 / 0 # ty: ignore[division-by-zero]
|
||||
<small>
|
||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-base) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L550)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L553)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1849,26 +1849,29 @@ class D(C): ... # error: [unsupported-base]
|
||||
|
||||
[method resolution order]: https://docs.python.org/3/glossary.html#term-method-resolution-order
|
||||
|
||||
## `division-by-zero`
|
||||
## `literal-math-error`
|
||||
|
||||
<small>
|
||||
Default level: [`ignore`](../rules.md#rule-levels "This lint has a default level of 'ignore'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero) ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20literal-math-error) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L245)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
|
||||
It detects division by zero.
|
||||
Detects runtime errors that would result from invalid math operations
|
||||
between two objects with literal `int` types. Examples include division
|
||||
by zero and negative bitshifts.
|
||||
|
||||
**Why is this bad?**
|
||||
|
||||
Dividing by zero raises a `ZeroDivisionError` at runtime.
|
||||
These math operations will lead to exceptions being raised at runtime.
|
||||
|
||||
**Examples**
|
||||
|
||||
```python
|
||||
5 / 0
|
||||
5 / 0 # `ZeroDivisionError`
|
||||
1 << -1 # `ValueError: negative shift count`
|
||||
```
|
||||
|
||||
## `possibly-unresolved-reference`
|
||||
@@ -1876,7 +1879,7 @@ Dividing by zero raises a `ZeroDivisionError` at runtime.
|
||||
<small>
|
||||
Default level: [`ignore`](../rules.md#rule-levels "This lint has a default level of 'ignore'.") ·
|
||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference) ·
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1223)
|
||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1226)
|
||||
</small>
|
||||
|
||||
**What it does**
|
||||
@@ -1917,7 +1920,7 @@ included by mistake, and should be removed to avoid confusion.
|
||||
**Examples**
|
||||
|
||||
```py
|
||||
a = 20 / 2 # ty: ignore[division-by-zero]
|
||||
a = 20 / 2 # ty: ignore[literal-math-error]
|
||||
```
|
||||
|
||||
Use instead:
|
||||
|
||||
@@ -327,7 +327,7 @@ fn user_configuration() -> anyhow::Result<()> {
|
||||
"project/ty.toml",
|
||||
r#"
|
||||
[rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
"#,
|
||||
),
|
||||
(
|
||||
@@ -356,7 +356,7 @@ fn user_configuration() -> anyhow::Result<()> {
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
warning[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> main.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0
|
||||
@@ -364,7 +364,7 @@ fn user_configuration() -> anyhow::Result<()> {
|
||||
3 |
|
||||
4 | for a in range(0, int(y)):
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
error[unresolved-reference]: Name `prin` used when not defined
|
||||
--> main.py:7:1
|
||||
@@ -384,13 +384,13 @@ fn user_configuration() -> anyhow::Result<()> {
|
||||
);
|
||||
|
||||
// The user-level configuration sets the severity for `unresolved-reference` to warn.
|
||||
// Changing the level for `division-by-zero` has no effect, because the project-level configuration
|
||||
// Changing the level for `literal-math-error` has no effect, because the project-level configuration
|
||||
// has higher precedence.
|
||||
case.write_file(
|
||||
config_directory.join("ty/ty.toml"),
|
||||
r#"
|
||||
[rules]
|
||||
division-by-zero = "error"
|
||||
literal-math-error = "error"
|
||||
unresolved-reference = "warn"
|
||||
"#,
|
||||
)?;
|
||||
@@ -401,7 +401,7 @@ fn user_configuration() -> anyhow::Result<()> {
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
warning[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> main.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0
|
||||
@@ -409,7 +409,7 @@ fn user_configuration() -> anyhow::Result<()> {
|
||||
3 |
|
||||
4 | for a in range(0, int(y)):
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
warning[unresolved-reference]: Name `prin` used when not defined
|
||||
--> main.py:7:1
|
||||
@@ -437,7 +437,7 @@ fn check_specific_paths() -> anyhow::Result<()> {
|
||||
(
|
||||
"project/main.py",
|
||||
r#"
|
||||
y = 4 / 0 # error: division-by-zero
|
||||
y = 4 / 0 # error: literal-math-error
|
||||
"#,
|
||||
),
|
||||
(
|
||||
|
||||
@@ -42,7 +42,7 @@ fn configuration_rule_severity() -> anyhow::Result<()> {
|
||||
"pyproject.toml",
|
||||
r#"
|
||||
[tool.ty.rules]
|
||||
division-by-zero = "warn" # promote to warn
|
||||
literal-math-error = "warn" # promote to warn
|
||||
unresolved-reference = "ignore"
|
||||
"#,
|
||||
)?;
|
||||
@@ -51,7 +51,7 @@ fn configuration_rule_severity() -> anyhow::Result<()> {
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
warning[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> test.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0
|
||||
@@ -59,7 +59,7 @@ fn configuration_rule_severity() -> anyhow::Result<()> {
|
||||
3 |
|
||||
4 | for a in range(0, int(y)):
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
Found 1 diagnostic
|
||||
|
||||
@@ -126,7 +126,7 @@ fn cli_rule_severity() -> anyhow::Result<()> {
|
||||
.arg("--ignore")
|
||||
.arg("unresolved-reference")
|
||||
.arg("--warn")
|
||||
.arg("division-by-zero")
|
||||
.arg("literal-math-error")
|
||||
.arg("--warn")
|
||||
.arg("unresolved-import"),
|
||||
@r"
|
||||
@@ -144,7 +144,7 @@ fn cli_rule_severity() -> anyhow::Result<()> {
|
||||
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
||||
info: rule `unresolved-import` was selected on the command line
|
||||
|
||||
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
warning[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> test.py:4:5
|
||||
|
|
||||
2 | import does_not_exit
|
||||
@@ -154,7 +154,7 @@ fn cli_rule_severity() -> anyhow::Result<()> {
|
||||
5 |
|
||||
6 | for a in range(0, int(y)):
|
||||
|
|
||||
info: rule `division-by-zero` was selected on the command line
|
||||
info: rule `literal-math-error` was selected on the command line
|
||||
|
||||
Found 2 diagnostics
|
||||
|
||||
@@ -209,14 +209,14 @@ fn cli_rule_severity_precedence() -> anyhow::Result<()> {
|
||||
.arg("--warn")
|
||||
.arg("unresolved-reference")
|
||||
.arg("--warn")
|
||||
.arg("division-by-zero")
|
||||
.arg("literal-math-error")
|
||||
.arg("--ignore")
|
||||
.arg("unresolved-reference"),
|
||||
@r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
warning[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> test.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0
|
||||
@@ -224,7 +224,7 @@ fn cli_rule_severity_precedence() -> anyhow::Result<()> {
|
||||
3 |
|
||||
4 | for a in range(0, int(y)):
|
||||
|
|
||||
info: rule `division-by-zero` was selected on the command line
|
||||
info: rule `literal-math-error` was selected on the command line
|
||||
|
||||
Found 1 diagnostic
|
||||
|
||||
@@ -299,21 +299,21 @@ fn overrides_basic() -> anyhow::Result<()> {
|
||||
"pyproject.toml",
|
||||
r#"
|
||||
[tool.ty.rules]
|
||||
division-by-zero = "error"
|
||||
literal-math-error = "error"
|
||||
unresolved-reference = "error"
|
||||
|
||||
[[tool.ty.overrides]]
|
||||
include = ["tests/**"]
|
||||
|
||||
[tool.ty.overrides.rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
unresolved-reference = "ignore"
|
||||
"#,
|
||||
),
|
||||
(
|
||||
"main.py",
|
||||
r#"
|
||||
y = 4 / 0 # division-by-zero: error (global)
|
||||
y = 4 / 0 # literal-math-error: error (global)
|
||||
x = 1
|
||||
prin(x) # unresolved-reference: error (global)
|
||||
"#,
|
||||
@@ -321,7 +321,7 @@ fn overrides_basic() -> anyhow::Result<()> {
|
||||
(
|
||||
"tests/test_main.py",
|
||||
r#"
|
||||
y = 4 / 0 # division-by-zero: warn (override)
|
||||
y = 4 / 0 # literal-math-error: warn (override)
|
||||
x = 1
|
||||
prin(x) # unresolved-reference: ignore (override)
|
||||
"#,
|
||||
@@ -332,35 +332,35 @@ fn overrides_basic() -> anyhow::Result<()> {
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
error[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
error[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> main.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0 # division-by-zero: error (global)
|
||||
2 | y = 4 / 0 # literal-math-error: error (global)
|
||||
| ^^^^^
|
||||
3 | x = 1
|
||||
4 | prin(x) # unresolved-reference: error (global)
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
error[unresolved-reference]: Name `prin` used when not defined
|
||||
--> main.py:4:1
|
||||
|
|
||||
2 | y = 4 / 0 # division-by-zero: error (global)
|
||||
2 | y = 4 / 0 # literal-math-error: error (global)
|
||||
3 | x = 1
|
||||
4 | prin(x) # unresolved-reference: error (global)
|
||||
| ^^^^
|
||||
|
|
||||
info: rule `unresolved-reference` was selected in the configuration file
|
||||
|
||||
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
warning[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> tests/test_main.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0 # division-by-zero: warn (override)
|
||||
2 | y = 4 / 0 # literal-math-error: warn (override)
|
||||
| ^^^^^
|
||||
3 | x = 1
|
||||
4 | prin(x) # unresolved-reference: ignore (override)
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
Found 3 diagnostics
|
||||
|
||||
@@ -379,31 +379,31 @@ fn overrides_precedence() -> anyhow::Result<()> {
|
||||
"pyproject.toml",
|
||||
r#"
|
||||
[tool.ty.rules]
|
||||
division-by-zero = "error"
|
||||
literal-math-error = "error"
|
||||
|
||||
# First override: all test files
|
||||
[[tool.ty.overrides]]
|
||||
include = ["tests/**"]
|
||||
[tool.ty.overrides.rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
|
||||
# Second override: specific test file (takes precedence)
|
||||
[[tool.ty.overrides]]
|
||||
include = ["tests/important.py"]
|
||||
[tool.ty.overrides.rules]
|
||||
division-by-zero = "ignore"
|
||||
literal-math-error = "ignore"
|
||||
"#,
|
||||
),
|
||||
(
|
||||
"tests/test_main.py",
|
||||
r#"
|
||||
y = 4 / 0 # division-by-zero: warn (first override)
|
||||
y = 4 / 0 # literal-math-error: warn (first override)
|
||||
"#,
|
||||
),
|
||||
(
|
||||
"tests/important.py",
|
||||
r#"
|
||||
y = 4 / 0 # division-by-zero: ignore (second override)
|
||||
y = 4 / 0 # literal-math-error: ignore (second override)
|
||||
"#,
|
||||
),
|
||||
])?;
|
||||
@@ -412,13 +412,13 @@ fn overrides_precedence() -> anyhow::Result<()> {
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
warning[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> tests/test_main.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0 # division-by-zero: warn (first override)
|
||||
2 | y = 4 / 0 # literal-math-error: warn (first override)
|
||||
| ^^^^^
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
Found 1 diagnostic
|
||||
|
||||
@@ -437,25 +437,25 @@ fn overrides_exclude() -> anyhow::Result<()> {
|
||||
"pyproject.toml",
|
||||
r#"
|
||||
[tool.ty.rules]
|
||||
division-by-zero = "error"
|
||||
literal-math-error = "error"
|
||||
|
||||
[[tool.ty.overrides]]
|
||||
include = ["tests/**"]
|
||||
exclude = ["tests/important.py"]
|
||||
[tool.ty.overrides.rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
"#,
|
||||
),
|
||||
(
|
||||
"tests/test_main.py",
|
||||
r#"
|
||||
y = 4 / 0 # division-by-zero: warn (override applies)
|
||||
y = 4 / 0 # literal-math-error: warn (override applies)
|
||||
"#,
|
||||
),
|
||||
(
|
||||
"tests/important.py",
|
||||
r#"
|
||||
y = 4 / 0 # division-by-zero: error (override excluded)
|
||||
y = 4 / 0 # literal-math-error: error (override excluded)
|
||||
"#,
|
||||
),
|
||||
])?;
|
||||
@@ -464,21 +464,21 @@ fn overrides_exclude() -> anyhow::Result<()> {
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
error[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
error[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> tests/important.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0 # division-by-zero: error (override excluded)
|
||||
2 | y = 4 / 0 # literal-math-error: error (override excluded)
|
||||
| ^^^^^
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
warning[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> tests/test_main.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0 # division-by-zero: warn (override applies)
|
||||
2 | y = 4 / 0 # literal-math-error: warn (override applies)
|
||||
| ^^^^^
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
Found 2 diagnostics
|
||||
|
||||
@@ -497,28 +497,28 @@ fn overrides_inherit_global() -> anyhow::Result<()> {
|
||||
"pyproject.toml",
|
||||
r#"
|
||||
[tool.ty.rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
unresolved-reference = "error"
|
||||
|
||||
[[tool.ty.overrides]]
|
||||
include = ["tests/**"]
|
||||
|
||||
[tool.ty.overrides.rules]
|
||||
# Override only division-by-zero, unresolved-reference should inherit from global
|
||||
division-by-zero = "ignore"
|
||||
# Override only literal-math-error, unresolved-reference should inherit from global
|
||||
literal-math-error = "ignore"
|
||||
"#,
|
||||
),
|
||||
(
|
||||
"main.py",
|
||||
r#"
|
||||
y = 4 / 0 # division-by-zero: warn (global)
|
||||
y = 4 / 0 # literal-math-error: warn (global)
|
||||
prin(y) # unresolved-reference: error (global)
|
||||
"#,
|
||||
),
|
||||
(
|
||||
"tests/test_main.py",
|
||||
r#"
|
||||
y = 4 / 0 # division-by-zero: ignore (overridden)
|
||||
y = 4 / 0 # literal-math-error: ignore (overridden)
|
||||
prin(y) # unresolved-reference: error (inherited from global)
|
||||
"#,
|
||||
),
|
||||
@@ -528,19 +528,19 @@ fn overrides_inherit_global() -> anyhow::Result<()> {
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
warning[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> main.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0 # division-by-zero: warn (global)
|
||||
2 | y = 4 / 0 # literal-math-error: warn (global)
|
||||
| ^^^^^
|
||||
3 | prin(y) # unresolved-reference: error (global)
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
error[unresolved-reference]: Name `prin` used when not defined
|
||||
--> main.py:3:1
|
||||
|
|
||||
2 | y = 4 / 0 # division-by-zero: warn (global)
|
||||
2 | y = 4 / 0 # literal-math-error: warn (global)
|
||||
3 | prin(y) # unresolved-reference: error (global)
|
||||
| ^^^^
|
||||
|
|
||||
@@ -549,7 +549,7 @@ fn overrides_inherit_global() -> anyhow::Result<()> {
|
||||
error[unresolved-reference]: Name `prin` used when not defined
|
||||
--> tests/test_main.py:3:1
|
||||
|
|
||||
2 | y = 4 / 0 # division-by-zero: ignore (overridden)
|
||||
2 | y = 4 / 0 # literal-math-error: ignore (overridden)
|
||||
3 | prin(y) # unresolved-reference: error (inherited from global)
|
||||
| ^^^^
|
||||
|
|
||||
@@ -572,12 +572,12 @@ fn overrides_invalid_include_glob() -> anyhow::Result<()> {
|
||||
"pyproject.toml",
|
||||
r#"
|
||||
[tool.ty.rules]
|
||||
division-by-zero = "error"
|
||||
literal-math-error = "error"
|
||||
|
||||
[[tool.ty.overrides]]
|
||||
include = ["tests/[invalid"] # Invalid glob: unclosed bracket
|
||||
[tool.ty.overrides.rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
"#,
|
||||
),
|
||||
(
|
||||
@@ -603,7 +603,7 @@ fn overrides_invalid_include_glob() -> anyhow::Result<()> {
|
||||
6 | include = ["tests/[invalid"] # Invalid glob: unclosed bracket
|
||||
| ^^^^^^^^^^^^^^^^ unclosed character class; missing ']'
|
||||
7 | [tool.ty.overrides.rules]
|
||||
8 | division-by-zero = "warn"
|
||||
8 | literal-math-error = "warn"
|
||||
|
|
||||
"#);
|
||||
|
||||
@@ -618,13 +618,13 @@ fn overrides_invalid_exclude_glob() -> anyhow::Result<()> {
|
||||
"pyproject.toml",
|
||||
r#"
|
||||
[tool.ty.rules]
|
||||
division-by-zero = "error"
|
||||
literal-math-error = "error"
|
||||
|
||||
[[tool.ty.overrides]]
|
||||
include = ["tests/**"]
|
||||
exclude = ["***/invalid"] # Invalid glob: triple asterisk
|
||||
[tool.ty.overrides.rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
"#,
|
||||
),
|
||||
(
|
||||
@@ -651,7 +651,7 @@ fn overrides_invalid_exclude_glob() -> anyhow::Result<()> {
|
||||
7 | exclude = ["***/invalid"] # Invalid glob: triple asterisk
|
||||
| ^^^^^^^^^^^^^ Too many stars at position 1
|
||||
8 | [tool.ty.overrides.rules]
|
||||
9 | division-by-zero = "warn"
|
||||
9 | literal-math-error = "warn"
|
||||
|
|
||||
"#);
|
||||
|
||||
@@ -666,12 +666,12 @@ fn overrides_missing_include_exclude() -> anyhow::Result<()> {
|
||||
"pyproject.toml",
|
||||
r#"
|
||||
[tool.ty.rules]
|
||||
division-by-zero = "error"
|
||||
literal-math-error = "error"
|
||||
|
||||
[[tool.ty.overrides]]
|
||||
# Missing both include and exclude - should warn
|
||||
[tool.ty.overrides.rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
"#,
|
||||
),
|
||||
(
|
||||
@@ -689,7 +689,7 @@ fn overrides_missing_include_exclude() -> anyhow::Result<()> {
|
||||
warning[unnecessary-overrides-section]: Unnecessary `overrides` section
|
||||
--> pyproject.toml:5:1
|
||||
|
|
||||
3 | division-by-zero = "error"
|
||||
3 | literal-math-error = "error"
|
||||
4 |
|
||||
5 | [[tool.ty.overrides]]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ This overrides section applies to all files
|
||||
@@ -700,13 +700,13 @@ fn overrides_missing_include_exclude() -> anyhow::Result<()> {
|
||||
info: Restrict the files by adding a pattern to `include` or `exclude`...
|
||||
info: or remove the `[[overrides]]` section and merge the configuration into the root `[rules]` table if the configuration should apply to all files
|
||||
|
||||
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
warning[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> test.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0
|
||||
| ^^^^^
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
Found 2 diagnostics
|
||||
|
||||
@@ -725,12 +725,12 @@ fn overrides_empty_include() -> anyhow::Result<()> {
|
||||
"pyproject.toml",
|
||||
r#"
|
||||
[tool.ty.rules]
|
||||
division-by-zero = "error"
|
||||
literal-math-error = "error"
|
||||
|
||||
[[tool.ty.overrides]]
|
||||
include = [] # Empty include - won't match any files
|
||||
[tool.ty.overrides.rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
"#,
|
||||
),
|
||||
(
|
||||
@@ -752,17 +752,17 @@ fn overrides_empty_include() -> anyhow::Result<()> {
|
||||
6 | include = [] # Empty include - won't match any files
|
||||
| ^^ This `include` list is empty
|
||||
7 | [tool.ty.overrides.rules]
|
||||
8 | division-by-zero = "warn"
|
||||
8 | literal-math-error = "warn"
|
||||
|
|
||||
info: Remove the `include` option to match all files or add a pattern to match specific files
|
||||
|
||||
error[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
error[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> test.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0
|
||||
| ^^^^^
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
Found 2 diagnostics
|
||||
|
||||
@@ -781,7 +781,7 @@ fn overrides_no_actual_overrides() -> anyhow::Result<()> {
|
||||
"pyproject.toml",
|
||||
r#"
|
||||
[tool.ty.rules]
|
||||
division-by-zero = "error"
|
||||
literal-math-error = "error"
|
||||
|
||||
[[tool.ty.overrides]]
|
||||
include = ["*.py"] # Has patterns but no rule overrides
|
||||
@@ -803,7 +803,7 @@ fn overrides_no_actual_overrides() -> anyhow::Result<()> {
|
||||
warning[useless-overrides-section]: Useless `overrides` section
|
||||
--> pyproject.toml:5:1
|
||||
|
|
||||
3 | division-by-zero = "error"
|
||||
3 | literal-math-error = "error"
|
||||
4 |
|
||||
5 | [[tool.ty.overrides]]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ This overrides section configures no rules
|
||||
@@ -814,13 +814,13 @@ fn overrides_no_actual_overrides() -> anyhow::Result<()> {
|
||||
info: Add a `[overrides.rules]` table...
|
||||
info: or remove the `[[overrides]]` section if there's nothing to override
|
||||
|
||||
error[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
error[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> test.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0
|
||||
| ^^^^^
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
Found 2 diagnostics
|
||||
|
||||
@@ -839,13 +839,13 @@ fn overrides_unknown_rules() -> anyhow::Result<()> {
|
||||
"pyproject.toml",
|
||||
r#"
|
||||
[tool.ty.rules]
|
||||
division-by-zero = "error"
|
||||
literal-math-error = "error"
|
||||
|
||||
[[tool.ty.overrides]]
|
||||
include = ["tests/**"]
|
||||
|
||||
[tool.ty.overrides.rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
division-by-zer = "error" # incorrect rule name
|
||||
"#,
|
||||
),
|
||||
@@ -871,26 +871,26 @@ fn overrides_unknown_rules() -> anyhow::Result<()> {
|
||||
--> pyproject.toml:10:1
|
||||
|
|
||||
8 | [tool.ty.overrides.rules]
|
||||
9 | division-by-zero = "warn"
|
||||
9 | literal-math-error = "warn"
|
||||
10 | division-by-zer = "error" # incorrect rule name
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
|
||||
error[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
error[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> main.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0
|
||||
| ^^^^^
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
|
||||
warning[literal-math-error]: Cannot divide object of type `Literal[4]` by zero
|
||||
--> tests/test_main.py:2:5
|
||||
|
|
||||
2 | y = 4 / 0
|
||||
| ^^^^^
|
||||
|
|
||||
info: rule `division-by-zero` was selected in the configuration file
|
||||
info: rule `literal-math-error` was selected in the configuration file
|
||||
|
||||
Found 3 diagnostics
|
||||
|
||||
|
||||
@@ -1687,7 +1687,7 @@ fn changes_to_user_configuration() -> anyhow::Result<()> {
|
||||
config_directory.join("ty/ty.toml").as_std_path(),
|
||||
r#"
|
||||
[rules]
|
||||
division-by-zero = "ignore"
|
||||
literal-math-error = "ignore"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
@@ -1710,12 +1710,12 @@ fn changes_to_user_configuration() -> anyhow::Result<()> {
|
||||
"Expected no diagnostics but got: {diagnostics:#?}"
|
||||
);
|
||||
|
||||
// Enable division-by-zero in the user configuration with warning severity
|
||||
// Enable literal-math-error in the user configuration with warning severity
|
||||
update_file(
|
||||
case.root_path().join("home/.config/ty/ty.toml"),
|
||||
r#"
|
||||
[rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
@@ -1753,7 +1753,7 @@ fn changes_to_config_file_override() -> anyhow::Result<()> {
|
||||
context.join_project_path("ty-override.toml").as_std_path(),
|
||||
r#"
|
||||
[rules]
|
||||
division-by-zero = "ignore"
|
||||
literal-math-error = "ignore"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
@@ -1770,12 +1770,12 @@ fn changes_to_config_file_override() -> anyhow::Result<()> {
|
||||
"Expected no diagnostics but got: {diagnostics:#?}"
|
||||
);
|
||||
|
||||
// Enable division-by-zero in the explicitly specified configuration with warning severity
|
||||
// Enable literal-math-error in the explicitly specified configuration with warning severity
|
||||
update_file(
|
||||
case.project_path("ty-override.toml"),
|
||||
r#"
|
||||
[rules]
|
||||
division-by-zero = "warn"
|
||||
literal-math-error = "warn"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ pub struct Options {
|
||||
example = r#"
|
||||
[tool.ty.rules]
|
||||
possibly-unresolved-reference = "warn"
|
||||
division-by-zero = "ignore"
|
||||
literal-math-error = "ignore"
|
||||
"#
|
||||
)]
|
||||
pub rules: Option<Rules>,
|
||||
|
||||
@@ -37,8 +37,8 @@ reveal_type(b**b) # revealed: Literal[1]
|
||||
# Division
|
||||
reveal_type(a / a) # revealed: float
|
||||
reveal_type(b / a) # revealed: float
|
||||
b / b # error: [division-by-zero] "Cannot divide object of type `Literal[False]` by zero"
|
||||
a / b # error: [division-by-zero] "Cannot divide object of type `Literal[True]` by zero"
|
||||
b / b # error: [literal-math-error] "Cannot divide object of type `Literal[False]` by zero"
|
||||
a / b # error: [literal-math-error] "Cannot divide object of type `Literal[True]` by zero"
|
||||
|
||||
# bitwise OR
|
||||
reveal_type(a | a) # revealed: Literal[True]
|
||||
@@ -57,6 +57,25 @@ reveal_type(a ^ a) # revealed: Literal[False]
|
||||
reveal_type(a ^ b) # revealed: Literal[True]
|
||||
reveal_type(b ^ a) # revealed: Literal[True]
|
||||
reveal_type(b ^ b) # revealed: Literal[False]
|
||||
|
||||
# left-shift
|
||||
reveal_type(a << a) # revealed: Literal[2]
|
||||
reveal_type(a << b) # revealed: Literal[1]
|
||||
reveal_type(b << a) # revealed: Literal[0]
|
||||
reveal_type(b << b) # revealed: Literal[0]
|
||||
reveal_type(True << 100) # revealed: int
|
||||
|
||||
# error: [literal-math-error] "Cannot left shift object of type `Literal[True]` by a negative value"
|
||||
reveal_type(True << -1) # revealed: int
|
||||
|
||||
# right-shift
|
||||
reveal_type(a >> a) # revealed: Literal[0]
|
||||
reveal_type(a >> b) # revealed: Literal[1]
|
||||
reveal_type(b >> a) # revealed: Literal[0]
|
||||
reveal_type(b >> b) # revealed: Literal[0]
|
||||
|
||||
# error: [literal-math-error] "Cannot right shift object of type `Literal[False]` by a negative value"
|
||||
reveal_type(False >> -1) # revealed: int
|
||||
```
|
||||
|
||||
## Arithmetic with a variable
|
||||
|
||||
@@ -39,6 +39,13 @@ def both(x: int):
|
||||
reveal_type(x // x) # revealed: int
|
||||
reveal_type(x / x) # revealed: int | float
|
||||
reveal_type(x % x) # revealed: int
|
||||
|
||||
# Edge case where negation leads to overflow:
|
||||
i64_max = 9223372036854775807
|
||||
i64_min = -i64_max - 1
|
||||
reveal_type(i64_max) # revealed: Literal[9223372036854775807]
|
||||
reveal_type(i64_min) # revealed: Literal[-9223372036854775808]
|
||||
reveal_type(-i64_min) # revealed: int
|
||||
```
|
||||
|
||||
## Power
|
||||
@@ -128,16 +135,65 @@ reveal_type(int() / 0) # revealed: int | float
|
||||
|
||||
# error: "Cannot divide object of type `Literal[1]` by zero"
|
||||
reveal_type(1 / False) # revealed: float
|
||||
# error: [division-by-zero] "Cannot divide object of type `Literal[True]` by zero"
|
||||
# error: [literal-math-error] "Cannot divide object of type `Literal[True]` by zero"
|
||||
True / False
|
||||
# error: [division-by-zero] "Cannot divide object of type `Literal[True]` by zero"
|
||||
# error: [literal-math-error] "Cannot divide object of type `Literal[True]` by zero"
|
||||
bool(1) / False
|
||||
|
||||
# error: "Cannot divide object of type `float` by zero"
|
||||
reveal_type(1.0 / 0) # revealed: int | float
|
||||
|
||||
# error: "Cannot divide object of type `complex` by zero"
|
||||
reveal_type(0j / 0) # revealed: int | float | complex
|
||||
|
||||
class MyInt(int): ...
|
||||
|
||||
# No error for a subclass of int
|
||||
reveal_type(MyInt(3) / 0) # revealed: int | float
|
||||
```
|
||||
|
||||
## Bit-shifting
|
||||
|
||||
Literal arithmetic is supported for bit-shifting operations on `int`s:
|
||||
|
||||
```py
|
||||
reveal_type(42 << 3) # revealed: Literal[336]
|
||||
reveal_type(0 << 3) # revealed: Literal[0]
|
||||
reveal_type(-42 << 3) # revealed: Literal[-336]
|
||||
|
||||
reveal_type(42 >> 3) # revealed: Literal[5]
|
||||
reveal_type(0 >> 3) # revealed: Literal[0]
|
||||
reveal_type(-42 >> 3) # revealed: Literal[-6]
|
||||
```
|
||||
|
||||
If the result of a left shift overflows the `int` literal type, it becomes `int`. Right shifts do
|
||||
not overflow:
|
||||
|
||||
```py
|
||||
reveal_type(42 << 100) # revealed: int
|
||||
reveal_type(0 << 100) # revealed: int
|
||||
reveal_type(-42 << 100) # revealed: int
|
||||
|
||||
reveal_type(42 >> 100) # revealed: Literal[0]
|
||||
reveal_type(0 >> 100) # revealed: Literal[0]
|
||||
reveal_type(-42 >> 100) # revealed: Literal[-1]
|
||||
```
|
||||
|
||||
It is an error to shift by a negative value. This is handled similarly to `ZeroDivisionError`
|
||||
detection, above:
|
||||
|
||||
```py
|
||||
# error: [literal-math-error] "Cannot left shift object of type `Literal[42]` by a negative value"
|
||||
reveal_type(42 << -3) # revealed: int
|
||||
# error: [literal-math-error]
|
||||
reveal_type(0 << -3) # revealed: int
|
||||
# error: [literal-math-error]
|
||||
reveal_type(-42 << -3) # revealed: int
|
||||
|
||||
# error: [literal-math-error] "Cannot right shift object of type `Literal[42]` by a negative value"
|
||||
reveal_type(42 >> -3) # revealed: int
|
||||
# error: [literal-math-error]
|
||||
reveal_type(0 >> -3) # revealed: int
|
||||
# error: [literal-math-error]
|
||||
reveal_type(-42 >> -3) # revealed: int
|
||||
```
|
||||
|
||||
@@ -54,6 +54,6 @@ If any of the union elements leads to a division by zero, we will report an erro
|
||||
|
||||
```py
|
||||
def f5(m: int, n: Literal[-1, 0, 1]):
|
||||
# error: [division-by-zero] "Cannot divide object of type `int` by zero"
|
||||
# error: [literal-math-error] "Cannot divide object of type `int` by zero"
|
||||
return m / n
|
||||
```
|
||||
|
||||
@@ -34,9 +34,9 @@ a = test + 3 # ty: ignore[possibly-unresolved-reference]
|
||||
|
||||
```py
|
||||
# error: [unused-ignore-comment]
|
||||
a = 10 / 2 # ty: ignore[division-by-zero]
|
||||
a = 10 / 2 # ty: ignore[division-by-zero, unused-ignore-comment]
|
||||
a = 10 / 2 # ty: ignore[unused-ignore-comment, division-by-zero]
|
||||
a = 10 / 2 # ty: ignore[literal-math-error]
|
||||
a = 10 / 2 # ty: ignore[literal-math-error, unused-ignore-comment]
|
||||
a = 10 / 2 # ty: ignore[unused-ignore-comment, literal-math-error]
|
||||
a = 10 / 2 # ty: ignore[unused-ignore-comment] # type: ignore
|
||||
a = 10 / 2 # type: ignore # ty: ignore[unused-ignore-comment]
|
||||
```
|
||||
@@ -45,7 +45,7 @@ a = 10 / 2 # type: ignore # ty: ignore[unused-ignore-comment]
|
||||
|
||||
```py
|
||||
# error: [unused-ignore-comment] "Unused `ty: ignore` directive: 'unused-ignore-comment'"
|
||||
a = 10 / 0 # ty: ignore[division-by-zero, unused-ignore-comment]
|
||||
a = 10 / 0 # ty: ignore[literal-math-error, unused-ignore-comment]
|
||||
```
|
||||
|
||||
## Multiple unused comments
|
||||
@@ -54,13 +54,13 @@ Today, ty emits a diagnostic for every unused code. We might want to group the c
|
||||
some point in the future.
|
||||
|
||||
```py
|
||||
# error: [unused-ignore-comment] "Unused `ty: ignore` directive: 'division-by-zero'"
|
||||
# error: [unused-ignore-comment] "Unused `ty: ignore` directive: 'literal-math-error'"
|
||||
# error: [unused-ignore-comment] "Unused `ty: ignore` directive: 'unresolved-reference'"
|
||||
a = 10 / 2 # ty: ignore[division-by-zero, unresolved-reference]
|
||||
a = 10 / 2 # ty: ignore[literal-math-error, unresolved-reference]
|
||||
|
||||
# error: [unused-ignore-comment] "Unused `ty: ignore` directive: 'invalid-assignment'"
|
||||
# error: [unused-ignore-comment] "Unused `ty: ignore` directive: 'unresolved-reference'"
|
||||
a = 10 / 0 # ty: ignore[invalid-assignment, division-by-zero, unresolved-reference]
|
||||
a = 10 / 0 # ty: ignore[invalid-assignment, literal-math-error, unresolved-reference]
|
||||
```
|
||||
|
||||
## Multiple suppressions
|
||||
@@ -96,14 +96,14 @@ reveal_type(a) # ty: ignore[revealed-type]
|
||||
|
||||
```py
|
||||
a = 10 / 0 # ty : ignore
|
||||
a = 10 / 0 # ty: ignore [ division-by-zero ]
|
||||
a = 10 / 0 # ty: ignore [ literal-math-error ]
|
||||
```
|
||||
|
||||
## Whitespace is optional
|
||||
|
||||
```py
|
||||
# fmt: off
|
||||
a = 10 / 0 #ty:ignore[division-by-zero]
|
||||
a = 10 / 0 #ty:ignore[literal-math-error]
|
||||
```
|
||||
|
||||
## Trailing codes comma
|
||||
@@ -111,13 +111,13 @@ a = 10 / 0 #ty:ignore[division-by-zero]
|
||||
Trailing commas in the codes section are allowed:
|
||||
|
||||
```py
|
||||
a = 10 / 0 # ty: ignore[division-by-zero,]
|
||||
a = 10 / 0 # ty: ignore[literal-math-error,]
|
||||
```
|
||||
|
||||
## Invalid characters in codes
|
||||
|
||||
```py
|
||||
# error: [division-by-zero]
|
||||
# error: [literal-math-error]
|
||||
# error: [invalid-ignore-comment] "Invalid `ty: ignore` comment: expected a alphanumeric character or `-` or `_` as code"
|
||||
a = 10 / 0 # ty: ignore[*-*]
|
||||
```
|
||||
@@ -127,7 +127,7 @@ a = 10 / 0 # ty: ignore[*-*]
|
||||
<!-- blacken-docs:off -->
|
||||
|
||||
```py
|
||||
a = 10 / 0 # ty: ignore[division-by-zero]
|
||||
a = 10 / 0 # ty: ignore[literal-math-error]
|
||||
# ^^^^^^ trailing whitespace
|
||||
```
|
||||
|
||||
@@ -141,7 +141,7 @@ future.
|
||||
```py
|
||||
# error: [unresolved-reference]
|
||||
# error: [invalid-ignore-comment] "Invalid `ty: ignore` comment: expected a comma separating the rule codes"
|
||||
a = x / 0 # ty: ignore[division-by-zero unresolved-reference]
|
||||
a = x / 0 # ty: ignore[literal-math-error unresolved-reference]
|
||||
```
|
||||
|
||||
## Missing closing bracket
|
||||
@@ -157,7 +157,7 @@ a = x / 2 # ty: ignore[unresolved-reference
|
||||
An empty codes array suppresses no-diagnostics and is always useless
|
||||
|
||||
```py
|
||||
# error: [division-by-zero]
|
||||
# error: [literal-math-error]
|
||||
# error: [unused-ignore-comment] "Unused `ty: ignore` without a code"
|
||||
a = 4 / 0 # ty: ignore[]
|
||||
```
|
||||
@@ -170,9 +170,9 @@ severity: `ty: possibly-undefined-reference=error`
|
||||
|
||||
```py
|
||||
# error: [unused-ignore-comment]
|
||||
# ty: ignore[division-by-zero]
|
||||
# ty: ignore[literal-math-error]
|
||||
|
||||
a = 4 / 0 # error: [division-by-zero]
|
||||
a = 4 / 0 # error: [literal-math-error]
|
||||
```
|
||||
|
||||
## Unknown rule
|
||||
@@ -185,7 +185,7 @@ a = 10 + 4 # ty: ignore[is-equal-14]
|
||||
## Code with `lint:` prefix
|
||||
|
||||
```py
|
||||
# error:[unknown-rule] "Unknown rule `lint:division-by-zero`. Did you mean `division-by-zero`?"
|
||||
# error: [division-by-zero]
|
||||
a = 10 / 0 # ty: ignore[lint:division-by-zero]
|
||||
# error:[unknown-rule] "Unknown rule `lint:literal-math-error`. Did you mean `literal-math-error`?"
|
||||
# error: [literal-math-error]
|
||||
a = 10 / 0 # ty: ignore[lint:literal-math-error]
|
||||
```
|
||||
|
||||
@@ -156,6 +156,6 @@ including module docstrings.
|
||||
# error: [unused-ignore-comment] "Unused blanket `type: ignore` directive"
|
||||
# type: ignore
|
||||
|
||||
a = 10 / 0 # error: [division-by-zero]
|
||||
b = a / 0 # error: [division-by-zero]
|
||||
a = 10 / 0 # error: [literal-math-error]
|
||||
b = a / 0 # error: [literal-math-error]
|
||||
```
|
||||
|
||||
@@ -520,7 +520,7 @@ if False:
|
||||
def f():
|
||||
return
|
||||
|
||||
1 / 0 # error: [division-by-zero]
|
||||
1 / 0 # error: [literal-math-error]
|
||||
```
|
||||
|
||||
### Conflicting type information
|
||||
|
||||
@@ -22,7 +22,7 @@ declare_lint! {
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```py
|
||||
/// a = 20 / 2 # ty: ignore[division-by-zero]
|
||||
/// a = 20 / 2 # ty: ignore[literal-math-error]
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
@@ -53,7 +53,7 @@ declare_lint! {
|
||||
/// Use instead:
|
||||
///
|
||||
/// ```py
|
||||
/// a = 20 / 0 # ty: ignore[division-by-zero]
|
||||
/// a = 20 / 0 # ty: ignore[literal-math-error]
|
||||
/// ```
|
||||
pub(crate) static UNKNOWN_RULE = {
|
||||
summary: "detects `ty: ignore` comments that reference unknown rules",
|
||||
@@ -241,7 +241,7 @@ fn check_unused_suppressions(context: &mut CheckSuppressionsContext) {
|
||||
// This looks silly but it's necessary to check again if a `unused-ignore-comment` is indeed unused
|
||||
// in case the "unused" directive comes after it:
|
||||
// ```py
|
||||
// a = 10 / 2 # ty: ignore[unused-ignore-comment, division-by-zero]
|
||||
// a = 10 / 2 # ty: ignore[unused-ignore-comment, literal-math-error]
|
||||
// ```
|
||||
if context.diagnostics.is_used(suppression.id()) {
|
||||
continue;
|
||||
|
||||
@@ -34,7 +34,7 @@ pub(crate) fn register_lints(registry: &mut LintRegistryBuilder) {
|
||||
registry.register_lint(&CONFLICTING_DECLARATIONS);
|
||||
registry.register_lint(&CONFLICTING_METACLASS);
|
||||
registry.register_lint(&CYCLIC_CLASS_DEFINITION);
|
||||
registry.register_lint(&DIVISION_BY_ZERO);
|
||||
registry.register_lint(&LITERAL_MATH_ERROR);
|
||||
registry.register_lint(&DUPLICATE_BASE);
|
||||
registry.register_lint(&DUPLICATE_KW_ONLY);
|
||||
registry.register_lint(&INSTANCE_LAYOUT_CONFLICT);
|
||||
@@ -244,17 +244,20 @@ declare_lint! {
|
||||
|
||||
declare_lint! {
|
||||
/// ## What it does
|
||||
/// It detects division by zero.
|
||||
/// Detects runtime errors that would result from invalid math operations
|
||||
/// between two objects with literal `int` types. Examples include division
|
||||
/// by zero and negative bitshifts.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Dividing by zero raises a `ZeroDivisionError` at runtime.
|
||||
/// These math operations will lead to exceptions being raised at runtime.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```python
|
||||
/// 5 / 0
|
||||
/// 5 / 0 # `ZeroDivisionError`
|
||||
/// 1 << -1 # `ValueError: negative shift count`
|
||||
/// ```
|
||||
pub(crate) static DIVISION_BY_ZERO = {
|
||||
summary: "detects division by zero",
|
||||
pub(crate) static LITERAL_MATH_ERROR = {
|
||||
summary: "detects runtime errors such as division by zero or negative bitshifts",
|
||||
status: LintStatus::preview("1.0.0"),
|
||||
default_level: Level::Ignore,
|
||||
}
|
||||
|
||||
@@ -89,10 +89,10 @@ use crate::types::call::{Binding, Bindings, CallArgumentTypes, CallArguments, Ca
|
||||
use crate::types::class::{CodeGeneratorKind, MetaclassErrorKind, SliceLiteral};
|
||||
use crate::types::diagnostic::{
|
||||
self, CALL_NON_CALLABLE, CONFLICTING_DECLARATIONS, CONFLICTING_METACLASS,
|
||||
CYCLIC_CLASS_DEFINITION, DIVISION_BY_ZERO, DUPLICATE_KW_ONLY, INCONSISTENT_MRO,
|
||||
INVALID_ARGUMENT_TYPE, INVALID_ASSIGNMENT, INVALID_ATTRIBUTE_ACCESS, INVALID_BASE,
|
||||
INVALID_DECLARATION, INVALID_GENERIC_CLASS, INVALID_PARAMETER_DEFAULT, INVALID_TYPE_FORM,
|
||||
INVALID_TYPE_GUARD_CALL, INVALID_TYPE_VARIABLE_CONSTRAINTS, IncompatibleBases,
|
||||
CYCLIC_CLASS_DEFINITION, DUPLICATE_KW_ONLY, INCONSISTENT_MRO, INVALID_ARGUMENT_TYPE,
|
||||
INVALID_ASSIGNMENT, INVALID_ATTRIBUTE_ACCESS, INVALID_BASE, INVALID_DECLARATION,
|
||||
INVALID_GENERIC_CLASS, INVALID_PARAMETER_DEFAULT, INVALID_TYPE_FORM, INVALID_TYPE_GUARD_CALL,
|
||||
INVALID_TYPE_VARIABLE_CONSTRAINTS, IncompatibleBases, LITERAL_MATH_ERROR,
|
||||
POSSIBLY_UNBOUND_IMPLICIT_CALL, POSSIBLY_UNBOUND_IMPORT, TypeCheckDiagnostics,
|
||||
UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE, UNRESOLVED_IMPORT, UNRESOLVED_REFERENCE,
|
||||
UNSUPPORTED_OPERATOR, report_implicit_return_type, report_instance_layout_conflict,
|
||||
@@ -1512,42 +1512,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Raise a diagnostic if the given type cannot be divided by zero.
|
||||
///
|
||||
/// Expects the resolved type of the left side of the binary expression.
|
||||
fn check_division_by_zero(
|
||||
&mut self,
|
||||
node: AnyNodeRef<'_>,
|
||||
op: ast::Operator,
|
||||
left: Type<'db>,
|
||||
) -> bool {
|
||||
match left {
|
||||
Type::BooleanLiteral(_) | Type::IntLiteral(_) => {}
|
||||
Type::NominalInstance(instance)
|
||||
if matches!(
|
||||
instance.class.known(self.db()),
|
||||
Some(KnownClass::Float | KnownClass::Int | KnownClass::Bool)
|
||||
) => {}
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
let (op, by_zero) = match op {
|
||||
ast::Operator::Div => ("divide", "by zero"),
|
||||
ast::Operator::FloorDiv => ("floor divide", "by zero"),
|
||||
ast::Operator::Mod => ("reduce", "modulo zero"),
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
if let Some(builder) = self.context.report_lint(&DIVISION_BY_ZERO, node) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
"Cannot {op} object of type `{}` {by_zero}",
|
||||
left.display(self.db())
|
||||
));
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn add_binding(&mut self, node: AnyNodeRef, binding: Definition<'db>, ty: Type<'db>) {
|
||||
debug_assert!(
|
||||
binding
|
||||
@@ -6341,7 +6305,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
(_, Type::Never) => Type::Never,
|
||||
|
||||
(ast::UnaryOp::UAdd, Type::IntLiteral(value)) => Type::IntLiteral(value),
|
||||
(ast::UnaryOp::USub, Type::IntLiteral(value)) => Type::IntLiteral(-value),
|
||||
(ast::UnaryOp::USub, Type::IntLiteral(value)) => value
|
||||
.checked_neg()
|
||||
.map(Type::IntLiteral)
|
||||
.unwrap_or_else(|| KnownClass::Int.to_instance(self.db())),
|
||||
(ast::UnaryOp::Invert, Type::IntLiteral(value)) => Type::IntLiteral(!value),
|
||||
|
||||
(ast::UnaryOp::UAdd, Type::BooleanLiteral(bool)) => Type::IntLiteral(i64::from(bool)),
|
||||
@@ -6460,39 +6427,82 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
fn infer_binary_expression_type(
|
||||
&mut self,
|
||||
node: AnyNodeRef<'_>,
|
||||
mut emitted_division_by_zero_diagnostic: bool,
|
||||
mut emitted_bad_rhs_diagnostic: bool,
|
||||
left_ty: Type<'db>,
|
||||
right_ty: Type<'db>,
|
||||
op: ast::Operator,
|
||||
) -> Option<Type<'db>> {
|
||||
// Check for division by zero; this doesn't change the inferred type for the expression, but
|
||||
// may emit a diagnostic
|
||||
if !emitted_division_by_zero_diagnostic
|
||||
&& matches!(
|
||||
(op, right_ty),
|
||||
let check_bad_rhs = || {
|
||||
let lhs_int = match left_ty {
|
||||
Type::BooleanLiteral(_) | Type::IntLiteral(_) => true,
|
||||
Type::NominalInstance(instance)
|
||||
if matches!(
|
||||
instance.class.known(self.db()),
|
||||
Some(KnownClass::Int | KnownClass::Bool)
|
||||
) =>
|
||||
{
|
||||
true
|
||||
}
|
||||
Type::NominalInstance(instance)
|
||||
if matches!(
|
||||
instance.class.known(self.db()),
|
||||
Some(KnownClass::Float | KnownClass::Complex)
|
||||
) =>
|
||||
{
|
||||
false
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let (op, by_what) = match (op, lhs_int) {
|
||||
(ast::Operator::Div, _) => ("divide", "by zero"),
|
||||
(ast::Operator::FloorDiv, _) => ("floor divide", "by zero"),
|
||||
(ast::Operator::Mod, _) => ("reduce", "modulo zero"),
|
||||
(ast::Operator::LShift, true) => ("left shift", "by a negative value"),
|
||||
(ast::Operator::RShift, true) => ("right shift", "by a negative value"),
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
if let Some(builder) = self.context.report_lint(&LITERAL_MATH_ERROR, node) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
"Cannot {op} object of type `{}` {by_what}",
|
||||
left_ty.display(self.db())
|
||||
));
|
||||
}
|
||||
|
||||
true
|
||||
};
|
||||
|
||||
// Check for division by zero or shift by a negative value; this doesn't change the inferred
|
||||
// type for the expression, but may emit a diagnostic
|
||||
if !emitted_bad_rhs_diagnostic {
|
||||
emitted_bad_rhs_diagnostic = match (op, right_ty) {
|
||||
(
|
||||
ast::Operator::Div | ast::Operator::FloorDiv | ast::Operator::Mod,
|
||||
Type::IntLiteral(0) | Type::BooleanLiteral(false)
|
||||
)
|
||||
)
|
||||
{
|
||||
emitted_division_by_zero_diagnostic = self.check_division_by_zero(node, op, left_ty);
|
||||
Type::IntLiteral(0) | Type::BooleanLiteral(false),
|
||||
) => check_bad_rhs(),
|
||||
(ast::Operator::LShift | ast::Operator::RShift, Type::IntLiteral(n)) if n < 0 => {
|
||||
check_bad_rhs()
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
match (left_ty, right_ty, op) {
|
||||
(Type::Union(lhs_union), rhs, _) => lhs_union.try_map(self.db(), |lhs_element| {
|
||||
self.infer_binary_expression_type(
|
||||
node,
|
||||
emitted_division_by_zero_diagnostic,
|
||||
emitted_bad_rhs_diagnostic,
|
||||
*lhs_element,
|
||||
rhs,
|
||||
op,
|
||||
)
|
||||
}),
|
||||
|
||||
(lhs, Type::Union(rhs_union), _) => rhs_union.try_map(self.db(), |rhs_element| {
|
||||
self.infer_binary_expression_type(
|
||||
node,
|
||||
emitted_division_by_zero_diagnostic,
|
||||
emitted_bad_rhs_diagnostic,
|
||||
lhs,
|
||||
*rhs_element,
|
||||
op,
|
||||
@@ -6595,6 +6605,22 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
Some(Type::IntLiteral(n ^ m))
|
||||
}
|
||||
|
||||
(Type::IntLiteral(n), Type::IntLiteral(m), ast::Operator::LShift) => Some(
|
||||
u32::try_from(m)
|
||||
.ok()
|
||||
.and_then(|m| n.checked_shl(m))
|
||||
.map(Type::IntLiteral)
|
||||
.unwrap_or_else(|| KnownClass::Int.to_instance(self.db())),
|
||||
),
|
||||
|
||||
(Type::IntLiteral(n), Type::IntLiteral(m), ast::Operator::RShift) => Some(
|
||||
u32::try_from(m)
|
||||
.ok()
|
||||
.map(|m| n >> m.clamp(0, 63))
|
||||
.map(Type::IntLiteral)
|
||||
.unwrap_or_else(|| KnownClass::Int.to_instance(self.db())),
|
||||
),
|
||||
|
||||
(Type::BytesLiteral(lhs), Type::BytesLiteral(rhs), ast::Operator::Add) => {
|
||||
let bytes = [lhs.value(self.db()), rhs.value(self.db())].concat();
|
||||
Some(Type::bytes_literal(self.db(), &bytes))
|
||||
@@ -6661,7 +6687,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
(Type::BooleanLiteral(b1), Type::BooleanLiteral(_) | Type::IntLiteral(_), op) => self
|
||||
.infer_binary_expression_type(
|
||||
node,
|
||||
emitted_division_by_zero_diagnostic,
|
||||
emitted_bad_rhs_diagnostic,
|
||||
Type::IntLiteral(i64::from(b1)),
|
||||
right_ty,
|
||||
op,
|
||||
@@ -6669,7 +6695,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
(Type::IntLiteral(_), Type::BooleanLiteral(b2), op) => self
|
||||
.infer_binary_expression_type(
|
||||
node,
|
||||
emitted_division_by_zero_diagnostic,
|
||||
emitted_bad_rhs_diagnostic,
|
||||
left_ty,
|
||||
Type::IntLiteral(i64::from(b2)),
|
||||
op,
|
||||
|
||||
24
ty.schema.json
generated
24
ty.schema.json
generated
@@ -331,16 +331,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"division-by-zero": {
|
||||
"title": "detects division by zero",
|
||||
"description": "## What it does\nIt detects division by zero.\n\n## Why is this bad?\nDividing by zero raises a `ZeroDivisionError` at runtime.\n\n## Examples\n```python\n5 / 0\n```",
|
||||
"default": "ignore",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Level"
|
||||
}
|
||||
]
|
||||
},
|
||||
"duplicate-base": {
|
||||
"title": "detects class definitions with duplicate bases",
|
||||
"description": "## What it does\nChecks for class definitions with duplicate bases.\n\n## Why is this bad?\nClass definitions with duplicate bases raise `TypeError` at runtime.\n\n## Examples\n```python\nclass A: ...\n\n# TypeError: duplicate base class\nclass B(A, A): ...\n```",
|
||||
@@ -661,6 +651,16 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"literal-math-error": {
|
||||
"title": "detects runtime errors such as division by zero or negative bitshifts",
|
||||
"description": "## What it does\nDetects runtime errors that would result from invalid math operations\nbetween two objects with literal `int` types. Examples include division\nby zero and negative bitshifts.\n\n## Why is this bad?\nThese math operations will lead to exceptions being raised at runtime.\n\n## Examples\n```python\n5 / 0 # `ZeroDivisionError`\n1 << -1 # `ValueError: negative shift count`\n```",
|
||||
"default": "ignore",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Level"
|
||||
}
|
||||
]
|
||||
},
|
||||
"missing-argument": {
|
||||
"title": "detects missing required arguments in a call",
|
||||
"description": "## What it does\nChecks for missing required arguments in a call.\n\n## Why is this bad?\nFailing to provide a required argument will raise a `TypeError` at runtime.\n\n## Examples\n```python\ndef func(x: int): ...\nfunc() # TypeError: func() missing 1 required positional argument: 'x'\n```",
|
||||
@@ -843,7 +843,7 @@
|
||||
},
|
||||
"unknown-rule": {
|
||||
"title": "detects `ty: ignore` comments that reference unknown rules",
|
||||
"description": "## What it does\nChecks for `ty: ignore[code]` where `code` isn't a known lint rule.\n\n## Why is this bad?\nA `ty: ignore[code]` directive with a `code` that doesn't match\nany known rule will not suppress any type errors, and is probably a mistake.\n\n## Examples\n```py\na = 20 / 0 # ty: ignore[division-by-zer]\n```\n\nUse instead:\n\n```py\na = 20 / 0 # ty: ignore[division-by-zero]\n```",
|
||||
"description": "## What it does\nChecks for `ty: ignore[code]` where `code` isn't a known lint rule.\n\n## Why is this bad?\nA `ty: ignore[code]` directive with a `code` that doesn't match\nany known rule will not suppress any type errors, and is probably a mistake.\n\n## Examples\n```py\na = 20 / 0 # ty: ignore[division-by-zer]\n```\n\nUse instead:\n\n```py\na = 20 / 0 # ty: ignore[literal-math-error]\n```",
|
||||
"default": "warn",
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -913,7 +913,7 @@
|
||||
},
|
||||
"unused-ignore-comment": {
|
||||
"title": "detects unused `type: ignore` comments",
|
||||
"description": "## What it does\nChecks for `type: ignore` or `ty: ignore` directives that are no longer applicable.\n\n## Why is this bad?\nA `type: ignore` directive that no longer matches any diagnostic violations is likely\nincluded by mistake, and should be removed to avoid confusion.\n\n## Examples\n```py\na = 20 / 2 # ty: ignore[division-by-zero]\n```\n\nUse instead:\n\n```py\na = 20 / 2\n```",
|
||||
"description": "## What it does\nChecks for `type: ignore` or `ty: ignore` directives that are no longer applicable.\n\n## Why is this bad?\nA `type: ignore` directive that no longer matches any diagnostic violations is likely\nincluded by mistake, and should be removed to avoid confusion.\n\n## Examples\n```py\na = 20 / 2 # ty: ignore[literal-math-error]\n```\n\nUse instead:\n\n```py\na = 20 / 2\n```",
|
||||
"default": "ignore",
|
||||
"oneOf": [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user