mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-22 08:12:17 +00:00
[ty] Do not assume that field
s have a default value (#20914)
## Summary fixes https://github.com/astral-sh/ty/issues/1366 ## Test Plan Added regression test
This commit is contained in:
parent
c9dfb51f49
commit
0cc663efcd
5 changed files with 29 additions and 19 deletions
|
@ -497,6 +497,8 @@ class A:
|
||||||
a: str = field(kw_only=False)
|
a: str = field(kw_only=False)
|
||||||
b: int = 0
|
b: int = 0
|
||||||
|
|
||||||
|
reveal_type(A.__init__) # revealed: (self: A, a: str, *, b: int = Literal[0]) -> None
|
||||||
|
|
||||||
A("hi")
|
A("hi")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ class A:
|
||||||
name: str = field(init=False)
|
name: str = field(init=False)
|
||||||
|
|
||||||
# field(init=False) should be ignored for dataclass_transform without explicit field_specifiers
|
# field(init=False) should be ignored for dataclass_transform without explicit field_specifiers
|
||||||
reveal_type(A.__init__) # revealed: (self: A, name: str = Unknown) -> None
|
reveal_type(A.__init__) # revealed: (self: A, name: str) -> None
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class B:
|
class B:
|
||||||
|
|
|
@ -1636,14 +1636,16 @@ impl<'db> Type<'db> {
|
||||||
(Type::KnownInstance(KnownInstanceType::Field(field)), right)
|
(Type::KnownInstance(KnownInstanceType::Field(field)), right)
|
||||||
if relation.is_assignability() =>
|
if relation.is_assignability() =>
|
||||||
{
|
{
|
||||||
field.default_type(db).has_relation_to_impl(
|
field.default_type(db).when_none_or(|default_type| {
|
||||||
db,
|
default_type.has_relation_to_impl(
|
||||||
right,
|
db,
|
||||||
inferable,
|
right,
|
||||||
relation,
|
inferable,
|
||||||
relation_visitor,
|
relation,
|
||||||
disjointness_visitor,
|
relation_visitor,
|
||||||
)
|
disjointness_visitor,
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamic is only a subtype of `object` and only a supertype of `Never`; both were
|
// Dynamic is only a subtype of `object` and only a supertype of `Never`; both were
|
||||||
|
@ -7499,7 +7501,9 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||||
// Nothing to visit
|
// Nothing to visit
|
||||||
}
|
}
|
||||||
KnownInstanceType::Field(field) => {
|
KnownInstanceType::Field(field) => {
|
||||||
visitor.visit_type(db, field.default_type(db));
|
if let Some(default_ty) = field.default_type(db) {
|
||||||
|
visitor.visit_type(db, default_ty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7599,9 +7603,11 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
KnownInstanceType::TypeVar(_) => f.write_str("typing.TypeVar"),
|
KnownInstanceType::TypeVar(_) => f.write_str("typing.TypeVar"),
|
||||||
KnownInstanceType::Deprecated(_) => f.write_str("warnings.deprecated"),
|
KnownInstanceType::Deprecated(_) => f.write_str("warnings.deprecated"),
|
||||||
KnownInstanceType::Field(field) => {
|
KnownInstanceType::Field(field) => {
|
||||||
f.write_str("dataclasses.Field[")?;
|
f.write_str("dataclasses.Field")?;
|
||||||
field.default_type(self.db).display(self.db).fmt(f)?;
|
if let Some(default_ty) = field.default_type(self.db) {
|
||||||
f.write_str("]")
|
write!(f, "[{}]", default_ty.display(self.db))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
KnownInstanceType::ConstraintSet(tracked_set) => {
|
KnownInstanceType::ConstraintSet(tracked_set) => {
|
||||||
let constraints = tracked_set.constraints(self.db);
|
let constraints = tracked_set.constraints(self.db);
|
||||||
|
@ -7988,7 +7994,7 @@ impl get_size2::GetSize for DeprecatedInstance<'_> {}
|
||||||
pub struct FieldInstance<'db> {
|
pub struct FieldInstance<'db> {
|
||||||
/// The type of the default value for this field. This is derived from the `default` or
|
/// The type of the default value for this field. This is derived from the `default` or
|
||||||
/// `default_factory` arguments to `dataclasses.field()`.
|
/// `default_factory` arguments to `dataclasses.field()`.
|
||||||
pub default_type: Type<'db>,
|
pub default_type: Option<Type<'db>>,
|
||||||
|
|
||||||
/// Whether this field is part of the `__init__` signature, or not.
|
/// Whether this field is part of the `__init__` signature, or not.
|
||||||
pub init: bool,
|
pub init: bool,
|
||||||
|
@ -8004,7 +8010,8 @@ impl<'db> FieldInstance<'db> {
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
FieldInstance::new(
|
FieldInstance::new(
|
||||||
db,
|
db,
|
||||||
self.default_type(db).normalized_impl(db, visitor),
|
self.default_type(db)
|
||||||
|
.map(|ty| ty.normalized_impl(db, visitor)),
|
||||||
self.init(db),
|
self.init(db),
|
||||||
self.kw_only(db),
|
self.kw_only(db),
|
||||||
)
|
)
|
||||||
|
|
|
@ -978,11 +978,12 @@ impl<'db> Bindings<'db> {
|
||||||
overload.parameter_type_by_name("kw_only").unwrap_or(None);
|
overload.parameter_type_by_name("kw_only").unwrap_or(None);
|
||||||
|
|
||||||
let default_ty = match (default, default_factory) {
|
let default_ty = match (default, default_factory) {
|
||||||
(Some(default_ty), _) => default_ty,
|
(Some(default_ty), _) => Some(default_ty),
|
||||||
(_, Some(default_factory_ty)) => default_factory_ty
|
(_, Some(default_factory_ty)) => default_factory_ty
|
||||||
.try_call(db, &CallArguments::none())
|
.try_call(db, &CallArguments::none())
|
||||||
.map_or(Type::unknown(), |binding| binding.return_type(db)),
|
.ok()
|
||||||
_ => Type::unknown(),
|
.map(|binding| binding.return_type(db)),
|
||||||
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let init = init
|
let init = init
|
||||||
|
|
|
@ -2898,7 +2898,7 @@ impl<'db> ClassLiteral<'db> {
|
||||||
let mut init = true;
|
let mut init = true;
|
||||||
let mut kw_only = None;
|
let mut kw_only = None;
|
||||||
if let Some(Type::KnownInstance(KnownInstanceType::Field(field))) = default_ty {
|
if let Some(Type::KnownInstance(KnownInstanceType::Field(field))) = default_ty {
|
||||||
default_ty = Some(field.default_type(db));
|
default_ty = field.default_type(db);
|
||||||
if self
|
if self
|
||||||
.dataclass_params(db)
|
.dataclass_params(db)
|
||||||
.map(|params| params.contains(DataclassParams::NO_FIELD_SPECIFIERS))
|
.map(|params| params.contains(DataclassParams::NO_FIELD_SPECIFIERS))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue