mirror of
https://github.com/astral-sh/ruff
synced 2026-01-22 05:51:03 -05:00
[ty] Ban NewTypes with generic bases (#22653)
This commit is contained in:
@@ -541,7 +541,7 @@ class Foo(TypedDict):
|
||||
Bar = NewType("Bar", Foo) # error: [invalid-newtype]
|
||||
```
|
||||
|
||||
## TODO: A `NewType` cannot be generic
|
||||
## A `NewType` cannot be generic
|
||||
|
||||
```py
|
||||
from typing import Any, NewType, TypeVar
|
||||
@@ -553,7 +553,14 @@ B = NewType("B", list[Any])
|
||||
|
||||
# But a free typevar is not allowed.
|
||||
T = TypeVar("T")
|
||||
C = NewType("C", list[T]) # TODO: should be "error: [invalid-newtype]"
|
||||
C = NewType("C", list[T]) # error: [invalid-newtype]
|
||||
|
||||
D = dict[str, T]
|
||||
E = NewType("E", D[T]) # error: [invalid-newtype]
|
||||
|
||||
# this is fine: omitting the type argument means that this is equivalent
|
||||
# to `F = NewType("F", dict[str, Any])
|
||||
F = NewType("F", D)
|
||||
```
|
||||
|
||||
## Forward references in stub files
|
||||
|
||||
@@ -6093,7 +6093,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
return error(
|
||||
&self.context,
|
||||
format!(
|
||||
"Wrong number of arguments in `NewType` creation, expected 2, found {}",
|
||||
"Wrong number of arguments in `NewType` creation: expected 2, found {}",
|
||||
arguments.args.len()
|
||||
),
|
||||
call_expr,
|
||||
@@ -6183,7 +6183,26 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
fn infer_newtype_assignment_deferred(&mut self, arguments: &ast::Arguments) {
|
||||
let inferred = self.infer_type_expression(&arguments.args[1]);
|
||||
match inferred {
|
||||
Type::NominalInstance(_) | Type::NewTypeInstance(_) => return,
|
||||
Type::NewTypeInstance(_) => return,
|
||||
Type::NominalInstance(instance) => {
|
||||
match instance.class(self.db()) {
|
||||
ClassType::NonGeneric(_) => {}
|
||||
ClassType::Generic(alias) => {
|
||||
let spec = alias.specialization(self.db());
|
||||
if spec.types(self.db()).iter().any(|t| {
|
||||
matches!(t, Type::KnownInstance(KnownInstanceType::TypeVar(_)))
|
||||
}) && let Some(builder) = self
|
||||
.context
|
||||
.report_lint(&INVALID_NEWTYPE, &arguments.args[1])
|
||||
{
|
||||
let mut diag =
|
||||
builder.into_diagnostic("invalid base for `typing.NewType`");
|
||||
diag.set_primary_message("A `NewType` base cannot be generic");
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// There are exactly two union types allowed as bases for NewType: `int | float` and
|
||||
// `int | float | complex`. These are allowed because that's what `float` and `complex`
|
||||
// expand into in type position. We don't currently ask whether the union was implicit
|
||||
|
||||
Reference in New Issue
Block a user