From ecda934c363272f3482b6f5501e602563cc90f32 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 17 Nov 2025 15:00:47 +0000 Subject: [PATCH] todo class bases --- crates/ty_python_semantic/src/types/class.rs | 30 +++++++++++++------- crates/ty_python_semantic/src/types/mro.rs | 7 +---- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index b23de7d424..3583646c0a 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -38,7 +38,7 @@ use crate::types::{ ManualPEP695TypeAliasType, MaterializationKind, NormalizedVisitor, PropertyInstanceType, StringLiteralType, TypeAliasType, TypeContext, TypeMapping, TypeRelation, TypedDictParams, UnionBuilder, VarianceInferable, declaration_type, determine_upper_bound, - exceeds_max_specialization_depth, infer_definition_types, + exceeds_max_specialization_depth, infer_definition_types, todo_type, }; use crate::{ Db, FxIndexMap, FxIndexSet, FxOrderSet, Program, @@ -1598,20 +1598,28 @@ impl<'db> ClassLiteral<'db> { let class_definition = semantic_index(db, self.file(db)).expect_single_definition(class_stmt); - if self.is_known(db, KnownClass::VersionInfo) { - let tuple_type = TupleType::new(db, &TupleSpec::version_info_spec(db)) - .expect("sys.version_info tuple spec should always be a valid tuple"); + if class_stmt.bases().iter().any(ast::Expr::is_starred_expr) { + return Box::new([todo_type!("Starred expressions in class bases")]); + } - Box::new([ - definition_expression_type(db, class_definition, &class_stmt.bases()[0]), - Type::from(tuple_type.to_class_type(db)), - ]) - } else { - class_stmt + match self.known(db) { + Some(KnownClass::VersionInfo) => { + let tuple_type = TupleType::new(db, &TupleSpec::version_info_spec(db)) + .expect("sys.version_info tuple spec should always be a valid tuple"); + + Box::new([ + definition_expression_type(db, class_definition, &class_stmt.bases()[0]), + Type::from(tuple_type.to_class_type(db)), + ]) + } + // Special-case `NotImplementedType`: typeshed says that it inherits from `Any`, + // but this causes more problems than it fixes. + Some(KnownClass::NotImplementedType) => Box::new([]), + _ => class_stmt .bases() .iter() .map(|base_node| definition_expression_type(db, class_definition, base_node)) - .collect() + .collect(), } } diff --git a/crates/ty_python_semantic/src/types/mro.rs b/crates/ty_python_semantic/src/types/mro.rs index 21501060da..dffd166fe0 100644 --- a/crates/ty_python_semantic/src/types/mro.rs +++ b/crates/ty_python_semantic/src/types/mro.rs @@ -7,7 +7,7 @@ use rustc_hash::FxBuildHasher; use crate::Db; use crate::types::class_base::ClassBase; use crate::types::generics::Specialization; -use crate::types::{ClassLiteral, ClassType, KnownClass, KnownInstanceType, SpecialFormType, Type}; +use crate::types::{ClassLiteral, ClassType, KnownInstanceType, SpecialFormType, Type}; /// The inferred method resolution order of a given class. /// @@ -52,11 +52,6 @@ impl<'db> Mro<'db> { specialization: Option>, ) -> Result> { let class = class_literal.apply_optional_specialization(db, specialization); - // Special-case `NotImplementedType`: typeshed says that it inherits from `Any`, - // but this causes more problems than it fixes. - if class_literal.is_known(db, KnownClass::NotImplementedType) { - return Ok(Self::from([ClassBase::Class(class), ClassBase::object(db)])); - } Self::of_class_impl(db, class, class_literal.explicit_bases(db), specialization) .map_err(|err| err.into_mro_error(db, class)) }