More cleanup, clarification

This commit is contained in:
David Peter 2025-09-24 17:33:26 +02:00
parent a945958777
commit 47678d176c
3 changed files with 26 additions and 29 deletions

View file

@ -376,8 +376,8 @@ pub enum ClassType<'db> {
#[salsa::tracked] #[salsa::tracked]
impl<'db> ClassType<'db> { impl<'db> ClassType<'db> {
pub(super) const fn is_not_generic(self) -> bool { pub(super) const fn is_generic(self) -> bool {
matches!(self, Self::NonGeneric(_)) matches!(self, Self::Generic(_))
} }
pub(super) const fn into_generic_alias(self) -> Option<GenericAlias<'db>> { pub(super) const fn into_generic_alias(self) -> Option<GenericAlias<'db>> {

View file

@ -5950,7 +5950,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
// but constructor calls to `tuple[int]`, `tuple[int, ...]`, `tuple[int, *tuple[str, ...]]` (etc.) // but constructor calls to `tuple[int]`, `tuple[int, ...]`, `tuple[int, *tuple[str, ...]]` (etc.)
// are handled by the default constructor-call logic (we synthesize a `__new__` method for them // are handled by the default constructor-call logic (we synthesize a `__new__` method for them
// in `ClassType::own_class_member()`). // in `ClassType::own_class_member()`).
class.is_known(self.db(), KnownClass::Tuple) && class.is_not_generic() class.is_known(self.db(), KnownClass::Tuple) && !class.is_generic()
); );
// temporary special-casing for all subclasses of `enum.Enum` // temporary special-casing for all subclasses of `enum.Enum`

View file

@ -27,16 +27,16 @@ use crate::types::infer::nearest_enclosing_class;
use crate::types::{ use crate::types::{
ApplyTypeMappingVisitor, BindingContext, BoundTypeVarInstance, ClassType, ApplyTypeMappingVisitor, BindingContext, BoundTypeVarInstance, ClassType,
FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsEquivalentVisitor, KnownClass, FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsEquivalentVisitor, KnownClass,
MaterializationKind, NormalizedVisitor, TypeMapping, TypeRelation, TypeVarKind, MaterializationKind, NormalizedVisitor, TypeMapping, TypeRelation, VarianceInferable,
VarianceInferable, todo_type, todo_type,
}; };
use crate::{Db, FxOrderSet}; use crate::{Db, FxOrderSet};
use ruff_python_ast::{self as ast, name::Name}; use ruff_python_ast::{self as ast, name::Name};
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
struct MethodInformation<'db> { struct MethodInformation<'db> {
method_type: FunctionType<'db>, method: FunctionType<'db>,
class_type: ClassType<'db>, class: ClassType<'db>,
} }
fn infer_method_information<'db>( fn infer_method_information<'db>(
@ -50,7 +50,7 @@ fn infer_method_information<'db>(
let class_scope = index.scope(class_scope_id.file_scope_id(db)); let class_scope = index.scope(class_scope_id.file_scope_id(db));
let class_node = class_scope.node().as_class()?; let class_node = class_scope.node().as_class()?;
let method_type = infer_definition_types(db, definition) let method = infer_definition_types(db, definition)
.declaration_type(definition) .declaration_type(definition)
.inner_type() .inner_type()
.into_function_literal()?; .into_function_literal()?;
@ -59,12 +59,9 @@ fn infer_method_information<'db>(
let class_literal = infer_definition_types(db, class_def) let class_literal = infer_definition_types(db, class_def)
.declaration_type(class_def) .declaration_type(class_def)
.inner_type(); .inner_type();
let class_type = class_literal.to_class_type(db)?; let class = class_literal.to_class_type(db)?;
Some(MethodInformation { Some(MethodInformation { method, class })
method_type,
class_type,
})
} }
/// The signature of a single callable. If the callable is overloaded, there is a separate /// The signature of a single callable. If the callable is overloaded, there is a separate
@ -1257,16 +1254,12 @@ impl<'db> Parameters<'db> {
); );
} }
let method_info = infer_method_information(db, definition); let method_info = infer_method_information(db, definition);
let is_classmethod = method_info.is_some_and(|f| f.method_type.is_classmethod(db)); let is_static_or_classmethod = method_info
let is_staticmethod = method_info.is_some_and(|f| f.method_type.is_staticmethod(db)); .is_some_and(|f| f.method.is_staticmethod(db) || f.method.is_classmethod(db));
let positional_or_keyword = pos_or_keyword_iter.map(|arg| { let positional_or_keyword = pos_or_keyword_iter.map(|arg| {
if let Some(MethodInformation { if let Some(MethodInformation { method, class }) = method_info
method_type: method, && !is_static_or_classmethod
class_type: class,
}) = method_info
&& !is_staticmethod
&& !is_classmethod
&& arg.parameter.annotation().is_none() && arg.parameter.annotation().is_none()
&& parameters.index(arg.name().id()) == Some(0) && parameters.index(arg.name().id()) == Some(0)
{ {
@ -1276,18 +1269,16 @@ impl<'db> Parameters<'db> {
context context
.variables(db) .variables(db)
.iter() .iter()
.any(|v| v.typevar(db).kind(db) == TypeVarKind::TypingSelf); .any(|v| v.typevar(db).is_self(db))
true
} else { } else {
false false
} }
}); });
let implicit_annotation = if !method_has_self_in_generic_context
&& class.is_not_generic() let inferred_annotation = if method_has_self_in_generic_context
&& !class.known(db).is_some_and(KnownClass::is_fallback_class) || class.is_generic()
|| class.known(db).is_some_and(KnownClass::is_fallback_class)
{ {
Type::instance(db, class)
} else {
let scope_id = definition.scope(db); let scope_id = definition.scope(db);
let typevar_binding_context = Some(definition); let typevar_binding_context = Some(definition);
let index = semantic_index(db, scope_id.file(db)); let index = semantic_index(db, scope_id.file(db));
@ -1301,9 +1292,15 @@ impl<'db> Parameters<'db> {
definition, definition,
))), ))),
) )
} else {
// For methods of non-generic classes that are not otherwise generic (e.g. return `Self` or
// have additional type parameters), the implicit `Self` type of the `self` parameter would
// be the only type variable, so we can just use the class directly.
Type::instance(db, class)
}; };
Parameter { Parameter {
annotated_type: Some(implicit_annotation), annotated_type: Some(inferred_annotation),
inferred_annotation: true, inferred_annotation: true,
kind: ParameterKind::PositionalOrKeyword { kind: ParameterKind::PositionalOrKeyword {
name: arg.parameter.name.id.clone(), name: arg.parameter.name.id.clone(),