Skip to content

Commit 9c3e5ec

Browse files
committed
Make it more similar
1 parent 896ffa9 commit 9c3e5ec

3 files changed

Lines changed: 277 additions & 289 deletions

File tree

crates/ty_python_semantic/src/types/class.rs

Lines changed: 29 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use crate::types::bound_super::BoundSuperError;
2020
use crate::types::constraints::{ConstraintSet, IteratorConstraintsExtension};
2121
use crate::types::context::InferContext;
2222
use crate::types::diagnostic::{
23-
DUPLICATE_BASE, INCONSISTENT_MRO, INVALID_BASE, INVALID_DATACLASS_OVERRIDE,
24-
INVALID_TYPE_ALIAS_TYPE, SUPER_CALL_IN_NAMED_TUPLE_METHOD,
23+
CYCLIC_CLASS_DEFINITION, DUPLICATE_BASE, INCONSISTENT_MRO, INVALID_BASE,
24+
INVALID_DATACLASS_OVERRIDE, INVALID_TYPE_ALIAS_TYPE, SUPER_CALL_IN_NAMED_TUPLE_METHOD,
2525
report_conflicting_metaclass_from_bases,
2626
};
2727
use crate::types::enums::{
@@ -92,14 +92,6 @@ fn static_class_explicit_bases_cycle_initial<'db>(
9292
Box::default()
9393
}
9494

95-
fn inheritance_cycle_initial<'db>(
96-
_db: &'db dyn Db,
97-
_id: salsa::Id,
98-
_self: StaticClassLiteral<'db>,
99-
) -> Option<InheritanceCycle> {
100-
None
101-
}
102-
10395
fn implicit_attribute_initial<'db>(
10496
_db: &'db dyn Db,
10597
id: salsa::Id,
@@ -151,24 +143,6 @@ fn try_metaclass_cycle_initial<'db>(
151143
})
152144
}
153145

154-
fn decorators_cycle_initial<'db>(
155-
_db: &'db dyn Db,
156-
_id: salsa::Id,
157-
_self: StaticClassLiteral<'db>,
158-
) -> Box<[Type<'db>]> {
159-
Box::default()
160-
}
161-
162-
fn fields_cycle_initial<'db>(
163-
_db: &'db dyn Db,
164-
_id: salsa::Id,
165-
_self: StaticClassLiteral<'db>,
166-
_specialization: Option<Specialization<'db>>,
167-
_field_policy: CodeGeneratorKind<'db>,
168-
) -> FxIndexMap<Name, Field<'db>> {
169-
FxIndexMap::default()
170-
}
171-
172146
fn dynamic_class_explicit_bases_cycle_initial<'db>(
173147
_db: &'db dyn Db,
174148
_id: salsa::Id,
@@ -5114,6 +5088,8 @@ impl<'db> DynamicClassLiteral<'db> {
51145088
///
51155089
/// Returns an empty slice if the bases cannot be computed (e.g., due to a cycle)
51165090
/// or if the bases argument is not a tuple.
5091+
///
5092+
/// Returns `[Unknown]` if the bases tuple is variable-length (like `tuple[type, ...]`).
51175093
#[salsa::tracked(returns(deref), cycle_initial=dynamic_class_explicit_bases_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
51185094
pub(crate) fn explicit_bases(self, db: &'db dyn Db) -> Box<[Type<'db>]> {
51195095
let scope = self.scope(db);
@@ -5162,7 +5138,7 @@ impl<'db> DynamicClassLiteral<'db> {
51625138
};
51635139

51645140
// For variable-length tuples (like `tuple[type, ...]`), we can't statically
5165-
// determine the bases, so return a single Unknown base.
5141+
// determine the bases, so return Unknown.
51665142
let Some(tuple_spec) = bases_type.tuple_instance_spec(db) else {
51675143
return Box::from([Type::unknown()]);
51685144
};
@@ -5235,12 +5211,12 @@ impl<'db> DynamicClassLiteral<'db> {
52355211
self,
52365212
db: &'db dyn Db,
52375213
) -> Result<Type<'db>, DynamicMetaclassConflict<'db>> {
5238-
let base_types = self.explicit_bases(db);
5214+
let original_bases = self.explicit_bases(db);
52395215

52405216
// If no bases, metaclass is `type`.
52415217
// To dynamically create a class with no bases that has a custom metaclass,
52425218
// you have to invoke that metaclass rather than `type()`.
5243-
if base_types.is_empty() {
5219+
if original_bases.is_empty() {
52445220
return Ok(KnownClass::Type.to_class_literal(db));
52455221
}
52465222

@@ -5249,17 +5225,20 @@ impl<'db> DynamicClassLiteral<'db> {
52495225
return Ok(SubclassOfType::subclass_of_unknown());
52505226
}
52515227

5252-
// Convert types to ClassBases. Use a placeholder class for conversion.
5228+
// Convert Types to ClassBases for metaclass computation.
52535229
let placeholder_class: ClassLiteral<'db> =
52545230
KnownClass::Object.try_to_class_literal(db).unwrap().into();
5255-
let bases: Vec<ClassBase<'db>> = base_types
5231+
5232+
let bases: Vec<ClassBase<'db>> = original_bases
52565233
.iter()
5257-
.map(|ty| {
5258-
ClassBase::try_from_type(db, *ty, placeholder_class)
5259-
.unwrap_or_else(ClassBase::unknown)
5260-
})
5234+
.filter_map(|base_type| ClassBase::try_from_type(db, *base_type, placeholder_class))
52615235
.collect();
52625236

5237+
// If all bases failed to convert, return type as the metaclass.
5238+
if bases.is_empty() {
5239+
return Ok(KnownClass::Type.to_class_literal(db));
5240+
}
5241+
52635242
// Start with the first base's metaclass as the candidate.
52645243
let mut candidate = bases[0].metaclass(db);
52655244

@@ -8211,18 +8190,27 @@ impl KnownClass {
82118190
if let Err(error) = dynamic_class.try_mro(db) {
82128191
match error.reason() {
82138192
DynamicMroErrorKind::InvalidBases(invalid_bases) => {
8214-
for (_, invalid_type) in invalid_bases {
8193+
for (_, base_type) in invalid_bases {
82158194
if let Some(builder) =
82168195
context.report_lint(&INVALID_BASE, call_expression)
82178196
{
82188197
builder.into_diagnostic(format_args!(
8219-
"Invalid class base with type `{}` (all bases must be a class, \
8220-
`Any`, `Unknown` or `Todo`)",
8221-
invalid_type.display(db),
8198+
"Invalid class base with type `{}`",
8199+
base_type.display(db)
82228200
));
82238201
}
82248202
}
82258203
}
8204+
DynamicMroErrorKind::InheritanceCycle => {
8205+
if let Some(builder) =
8206+
context.report_lint(&CYCLIC_CLASS_DEFINITION, call_expression)
8207+
{
8208+
builder.into_diagnostic(format_args!(
8209+
"Cyclic definition of `{}`",
8210+
dynamic_class.name(db)
8211+
));
8212+
}
8213+
}
82268214
DynamicMroErrorKind::DuplicateBases(duplicates) => {
82278215
if let Some(builder) =
82288216
context.report_lint(&DUPLICATE_BASE, call_expression)

0 commit comments

Comments
 (0)