@@ -39,7 +39,6 @@ use crate::semantic_index::scope::ScopeId;
3939use crate :: semantic_index:: { imported_modules, place_table, semantic_index} ;
4040use crate :: suppression:: check_suppressions;
4141use crate :: types:: call:: { Binding , Bindings , CallArguments , CallableBinding } ;
42- use crate::types::class::MethodDecorator;
4342pub ( crate ) use crate :: types:: class_base:: ClassBase ;
4443use crate :: types:: constraints:: {
4544 ConstraintSet , IteratorConstraintsExtension , OptionConstraintsExtension ,
@@ -62,15 +61,14 @@ pub use crate::types::ide_support::{
6261 definitions_for_keyword_argument, definitions_for_name, find_active_signature_from_details,
6362 inlay_hint_function_argument_details,
6463} ;
65- use crate::types::infer::InferExpression;
6664use crate :: types:: mro:: { Mro , MroError , MroIterator } ;
6765pub ( crate ) use crate :: types:: narrow:: infer_narrowing_constraint;
6866pub ( crate ) use crate :: types:: signatures:: { Parameter , Parameters } ;
6967use crate :: types:: signatures:: { ParameterForm , walk_signature} ;
7068use crate :: types:: tuple:: TupleSpec ;
7169pub ( crate ) use crate :: types:: typed_dict:: { TypedDictParams , TypedDictType , walk_typed_dict_type} ;
7270use crate :: types:: variance:: { TypeVarVariance , VarianceInferable } ;
73- use crate::unpack::{ EvaluationMode, Unpack} ;
71+ use crate :: unpack:: EvaluationMode ;
7472pub use crate :: util:: diagnostics:: add_inferred_python_version_hint_to_diagnostic;
7573use crate :: { Db , FxOrderSet , Module , Program } ;
7674pub ( crate ) use class:: { ClassLiteral , ClassType , GenericAlias , KnownClass } ;
@@ -121,16 +119,13 @@ fn return_type_cycle_recover<'db>(
121119}
122120
123121fn return_type_cycle_initial < ' db > ( db : & ' db dyn Db , method : BoundMethodType < ' db > ) -> Type < ' db > {
124- Type::divergent(DivergentType::new(
125- db,
126- DivergenceKind::InferReturnType(
127- method
128- .function(db)
129- .literal(db)
130- .last_definition(db)
131- .body_scope(db),
132- ),
133- ))
122+ Type :: divergent (
123+ method
124+ . function ( db)
125+ . literal ( db)
126+ . last_definition ( db)
127+ . body_scope ( db) ,
128+ )
134129}
135130
136131pub fn check_types ( db : & dyn Db , file : File ) -> Vec < Diagnostic > {
@@ -287,7 +282,11 @@ pub(crate) struct RecursiveTypeNormalizedVisitor<'db> {
287282
288283impl < ' db > RecursiveTypeNormalizedVisitor < ' db > {
289284 fn new ( div : Type < ' db > ) -> Self {
290- debug_assert!(matches!(div, Type::Dynamic(DynamicType::Divergent(_))));
285+ // TODO: Divergent only
286+ debug_assert ! ( matches!(
287+ div,
288+ Type :: Never | Type :: Dynamic ( DynamicType :: Divergent ( _) )
289+ ) ) ;
291290 Self {
292291 transformer : NormalizedVisitor :: default ( ) ,
293292 div,
@@ -446,22 +445,13 @@ fn member_lookup_cycle_recover<'db>(
446445 salsa:: CycleRecoveryAction :: Iterate
447446}
448447
449- #[allow(clippy::needless_pass_by_value)]
450448fn member_lookup_cycle_initial < ' db > (
451- db : &'db dyn Db,
452- self_type : Type<'db>,
453- name : Name,
454- policy : MemberLookupPolicy,
449+ _db : & ' db dyn Db ,
450+ _self : Type < ' db > ,
451+ _name : Name ,
452+ _policy : MemberLookupPolicy ,
455453) -> PlaceAndQualifiers < ' db > {
456- Place::bound(Type::divergent(DivergentType::new(
457- db,
458- DivergenceKind::MemberLookupWithPolicy {
459- self_type,
460- name,
461- policy,
462- },
463- )))
464- .into()
454+ Place :: bound ( Type :: Never ) . into ( )
465455}
466456
467457fn class_lookup_cycle_recover < ' db > (
@@ -475,22 +465,13 @@ fn class_lookup_cycle_recover<'db>(
475465 salsa:: CycleRecoveryAction :: Iterate
476466}
477467
478- #[allow(clippy::needless_pass_by_value)]
479468fn class_lookup_cycle_initial < ' db > (
480- db : &'db dyn Db,
481- self_type : Type<'db>,
482- name : Name,
483- policy : MemberLookupPolicy,
469+ _db : & ' db dyn Db ,
470+ _self : Type < ' db > ,
471+ _name : Name ,
472+ _policy : MemberLookupPolicy ,
484473) -> PlaceAndQualifiers < ' db > {
485- Place::bound(Type::divergent(DivergentType::new(
486- db,
487- DivergenceKind::ClassLookupWithPolicy {
488- self_type,
489- name,
490- policy,
491- },
492- )))
493- .into()
474+ Place :: bound ( Type :: Never ) . into ( )
494475}
495476
496477#[ allow( clippy:: trivially_copy_pass_by_ref) ]
@@ -909,8 +890,8 @@ impl<'db> Type<'db> {
909890 Self :: Dynamic ( DynamicType :: Unknown )
910891 }
911892
912- pub(crate) fn divergent(divergent: DivergentType <'db>) -> Self {
913- Self::Dynamic(DynamicType::Divergent(divergent ))
893+ pub ( crate ) fn divergent ( scope : ScopeId < ' db > ) -> Self {
894+ Self :: Dynamic ( DynamicType :: Divergent ( DivergentType { scope } ) )
914895 }
915896
916897 pub const fn is_unknown ( & self ) -> bool {
@@ -3169,7 +3150,7 @@ impl<'db> Type<'db> {
31693150 policy : MemberLookupPolicy ,
31703151 ) -> PlaceAndQualifiers < ' db > {
31713152 tracing:: trace!( "class_member: {}.{}" , self . display( db) , name) ;
3172- let result = match self {
3153+ match self {
31733154 Type :: Union ( union) => union. map_with_boundness_and_qualifiers ( db, |elem| {
31743155 elem. class_member_with_policy ( db, name. clone ( ) , policy)
31753156 } ) ,
@@ -3187,30 +3168,7 @@ impl<'db> Type<'db> {
31873168 . expect (
31883169 "`Type::find_name_in_mro()` should return `Some()` when called on a meta-type" ,
31893170 ) ,
3190- };
3191- result.map_type(|ty| {
3192- // In fixed-point iteration of type inference, the member type must be monotonically widened and not "oscillate".
3193- // Here, monotonicity is guaranteed by pre-unioning the type of the previous iteration into the current result.
3194- let previous_cycle_value = self.class_member_with_policy(db, name.clone(), policy);
3195-
3196- let ty = if let Some(previous_ty) = previous_cycle_value.place.ignore_possibly_unbound()
3197- {
3198- UnionType::from_elements(db, [ty, previous_ty])
3199- } else {
3200- ty
3201- };
3202-
3203- let div = Type::divergent(DivergentType::new(
3204- db,
3205- DivergenceKind::ClassLookupWithPolicy {
3206- self_type: self,
3207- name,
3208- policy,
3209- },
3210- ));
3211- let visitor = RecursiveTypeNormalizedVisitor::new(div);
3212- ty.recursive_type_normalized(db, &visitor)
3213- })
3171+ }
32143172 }
32153173
32163174 /// This function roughly corresponds to looking up an attribute in the `__dict__` of an object.
@@ -3664,7 +3622,7 @@ impl<'db> Type<'db> {
36643622
36653623 let name_str = name. as_str ( ) ;
36663624
3667- let result = match self {
3625+ match self {
36683626 Type :: Union ( union) => union. map_with_boundness_and_qualifiers ( db, |elem| {
36693627 elem. member_lookup_with_policy ( db, name_str. into ( ) , policy)
36703628 } ) ,
@@ -4003,30 +3961,7 @@ impl<'db> Type<'db> {
40033961 . try_call_dunder_get_on_attribute ( db, owner_attr. clone ( ) )
40043962 . unwrap_or ( owner_attr)
40053963 }
4006- };
4007- result.map_type(|ty| {
4008- // In fixed-point iteration of type inference, the member type must be monotonically widened and not "oscillate".
4009- // Here, monotonicity is guaranteed by pre-unioning the type of the previous iteration into the current result.
4010- let previous_cycle_value = self.member_lookup_with_policy(db, name.clone(), policy);
4011-
4012- let ty = if let Some(previous_ty) = previous_cycle_value.place.ignore_possibly_unbound()
4013- {
4014- UnionType::from_elements(db, [ty, previous_ty])
4015- } else {
4016- ty
4017- };
4018-
4019- let div = Type::divergent(DivergentType::new(
4020- db,
4021- DivergenceKind::MemberLookupWithPolicy {
4022- self_type: self,
4023- name,
4024- policy,
4025- },
4026- ));
4027- let visotor = RecursiveTypeNormalizedVisitor::new(div);
4028- ty.recursive_type_normalized(db, &visotor)
4029- })
3964+ }
40303965 }
40313966
40323967 /// Resolves the boolean value of the type and falls back to [`Truthiness::Ambiguous`] if the type doesn't implement `__bool__` correctly.
@@ -7485,59 +7420,17 @@ impl<'db> KnownInstanceType<'db> {
74857420 }
74867421}
74877422
7488- #[allow(private_interfaces)]
7489- #[derive(Clone, Debug, Eq, Hash, PartialEq, salsa::Update, get_size2::GetSize)]
7490- pub enum DivergenceKind<'db> {
7491- /// Divergence from `{FunctionLiteral, BoundMethodType}::infer_return_type`.
7492- InferReturnType(ScopeId<'db>),
7493- /// Divergence from `ClassLiteral::implicit_attribute_inner`.
7494- ImplicitAttribute {
7495- class_body_scope: ScopeId<'db>,
7496- name: String,
7497- target_method_decorator: MethodDecorator,
7498- },
7499- /// Divergence from `Type::member_lookup_with_policy`.
7500- MemberLookupWithPolicy {
7501- self_type: Type<'db>,
7502- name: Name,
7503- policy: MemberLookupPolicy,
7504- },
7505- /// Divergence from `Type::class_lookup_with_policy`.
7506- ClassLookupWithPolicy {
7507- self_type: Type<'db>,
7508- name: Name,
7509- policy: MemberLookupPolicy,
7510- },
7511- /// Divergence from `infer_expression_type_impl`.
7512- InferExpression(InferExpression<'db>),
7513- /// Divergence from `infer_expression_types_impl`.
7514- InferExpressionTypes(InferExpression<'db>),
7515- /// Divergence from `infer_definition_types`.
7516- InferDefinitionTypes(Definition<'db>),
7517- /// Divergence from `infer_scope_types`.
7518- InferScopeTypes(ScopeId<'db>),
7519- /// Divergence from `infer_unpack_types`.
7520- InferUnpackTypes(Unpack<'db>),
7521- }
7522-
7523- pub(crate) type CycleRecoveryType<'db> = Type<'db>;
7524-
75257423/// A type that is determined to be divergent during recursive type inference.
75267424/// This type must never be eliminated by dynamic type reduction
75277425/// (e.g. `Divergent` is assignable to `@Todo`, but `@Todo | Divergent` must not be reducted to `@Todo`).
75287426/// Otherwise, type inference cannot converge properly.
75297427/// For detailed properties of this type, see the unit test at the end of the file.
7530- #[salsa::interned(debug, heap_size=ruff_memory_usage::heap_size)]
7531- #[derive(PartialOrd, Ord)]
7428+ #[ derive( Copy , Clone , Debug , Eq , Hash , PartialEq , salsa:: Update , get_size2:: GetSize ) ]
75327429pub struct DivergentType < ' db > {
7533- /// The kind of divergence.
7534- #[returns(ref)]
7535- kind: DivergenceKind<'db>,
7430+ /// The scope where this divergence was detected.
7431+ scope : ScopeId < ' db > ,
75367432}
75377433
7538- // The Salsa heap is tracked separately.
7539- impl get_size2::GetSize for DivergentType<'_> {}
7540-
75417434#[ derive( Copy , Clone , Debug , Eq , Hash , PartialEq , salsa:: Update , get_size2:: GetSize ) ]
75427435pub enum DynamicType < ' db > {
75437436 /// An explicitly annotated `typing.Any`
@@ -12000,11 +11893,7 @@ pub(crate) mod tests {
1200011893 let file = system_path_to_file ( & db, "src/foo.py" ) . unwrap ( ) ;
1200111894 let file_scope_id = FileScopeId :: global ( ) ;
1200211895 let scope = file_scope_id. to_scope_id ( & db, file) ;
12003-
12004- let div = Type::divergent(DivergentType::new(
12005- &db,
12006- DivergenceKind::InferReturnType(scope),
12007- ));
11896+ let div = Type :: divergent ( scope) ;
1200811897
1200911898 // The `Divergent` type must not be eliminated in union with other dynamic types,
1201011899 // as this would prevent detection of divergent type inference using `Divergent`.
0 commit comments