From ebce96c20dcebdd7098b7a0550653605833bc000 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 | 29 +++++++++++++------- crates/ty_python_semantic/src/types/infer.rs | 2 +- crates/ty_python_semantic/src/types/mro.rs | 7 +---- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index 033f326c39..4715a51710 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -38,6 +38,7 @@ use crate::types::{ ManualPEP695TypeAliasType, MaterializationKind, NormalizedVisitor, PropertyInstanceType, StringLiteralType, TypeAliasType, TypeContext, TypeMapping, TypeRelation, TypedDictParams, UnionBuilder, VarianceInferable, binding_type, declaration_type, determine_upper_bound, + todo_type, }; use crate::{ Db, FxIndexMap, FxIndexSet, FxOrderSet, Program, @@ -1664,20 +1665,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/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index cb2f2a1068..e4903da824 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -36,8 +36,8 @@ //! of iterations, so if we fail to converge, Salsa will eventually panic. (This should of course //! be considered a bug.) -use ruff_python_ast as ast; use ruff_db::parsed::{ParsedModuleRef, parsed_module}; +use ruff_python_ast as ast; use ruff_text_size::Ranged; use rustc_hash::{FxHashMap, FxHashSet}; use salsa; 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)) }