Merge remote-tracking branch 'origin/main' into dcreager/ty1874

* origin/main:
  Update MSRV to 1.90 (#21987)
  [ty] Improve check enforcing that an overloaded function must have an implementation (#21978)
  Update actions/checkout digest to 8e8c483 (#21982)
  [ty] Use `ParamSpec` without the attr for inferable check (#21934)
  [ty] Emit diagnostic when a type variable with a default is followed by one without a default (#21787)
  [ty] Fix callout syntax in configuration mkdocs (#1875) (#21961)
  Update debug_assert which pointed at missing method (#21969)
  [ty] Add support for `__qualname__` and other implicit class attributes (#21966)
This commit is contained in:
Douglas Creager 2025-12-15 08:55:51 -05:00
commit 959ae042b8
31 changed files with 797 additions and 117 deletions

View File

@ -60,7 +60,7 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
with:
persist-credentials: false
submodules: recursive
@ -123,7 +123,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
with:
persist-credentials: false
submodules: recursive
@ -174,7 +174,7 @@ jobs:
outputs:
val: ${{ steps.host.outputs.manifest }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
with:
persist-credentials: false
submodules: recursive
@ -250,7 +250,7 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
with:
persist-credentials: false
submodules: recursive

View File

@ -5,7 +5,7 @@ resolver = "2"
[workspace.package]
# Please update rustfmt.toml when bumping the Rust edition
edition = "2024"
rust-version = "1.89"
rust-version = "1.90"
homepage = "https://docs.astral.sh/ruff"
documentation = "https://docs.astral.sh/ruff"
repository = "https://github.com/astral-sh/ruff"

View File

@ -10,7 +10,7 @@ use anyhow::bail;
use clap::builder::Styles;
use clap::builder::styling::{AnsiColor, Effects};
use clap::builder::{TypedValueParser, ValueParserFactory};
use clap::{Parser, Subcommand, command};
use clap::{Parser, Subcommand};
use colored::Colorize;
use itertools::Itertools;
use path_absolutize::path_dedot;

View File

@ -9,7 +9,7 @@ use std::sync::mpsc::channel;
use anyhow::Result;
use clap::CommandFactory;
use colored::Colorize;
use log::{error, warn};
use log::error;
use notify::{RecursiveMode, Watcher, recommended_watcher};
use args::{GlobalConfigArgs, ServerCommand};

View File

@ -144,8 +144,8 @@ fn emit_field(output: &mut String, name: &str, field: &OptionField, parents: &[S
output.push('\n');
if let Some(deprecated) = &field.deprecated {
output.push_str("> [!WARN] \"Deprecated\"\n");
output.push_str("> This option has been deprecated");
output.push_str("!!! warning \"Deprecated\"\n");
output.push_str(" This option has been deprecated");
if let Some(since) = deprecated.since {
write!(output, " in {since}").unwrap();

View File

@ -39,7 +39,7 @@ impl Edit {
/// Creates an edit that replaces the content in `range` with `content`.
pub fn range_replacement(content: String, range: TextRange) -> Self {
debug_assert!(!content.is_empty(), "Prefer `Fix::deletion`");
debug_assert!(!content.is_empty(), "Prefer `Edit::deletion`");
Self {
content: Some(Box::from(content)),

View File

@ -337,7 +337,7 @@ macro_rules! best_fitting {
#[cfg(test)]
mod tests {
use crate::prelude::*;
use crate::{FormatState, SimpleFormatOptions, VecBuffer, write};
use crate::{FormatState, SimpleFormatOptions, VecBuffer};
struct TestFormat;
@ -385,8 +385,8 @@ mod tests {
#[test]
fn best_fitting_variants_print_as_lists() {
use crate::Formatted;
use crate::prelude::*;
use crate::{Formatted, format, format_args};
// The second variant below should be selected when printing at a width of 30
let formatted_best_fitting = format!(

View File

@ -286,12 +286,7 @@ pub(crate) fn add_argument(argument: &str, arguments: &Arguments, tokens: &Token
/// Generic function to add a (regular) parameter to a function definition.
pub(crate) fn add_parameter(parameter: &str, parameters: &Parameters, source: &str) -> Edit {
if let Some(last) = parameters
.args
.iter()
.filter(|arg| arg.default.is_none())
.next_back()
{
if let Some(last) = parameters.args.iter().rfind(|arg| arg.default.is_none()) {
// Case 1: at least one regular parameter, so append after the last one.
Edit::insertion(format!(", {parameter}"), last.end())
} else if !parameters.args.is_empty() {

View File

@ -146,7 +146,7 @@ fn reverse_comparison(expr: &Expr, locator: &Locator, stylist: &Stylist) -> Resu
let left = (*comparison.left).clone();
// Copy the right side to the left side.
comparison.left = Box::new(comparison.comparisons[0].comparator.clone());
*comparison.left = comparison.comparisons[0].comparator.clone();
// Copy the left side to the right side.
comparison.comparisons[0].comparator = left;

View File

@ -1247,6 +1247,7 @@ impl<'a> Generator<'a> {
self.p_bytes_repr(&bytes_literal.value, bytes_literal.flags);
}
}
#[expect(clippy::eq_op)]
Expr::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => {
static INF_STR: &str = "1e309";
assert_eq!(f64::MAX_10_EXP, 308);

View File

@ -3,7 +3,7 @@
use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use clap::{Parser, ValueEnum, command};
use clap::{Parser, ValueEnum};
use ruff_formatter::SourceCode;
use ruff_python_ast::{PySourceType, PythonVersion};

View File

@ -432,8 +432,8 @@ respect-ignore-files = false
### `root`
> [!WARN] "Deprecated"
> This option has been deprecated. Use `environment.root` instead.
!!! warning "Deprecated"
This option has been deprecated. Use `environment.root` instead.
The root of the project, used for finding first-party modules.

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

@ -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#L2003" 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#L1673" 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.35">0.0.1-alpha.35</a> ·
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-frozen-dataclass-subclass" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2224" target="_blank">View source</a>
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2229" target="_blank">View source</a>
</small>
@ -848,16 +848,21 @@ Checks for the creation of invalid generic classes
**Why is this bad?**
There are several requirements that you must follow when defining a generic class.
Many of these result in `TypeError` being raised at runtime if they are violated.
**Examples**
```python
from typing import Generic, TypeVar
from typing_extensions import Generic, TypeVar
T = TypeVar("T") # okay
T = TypeVar("T")
U = TypeVar("U", default=int)
# error: class uses both PEP-695 syntax and legacy syntax
class C[U](Generic[T]): ...
# error: type parameter with default comes before type parameter without default
class D(Generic[U, T]): ...
```
**References**
@ -909,7 +914,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#L922" target="_blank">View source</a>
</small>
@ -944,7 +949,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#L1019" target="_blank">View source</a>
</small>
@ -978,7 +983,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#L2131" target="_blank">View source</a>
</small>
@ -1139,7 +1144,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#L995" target="_blank">View source</a>
</small>
@ -1169,7 +1174,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#L1046" target="_blank">View source</a>
</small>
@ -1219,7 +1224,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#L1145" target="_blank">View source</a>
</small>
@ -1245,7 +1250,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#L950" target="_blank">View source</a>
</small>
@ -1310,7 +1315,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#L1165" target="_blank">View source</a>
</small>
@ -1384,7 +1389,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#L1208" target="_blank">View source</a>
</small>
@ -1442,7 +1447,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#L974" target="_blank">View source</a>
</small>
@ -1469,7 +1474,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#L1440" target="_blank">View source</a>
</small>
@ -1516,7 +1521,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#L1247" target="_blank">View source</a>
</small>
@ -1546,7 +1551,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#L1271" target="_blank">View source</a>
</small>
@ -1576,7 +1581,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#L1323" target="_blank">View source</a>
</small>
@ -1610,7 +1615,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#L1295" target="_blank">View source</a>
</small>
@ -1644,7 +1649,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#L1351" target="_blank">View source</a>
</small>
@ -1679,7 +1684,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#L1380" target="_blank">View source</a>
</small>
@ -1704,7 +1709,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#L2104" target="_blank">View source</a>
</small>
@ -1737,7 +1742,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#L1399" target="_blank">View source</a>
</small>
@ -1766,7 +1771,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#L1422" target="_blank">View source</a>
</small>
@ -1790,7 +1795,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#L1481" target="_blank">View source</a>
</small>
@ -1816,7 +1821,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#L1646" target="_blank">View source</a>
</small>
@ -1849,7 +1854,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#L1532" target="_blank">View source</a>
</small>
@ -1876,7 +1881,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#L1857" target="_blank">View source</a>
</small>
@ -1934,7 +1939,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#L1979" target="_blank">View source</a>
</small>
@ -1964,7 +1969,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#L1623" target="_blank">View source</a>
</small>
@ -1993,7 +1998,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#L1791" target="_blank">View source</a>
</small>
@ -2027,7 +2032,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#L1731" target="_blank">View source</a>
</small>
@ -2054,7 +2059,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#L1709" target="_blank">View source</a>
</small>
@ -2082,7 +2087,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#L1752" target="_blank">View source</a>
</small>
@ -2128,7 +2133,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#L1836" target="_blank">View source</a>
</small>
@ -2155,7 +2160,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#L1878" target="_blank">View source</a>
</small>
@ -2183,7 +2188,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#L1900" target="_blank">View source</a>
</small>
@ -2208,7 +2213,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#L1919" target="_blank">View source</a>
</small>
@ -2233,7 +2238,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#L1501" target="_blank">View source</a>
</small>
@ -2270,7 +2275,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#L1938" target="_blank">View source</a>
</small>
@ -2298,7 +2303,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#L1960" target="_blank">View source</a>
</small>
@ -2452,7 +2457,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#L1553" target="_blank">View source</a>
</small>
@ -2512,7 +2517,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#L1575" target="_blank">View source</a>
</small>
@ -2544,7 +2549,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#L2031" target="_blank">View source</a>
</small>
@ -2571,7 +2576,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#L1818" target="_blank">View source</a>
</small>
@ -2595,7 +2600,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#L2052" target="_blank">View source</a>
</small>
@ -2692,7 +2697,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#L1089" target="_blank">View source</a>
</small>
@ -2779,7 +2784,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#L1601" target="_blank">View source</a>
</small>

View File

@ -4711,8 +4711,7 @@ from os.<CURSOR>
let last_nonunderscore = test
.completions()
.iter()
.filter(|c| !c.name.starts_with('_'))
.next_back()
.rfind(|c| !c.name.starts_with('_'))
.unwrap();
assert_eq!(&last_nonunderscore.name, "type_check_only");

View File

@ -27,7 +27,6 @@ use std::iter::FusedIterator;
use std::panic::{AssertUnwindSafe, UnwindSafe};
use std::sync::Arc;
use thiserror::Error;
use tracing::error;
use ty_python_semantic::add_inferred_python_version_hint_to_diagnostic;
use ty_python_semantic::lint::RuleSelection;
use ty_python_semantic::types::check_types;

View File

@ -0,0 +1,43 @@
# Invalid Order of Legacy Type Parameters
<!-- snapshot-diagnostics -->
```toml
[environment]
python-version = "3.13"
```
```py
from typing import TypeVar, Generic, Protocol
T1 = TypeVar("T1", default=int)
T2 = TypeVar("T2")
T3 = TypeVar("T3")
DefaultStrT = TypeVar("DefaultStrT", default=str)
class SubclassMe(Generic[T1, DefaultStrT]):
x: DefaultStrT
class Baz(SubclassMe[int, DefaultStrT]):
pass
# error: [invalid-generic-class] "Type parameter `T2` without a default cannot follow earlier parameter `T1` with a default"
class Foo(Generic[T1, T2]):
pass
class Bar(Generic[T2, T1, T3]): # error: [invalid-generic-class]
pass
class Spam(Generic[T1, T2, DefaultStrT, T3]): # error: [invalid-generic-class]
pass
class Ham(Protocol[T1, T2, DefaultStrT, T3]): # error: [invalid-generic-class]
pass
class VeryBad(
Protocol[T1, T2, DefaultStrT, T3], # error: [invalid-generic-class]
Generic[T1, T2, DefaultStrT, T3],
): ...
```

View File

@ -424,9 +424,8 @@ p3 = ParamSpecWithDefault4[[int], [str]]()
reveal_type(p3.attr1) # revealed: (int, /) -> None
reveal_type(p3.attr2) # revealed: (str, /) -> None
# TODO: error
# Un-ordered type variables as the default of `PAnother` is `P`
class ParamSpecWithDefault5(Generic[PAnother, P]):
class ParamSpecWithDefault5(Generic[PAnother, P]): # error: [invalid-generic-class]
attr: Callable[PAnother, None]
# TODO: error

View File

@ -670,3 +670,59 @@ reveal_type(with_parameters(int_int, 1)) # revealed: Overload[(x: int) -> str,
# error: [invalid-argument-type]
reveal_type(with_parameters(int_int, "a")) # revealed: Overload[(x: int) -> str, (x: str) -> str]
```
## ParamSpec attribute assignability
When comparing signatures with `ParamSpec` attributes (`P.args` and `P.kwargs`), two different
inferable `ParamSpec` attributes with the same kind are assignable to each other. This enables
method overrides where both methods have their own `ParamSpec`.
### Same attribute kind, both inferable
```py
from typing import Callable
class Parent:
def method[**P](self, callback: Callable[P, None]) -> Callable[P, None]:
return callback
class Child1(Parent):
# This is a valid override: Q.args matches P.args, Q.kwargs matches P.kwargs
def method[**Q](self, callback: Callable[Q, None]) -> Callable[Q, None]:
return callback
# Both signatures use ParamSpec, so they should be compatible
def outer[**P](f: Callable[P, int]) -> Callable[P, int]:
def inner[**Q](g: Callable[Q, int]) -> Callable[Q, int]:
return g
return inner(f)
```
We can explicitly mark it as an override using the `@override` decorator.
```py
from typing import override
class Child2(Parent):
@override
def method[**Q](self, callback: Callable[Q, None]) -> Callable[Q, None]:
return callback
```
### One `ParamSpec` not inferable
Here, `P` is in a non-inferable position while `Q` is inferable. So, they are not considered
assignable.
```py
from typing import Callable
class Container[**P]:
def method(self, f: Callable[P, None]) -> Callable[P, None]:
return f
def try_assign[**Q](self, f: Callable[Q, None]) -> Callable[Q, None]:
# error: [invalid-return-type] "Return type does not match returned value: expected `(**Q@try_assign) -> None`, found `(**P@Container) -> None`"
# error: [invalid-argument-type] "Argument to bound method `method` is incorrect: Expected `(**P@Container) -> None`, found `(**Q@try_assign) -> None`"
return self.method(f)
```

View File

@ -418,6 +418,18 @@ Using the `@abstractmethod` decorator requires that the class's metaclass is `AB
from it.
```py
from abc import ABCMeta
class CustomAbstractMetaclass(ABCMeta): ...
class Fine(metaclass=CustomAbstractMetaclass):
@overload
@abstractmethod
def f(self, x: int) -> int: ...
@overload
@abstractmethod
def f(self, x: str) -> str: ...
class Foo:
@overload
@abstractmethod
@ -448,6 +460,52 @@ class PartialFoo(ABC):
def f(self, x: str) -> str: ...
```
#### `TYPE_CHECKING` blocks
As in other areas of ty, we treat `TYPE_CHECKING` blocks the same as "inline stub files", so we
permit overloaded functions to exist without an implementation if all overloads are defined inside
an `if TYPE_CHECKING` block:
```py
from typing import overload, TYPE_CHECKING
if TYPE_CHECKING:
@overload
def a() -> str: ...
@overload
def a(x: int) -> int: ...
class F:
@overload
def method(self) -> None: ...
@overload
def method(self, x: int) -> int: ...
class G:
if TYPE_CHECKING:
@overload
def method(self) -> None: ...
@overload
def method(self, x: int) -> int: ...
if TYPE_CHECKING:
@overload
def b() -> str: ...
if TYPE_CHECKING:
@overload
def b(x: int) -> int: ...
if TYPE_CHECKING:
@overload
def c() -> None: ...
# not all overloads are in a `TYPE_CHECKING` block, so this is an error
@overload
# error: [invalid-overload]
def c(x: int) -> int: ...
```
### `@overload`-decorated functions with non-stub bodies
<!-- snapshot-diagnostics -->

View File

@ -0,0 +1,120 @@
# Implicit class body attributes
## Class body implicit attributes
Python makes certain names available implicitly inside class body scopes. These are `__qualname__`,
`__module__`, and `__doc__`, as documented at
<https://docs.python.org/3/reference/datamodel.html#creating-the-class-object>.
```py
class Foo:
reveal_type(__qualname__) # revealed: str
reveal_type(__module__) # revealed: str
reveal_type(__doc__) # revealed: str | None
```
## `__firstlineno__` (Python 3.13+)
Python 3.13 added `__firstlineno__` to the class body namespace.
### Available in Python 3.13+
```toml
[environment]
python-version = "3.13"
```
```py
class Foo:
reveal_type(__firstlineno__) # revealed: int
```
### Not available in Python 3.12 and earlier
```toml
[environment]
python-version = "3.12"
```
```py
class Foo:
# error: [unresolved-reference]
__firstlineno__
```
## Nested classes
These implicit attributes are also available in nested classes, and refer to the nested class:
```py
class Outer:
class Inner:
reveal_type(__qualname__) # revealed: str
reveal_type(__module__) # revealed: str
```
## Class body implicit attributes have priority over globals
If a global variable with the same name exists, the class body implicit attribute takes priority
within the class body:
```py
__qualname__ = 42
__module__ = 42
class Foo:
# Inside the class body, these are the implicit class attributes
reveal_type(__qualname__) # revealed: str
reveal_type(__module__) # revealed: str
# Outside the class, the globals are visible
reveal_type(__qualname__) # revealed: Literal[42]
reveal_type(__module__) # revealed: Literal[42]
```
## `__firstlineno__` has priority over globals (Python 3.13+)
The same applies to `__firstlineno__` on Python 3.13+:
```toml
[environment]
python-version = "3.13"
```
```py
__firstlineno__ = "not an int"
class Foo:
reveal_type(__firstlineno__) # revealed: int
reveal_type(__firstlineno__) # revealed: Literal["not an int"]
```
## Class body implicit attributes are not visible in methods
The implicit class body attributes are only available directly in the class body, not in nested
function scopes (methods):
```py
class Foo:
# Available directly in the class body
x = __qualname__
reveal_type(x) # revealed: str
def method(self):
# Not available in methods - falls back to builtins/globals
# error: [unresolved-reference]
__qualname__
```
## Real-world use case: logging
A common use case is defining a logger with the class name:
```py
import logging
class MyClass:
logger = logging.getLogger(__qualname__)
reveal_type(logger) # revealed: Logger
```

View File

@ -0,0 +1,190 @@
---
source: crates/ty_test/src/lib.rs
expression: snapshot
---
---
mdtest name: invalid_type_parameter_order.md - Invalid Order of Legacy Type Parameters
mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_type_parameter_order.md
---
# Python source files
## mdtest_snippet.py
```
1 | from typing import TypeVar, Generic, Protocol
2 |
3 | T1 = TypeVar("T1", default=int)
4 |
5 | T2 = TypeVar("T2")
6 | T3 = TypeVar("T3")
7 |
8 | DefaultStrT = TypeVar("DefaultStrT", default=str)
9 |
10 | class SubclassMe(Generic[T1, DefaultStrT]):
11 | x: DefaultStrT
12 |
13 | class Baz(SubclassMe[int, DefaultStrT]):
14 | pass
15 |
16 | # error: [invalid-generic-class] "Type parameter `T2` without a default cannot follow earlier parameter `T1` with a default"
17 | class Foo(Generic[T1, T2]):
18 | pass
19 |
20 | class Bar(Generic[T2, T1, T3]): # error: [invalid-generic-class]
21 | pass
22 |
23 | class Spam(Generic[T1, T2, DefaultStrT, T3]): # error: [invalid-generic-class]
24 | pass
25 |
26 | class Ham(Protocol[T1, T2, DefaultStrT, T3]): # error: [invalid-generic-class]
27 | pass
28 |
29 | class VeryBad(
30 | Protocol[T1, T2, DefaultStrT, T3], # error: [invalid-generic-class]
31 | Generic[T1, T2, DefaultStrT, T3],
32 | ): ...
```
# Diagnostics
```
error[invalid-generic-class]: Type parameters without defaults cannot follow type parameters with defaults
--> src/mdtest_snippet.py:17:19
|
16 | # error: [invalid-generic-class] "Type parameter `T2` without a default cannot follow earlier parameter `T1` with a default"
17 | class Foo(Generic[T1, T2]):
| ^^^^^^
| |
| Type variable `T2` does not have a default
| Earlier TypeVar `T1` does
18 | pass
|
::: src/mdtest_snippet.py:3:1
|
1 | from typing import TypeVar, Generic, Protocol
2 |
3 | T1 = TypeVar("T1", default=int)
| ------------------------------- `T1` defined here
4 |
5 | T2 = TypeVar("T2")
| ------------------ `T2` defined here
6 | T3 = TypeVar("T3")
|
info: rule `invalid-generic-class` is enabled by default
```
```
error[invalid-generic-class]: Type parameters without defaults cannot follow type parameters with defaults
--> src/mdtest_snippet.py:20:19
|
18 | pass
19 |
20 | class Bar(Generic[T2, T1, T3]): # error: [invalid-generic-class]
| ^^^^^^^^^^
| |
| Type variable `T3` does not have a default
| Earlier TypeVar `T1` does
21 | pass
|
::: src/mdtest_snippet.py:3:1
|
1 | from typing import TypeVar, Generic, Protocol
2 |
3 | T1 = TypeVar("T1", default=int)
| ------------------------------- `T1` defined here
4 |
5 | T2 = TypeVar("T2")
6 | T3 = TypeVar("T3")
| ------------------ `T3` defined here
7 |
8 | DefaultStrT = TypeVar("DefaultStrT", default=str)
|
info: rule `invalid-generic-class` is enabled by default
```
```
error[invalid-generic-class]: Type parameters without defaults cannot follow type parameters with defaults
--> src/mdtest_snippet.py:23:20
|
21 | pass
22 |
23 | class Spam(Generic[T1, T2, DefaultStrT, T3]): # error: [invalid-generic-class]
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
| Type variables `T2` and `T3` do not have defaults
| Earlier TypeVar `T1` does
24 | pass
|
::: src/mdtest_snippet.py:3:1
|
1 | from typing import TypeVar, Generic, Protocol
2 |
3 | T1 = TypeVar("T1", default=int)
| ------------------------------- `T1` defined here
4 |
5 | T2 = TypeVar("T2")
| ------------------ `T2` defined here
6 | T3 = TypeVar("T3")
|
info: rule `invalid-generic-class` is enabled by default
```
```
error[invalid-generic-class]: Type parameters without defaults cannot follow type parameters with defaults
--> src/mdtest_snippet.py:26:20
|
24 | pass
25 |
26 | class Ham(Protocol[T1, T2, DefaultStrT, T3]): # error: [invalid-generic-class]
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
| Type variables `T2` and `T3` do not have defaults
| Earlier TypeVar `T1` does
27 | pass
|
::: src/mdtest_snippet.py:3:1
|
1 | from typing import TypeVar, Generic, Protocol
2 |
3 | T1 = TypeVar("T1", default=int)
| ------------------------------- `T1` defined here
4 |
5 | T2 = TypeVar("T2")
| ------------------ `T2` defined here
6 | T3 = TypeVar("T3")
|
info: rule `invalid-generic-class` is enabled by default
```
```
error[invalid-generic-class]: Type parameters without defaults cannot follow type parameters with defaults
--> src/mdtest_snippet.py:30:14
|
29 | class VeryBad(
30 | Protocol[T1, T2, DefaultStrT, T3], # error: [invalid-generic-class]
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
| Type variables `T2` and `T3` do not have defaults
| Earlier TypeVar `T1` does
31 | Generic[T1, T2, DefaultStrT, T3],
32 | ): ...
|
::: src/mdtest_snippet.py:3:1
|
1 | from typing import TypeVar, Generic, Protocol
2 |
3 | T1 = TypeVar("T1", default=int)
| ------------------------------- `T1` defined here
4 |
5 | T2 = TypeVar("T2")
| ------------------ `T2` defined here
6 | T3 = TypeVar("T3")
|
info: rule `invalid-generic-class` is enabled by default
```

View File

@ -42,7 +42,11 @@ error[invalid-overload]: Overloads for function `func` must be followed by a non
9 | class Foo:
|
info: Attempting to call `func` will raise `TypeError` at runtime
info: Overloaded functions without implementations are only permitted in stub files, on protocols, or for abstract methods
info: Overloaded functions without implementations are only permitted:
info: - in stub files
info: - in `if TYPE_CHECKING` blocks
info: - as methods on protocol classes
info: - or as `@abstractmethod`-decorated methods on abstract classes
info: See https://docs.python.org/3/library/typing.html#typing.overload for more details
info: rule `invalid-overload` is enabled by default
@ -58,7 +62,11 @@ error[invalid-overload]: Overloads for function `method` must be followed by a n
| ^^^^^^
|
info: Attempting to call `method` will raise `TypeError` at runtime
info: Overloaded functions without implementations are only permitted in stub files, on protocols, or for abstract methods
info: Overloaded functions without implementations are only permitted:
info: - in stub files
info: - in `if TYPE_CHECKING` blocks
info: - as methods on protocol classes
info: - or as `@abstractmethod`-decorated methods on abstract classes
info: See https://docs.python.org/3/library/typing.html#typing.overload for more details
info: rule `invalid-overload` is enabled by default

View File

@ -1,4 +1,5 @@
use ruff_db::files::File;
use ruff_python_ast::PythonVersion;
use crate::dunder_all::dunder_all_names;
use crate::module_resolver::{KnownModule, file_to_module, resolve_module_confident};
@ -1633,6 +1634,35 @@ mod implicit_globals {
}
}
/// Looks up the type of an "implicit class body symbol". Returns [`Place::Undefined`] if
/// `name` is not present as an implicit symbol in class bodies.
///
/// Implicit class body symbols are symbols such as `__qualname__`, `__module__`, `__doc__`,
/// and `__firstlineno__` that Python implicitly makes available inside a class body during
/// class creation.
///
/// See <https://docs.python.org/3/reference/datamodel.html#creating-the-class-object>
pub(crate) fn class_body_implicit_symbol<'db>(
db: &'db dyn Db,
name: &str,
) -> PlaceAndQualifiers<'db> {
match name {
"__qualname__" => Place::bound(KnownClass::Str.to_instance(db)).into(),
"__module__" => Place::bound(KnownClass::Str.to_instance(db)).into(),
// __doc__ is `str` if there's a docstring, `None` if there isn't
"__doc__" => Place::bound(UnionType::from_elements(
db,
[KnownClass::Str.to_instance(db), Type::none(db)],
))
.into(),
// __firstlineno__ was added in Python 3.13
"__firstlineno__" if Program::get(db).python_version(db) >= PythonVersion::PY313 => {
Place::bound(KnownClass::Int.to_instance(db)).into()
}
_ => Place::Undefined.into(),
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) enum RequiresExplicitReExport {
Yes,

View File

@ -10691,7 +10691,6 @@ pub struct UnionTypeInstance<'db> {
/// `<class 'str'>`. For `Union[int, str]`, this field is `None`, as we infer
/// the elements as type expressions. Use `value_expression_types` to get the
/// corresponding value expression types.
#[expect(clippy::ref_option)]
#[returns(ref)]
_value_expr_types: Option<Box<[Type<'db>]>>,

View File

@ -1815,13 +1815,6 @@ impl<'db> ClassLiteral<'db> {
})
}
/// Determine if this is an abstract class.
pub(super) fn is_abstract(self, db: &'db dyn Db) -> bool {
self.metaclass(db)
.as_class_literal()
.is_some_and(|metaclass| metaclass.is_known(db, KnownClass::ABCMeta))
}
/// Return the types of the decorators on this class
#[salsa::tracked(returns(deref), cycle_initial=decorators_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
fn decorators(self, db: &'db dyn Db) -> Box<[Type<'db>]> {

View File

@ -30,7 +30,7 @@ use crate::types::{
ProtocolInstanceType, SpecialFormType, SubclassOfInner, Type, TypeContext, binding_type,
protocol_class::ProtocolClass,
};
use crate::types::{DataclassFlags, KnownInstanceType, MemberLookupPolicy};
use crate::types::{DataclassFlags, KnownInstanceType, MemberLookupPolicy, TypeVarInstance};
use crate::{Db, DisplaySettings, FxIndexMap, Module, ModuleName, Program, declare_lint};
use itertools::Itertools;
use ruff_db::{
@ -894,15 +894,20 @@ declare_lint! {
///
/// ## Why is this bad?
/// There are several requirements that you must follow when defining a generic class.
/// Many of these result in `TypeError` being raised at runtime if they are violated.
///
/// ## Examples
/// ```python
/// from typing import Generic, TypeVar
/// from typing_extensions import Generic, TypeVar
///
/// T = TypeVar("T") # okay
/// T = TypeVar("T")
/// U = TypeVar("U", default=int)
///
/// # error: class uses both PEP-695 syntax and legacy syntax
/// class C[U](Generic[T]): ...
///
/// # error: type parameter with default comes before type parameter without default
/// class D(Generic[U, T]): ...
/// ```
///
/// ## References
@ -3695,6 +3700,90 @@ pub(crate) fn report_cannot_pop_required_field_on_typed_dict<'db>(
}
}
pub(crate) fn report_invalid_type_param_order<'db>(
context: &InferContext<'db, '_>,
class: ClassLiteral<'db>,
node: &ast::StmtClassDef,
typevar_with_default: TypeVarInstance<'db>,
invalid_later_typevars: &[TypeVarInstance<'db>],
) {
let db = context.db();
let base_index = class
.explicit_bases(db)
.iter()
.position(|base| {
matches!(
base,
Type::KnownInstance(
KnownInstanceType::SubscriptedProtocol(_)
| KnownInstanceType::SubscriptedGeneric(_)
)
)
})
.expect(
"It should not be possible for a class to have a legacy generic context \
if it does not inherit from `Protocol[]` or `Generic[]`",
);
let base_node = &node.bases()[base_index];
let primary_diagnostic_range = base_node
.as_subscript_expr()
.map(|subscript| &*subscript.slice)
.unwrap_or(base_node)
.range();
let Some(builder) = context.report_lint(&INVALID_GENERIC_CLASS, primary_diagnostic_range)
else {
return;
};
let mut diagnostic = builder.into_diagnostic(
"Type parameters without defaults cannot follow type parameters with defaults",
);
diagnostic.set_concise_message(format_args!(
"Type parameter `{}` without a default cannot follow earlier parameter `{}` with a default",
invalid_later_typevars[0].name(db),
typevar_with_default.name(db),
));
if let [single_typevar] = invalid_later_typevars {
diagnostic.set_primary_message(format_args!(
"Type variable `{}` does not have a default",
single_typevar.name(db),
));
} else {
let later_typevars =
format_enumeration(invalid_later_typevars.iter().map(|tv| tv.name(db)));
diagnostic.set_primary_message(format_args!(
"Type variables {later_typevars} do not have defaults",
));
}
diagnostic.annotate(
Annotation::primary(Span::from(context.file()).with_range(primary_diagnostic_range))
.message(format_args!(
"Earlier TypeVar `{}` does",
typevar_with_default.name(db)
)),
);
for tvar in [typevar_with_default, invalid_later_typevars[0]] {
let Some(definition) = tvar.definition(db) else {
continue;
};
let file = definition.file(db);
diagnostic.annotate(
Annotation::secondary(Span::from(
definition.full_range(db, &parsed_module(db, file).load(db)),
))
.message(format_args!("`{}` defined here", tvar.name(db))),
);
}
}
pub(crate) fn report_rebound_typevar<'db>(
context: &InferContext<'db, '_>,
typevar_name: &ast::name::Name,

View File

@ -28,9 +28,9 @@ use crate::module_resolver::{
use crate::node_key::NodeKey;
use crate::place::{
ConsideredDefinitions, Definedness, LookupError, Place, PlaceAndQualifiers, TypeOrigin,
builtins_module_scope, builtins_symbol, explicit_global_symbol, global_symbol,
module_type_implicit_global_declaration, module_type_implicit_global_symbol, place,
place_from_bindings, place_from_declarations, typing_extensions_symbol,
builtins_module_scope, builtins_symbol, class_body_implicit_symbol, explicit_global_symbol,
global_symbol, module_type_implicit_global_declaration, module_type_implicit_global_symbol,
place, place_from_bindings, place_from_declarations, typing_extensions_symbol,
};
use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey;
use crate::semantic_index::ast_ids::{HasScopedUseId, ScopedUseId};
@ -78,7 +78,7 @@ use crate::types::diagnostic::{
report_invalid_exception_tuple_caught, report_invalid_generator_function_return_type,
report_invalid_key_on_typed_dict, report_invalid_or_unsupported_base,
report_invalid_return_type, report_invalid_type_checking_constant,
report_named_tuple_field_with_leading_underscore,
report_invalid_type_param_order, 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_unsupported_augmented_assignment,
@ -949,23 +949,62 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
}
}
let scope = class.body_scope(self.db()).scope(self.db());
if self.context.is_lint_enabled(&INVALID_GENERIC_CLASS)
&& let Some(parent) = scope.parent()
{
for self_typevar in class.typevars_referenced_in_definition(self.db()) {
let self_typevar_name = self_typevar.typevar(self.db()).name(self.db());
for enclosing in enclosing_generic_contexts(self.db(), self.index, parent) {
if let Some(other_typevar) =
enclosing.binds_named_typevar(self.db(), self_typevar_name)
{
report_rebound_typevar(
&self.context,
self_typevar_name,
class,
class_node,
other_typevar,
);
if self.context.is_lint_enabled(&INVALID_GENERIC_CLASS) {
if !class.has_pep_695_type_params(self.db())
&& let Some(generic_context) = class.legacy_generic_context(self.db())
{
struct State<'db> {
typevar_with_default: TypeVarInstance<'db>,
invalid_later_tvars: Vec<TypeVarInstance<'db>>,
}
let mut state: Option<State<'db>> = None;
for bound_typevar in generic_context.variables(self.db()) {
let typevar = bound_typevar.typevar(self.db());
let has_default = typevar.default_type(self.db()).is_some();
if let Some(state) = state.as_mut() {
if !has_default {
state.invalid_later_tvars.push(typevar);
}
} else if has_default {
state = Some(State {
typevar_with_default: typevar,
invalid_later_tvars: vec![],
});
}
}
if let Some(state) = state
&& !state.invalid_later_tvars.is_empty()
{
report_invalid_type_param_order(
&self.context,
class,
class_node,
state.typevar_with_default,
&state.invalid_later_tvars,
);
}
}
let scope = class.body_scope(self.db()).scope(self.db());
if let Some(parent) = scope.parent() {
for self_typevar in class.typevars_referenced_in_definition(self.db()) {
let self_typevar_name = self_typevar.typevar(self.db()).name(self.db());
for enclosing in enclosing_generic_contexts(self.db(), self.index, parent) {
if let Some(other_typevar) =
enclosing.binds_named_typevar(self.db(), self_typevar_name)
{
report_rebound_typevar(
&self.context,
self_typevar_name,
class,
class_node,
other_typevar,
);
}
}
}
}
@ -1104,7 +1143,16 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
if implementation.is_none() && !self.in_stub() {
let mut implementation_required = true;
if let NodeWithScopeKind::Class(class_node_ref) = scope {
if function
.iter_overloads_and_implementation(self.db())
.all(|f| {
f.body_scope(self.db())
.scope(self.db())
.in_type_checking_block()
})
{
implementation_required = false;
} else if let NodeWithScopeKind::Class(class_node_ref) = scope {
let class = binding_type(
self.db(),
self.index
@ -1113,7 +1161,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
.expect_class_literal();
if class.is_protocol(self.db())
|| (class.is_abstract(self.db())
|| (Type::ClassLiteral(class)
.is_subtype_of(self.db(), KnownClass::ABCMeta.to_instance(self.db()))
&& overloads.iter().all(|overload| {
overload.has_known_decorator(
self.db(),
@ -1140,8 +1189,13 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
&function_node.name
));
diagnostic.info(
"Overloaded functions without implementations are only permitted \
in stub files, on protocols, or for abstract methods",
"Overloaded functions without implementations are only permitted:",
);
diagnostic.info(" - in stub files");
diagnostic.info(" - in `if TYPE_CHECKING` blocks");
diagnostic.info(" - as methods on protocol classes");
diagnostic.info(
" - or as `@abstractmethod`-decorated methods on abstract classes",
);
diagnostic.info(
"See https://docs.python.org/3/library/typing.html#typing.overload \
@ -9210,6 +9264,25 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
}
PlaceAndQualifiers::from(Place::Undefined)
// If we're in a class body, check for implicit class body symbols first.
// These take precedence over globals.
.or_fall_back_to(db, || {
if scope.node(db).scope_kind().is_class()
&& let Some(symbol) = place_expr.as_symbol()
{
let implicit = class_body_implicit_symbol(db, symbol.name());
if implicit.place.is_definitely_bound() {
return implicit.map_type(|ty| {
self.narrow_place_with_applicable_constraints(
place_expr,
ty,
&constraint_keys,
)
});
}
}
Place::Undefined.into()
})
// No nonlocal binding? Check the module's explicit globals.
// Avoid infinite recursion if `self.scope` already is the module's global scope.
.or_fall_back_to(db, || {

View File

@ -1072,6 +1072,29 @@ impl<'db> Signature<'db> {
let mut check_types = |type1: Option<Type<'db>>, type2: Option<Type<'db>>| {
let type1 = type1.unwrap_or(Type::unknown());
let type2 = type2.unwrap_or(Type::unknown());
match (type1, type2) {
// This is a special case where the _same_ components of two different `ParamSpec`
// type variables are assignable to each other when they're both in an inferable
// position.
//
// `ParamSpec` type variables can only occur in parameter lists so this special case
// is present here instead of in `Type::has_relation_to_impl`.
(Type::TypeVar(typevar1), Type::TypeVar(typevar2))
if typevar1.paramspec_attr(db).is_some()
&& typevar1.paramspec_attr(db) == typevar2.paramspec_attr(db)
&& typevar1
.without_paramspec_attr(db)
.is_inferable(db, inferable)
&& typevar2
.without_paramspec_attr(db)
.is_inferable(db, inferable) =>
{
return true;
}
_ => {}
}
!result
.intersect(
db,

View File

@ -66,7 +66,7 @@ install-path = ["$XDG_BIN_HOME/", "$XDG_DATA_HOME/../bin", "~/.local/bin"]
global = "depot-ubuntu-latest-4"
[dist.github-action-commits]
"actions/checkout" = "1af3b93b6815bc44a9784bd300feb67ff0d1eeb3" # v6.0.0
"actions/checkout" = "8e8c483db84b4bee98b60c0593521ed34d9990e8" # v6.0.1
"actions/upload-artifact" = "330a01c490aca151604b8cf639adc76d48f6c5d4" # v5.0.0
"actions/download-artifact" = "018cc2cf5baa6db3ef3c5f8a56943fffe632ef53" # v6.0.0
"actions/attest-build-provenance" = "c074443f1aee8d4aeeae555aebba3282517141b2" #v2.2.3

View File

@ -1,2 +1,2 @@
[toolchain]
channel = "1.91"
channel = "1.92"

2
ty.schema.json generated
View File

@ -595,7 +595,7 @@
},
"invalid-generic-class": {
"title": "detects invalid generic classes",
"description": "## What it does\nChecks for the creation of invalid generic classes\n\n## Why is this bad?\nThere are several requirements that you must follow when defining a generic class.\n\n## Examples\n```python\nfrom typing import Generic, TypeVar\n\nT = TypeVar(\"T\") # okay\n\n# error: class uses both PEP-695 syntax and legacy syntax\nclass C[U](Generic[T]): ...\n```\n\n## References\n- [Typing spec: Generics](https://typing.python.org/en/latest/spec/generics.html#introduction)",
"description": "## What it does\nChecks for the creation of invalid generic classes\n\n## Why is this bad?\nThere are several requirements that you must follow when defining a generic class.\nMany of these result in `TypeError` being raised at runtime if they are violated.\n\n## Examples\n```python\nfrom typing_extensions import Generic, TypeVar\n\nT = TypeVar(\"T\")\nU = TypeVar(\"U\", default=int)\n\n# error: class uses both PEP-695 syntax and legacy syntax\nclass C[U](Generic[T]): ...\n\n# error: type parameter with default comes before type parameter without default\nclass D(Generic[U, T]): ...\n```\n\n## References\n- [Typing spec: Generics](https://typing.python.org/en/latest/spec/generics.html#introduction)",
"default": "error",
"oneOf": [
{