@@ -2308,6 +2308,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
23082308 let module = & parsed_module ( self . db ( ) , self . scope ( ) . file ( self . db ( ) ) ) . load ( self . db ( ) ) ;
23092309 let method = current_scope. node ( ) . as_function ( module) ?;
23102310
2311+ let parent_scope_id = current_scope. parent ( ) ?;
2312+ let parent_scope = self . index . scope ( parent_scope_id) ;
2313+ parent_scope. node ( ) . as_class ( module) ?;
2314+
23112315 let definition = self . index . expect_single_definition ( method) ;
23122316 let DefinitionKind :: Function ( func_def) = definition. kind ( self . db ( ) ) else {
23132317 return None ;
@@ -2326,18 +2330,17 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
23262330 return None ;
23272331 }
23282332
2329- if func_type. has_known_decorator ( self . db ( ) , FunctionDecorators :: CLASSMETHOD ) {
2330- // TODO: cls
2333+ if func_type. is_class_method ( self . db ( ) ) {
2334+ // TODO: set the type for ` cls` argument
23312335 return None ;
23322336 } else if func_type. has_known_decorator ( self . db ( ) , FunctionDecorators :: STATICMETHOD ) {
23332337 return None ;
2334- } else {
2335- return Some (
2336- Type :: SpecialForm ( SpecialFormType :: TypingSelf )
2337- . in_type_expression ( self . db ( ) , self . scope ( ) )
2338- . unwrap ( ) ,
2339- ) ;
2340- } ;
2338+ }
2339+ Some (
2340+ Type :: SpecialForm ( SpecialFormType :: TypingSelf )
2341+ . in_type_expression ( self . db ( ) , self . scope ( ) )
2342+ . unwrap ( ) ,
2343+ )
23412344 }
23422345
23432346 /// Set initial declared/inferred types for a `*args` variadic positional parameter.
@@ -3246,6 +3249,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
32463249 dataclass_params. is_some_and ( |params| params. contains ( DataclassParams :: FROZEN ) )
32473250 } ;
32483251
3252+ // TODO: A hacky way to allow assigning instance attributes to self.
3253+ // Without this flag we would emit diagnostics for `self.x = 1` if `x` is unbound.
3254+ // The correct solution is to review how we emit diagnostics in store context.
3255+ let allow_instance_attribute_assignments_to_self = || match object_ty {
3256+ Type :: TypeVar ( tv) => tv. is_self ( db) ,
3257+ _ => false ,
3258+ } ;
3259+
32493260 match object_ty. class_member ( db, attribute. into ( ) ) {
32503261 meta_attr @ PlaceAndQualifiers { .. } if meta_attr. is_class_var ( ) => {
32513262 if emit_diagnostics {
@@ -3351,12 +3362,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
33513362 object_ty. instance_member ( db, attribute) . place
33523363 {
33533364 if instance_attr_boundness == Boundness :: PossiblyUnbound {
3354- report_possibly_unbound_attribute (
3355- & self . context ,
3356- target,
3357- attribute,
3358- object_ty,
3359- ) ;
3365+ if !allow_instance_attribute_assignments_to_self ( ) {
3366+ report_possibly_unbound_attribute (
3367+ & self . context ,
3368+ target,
3369+ attribute,
3370+ object_ty,
3371+ ) ;
3372+ }
33603373 }
33613374
33623375 if is_read_only ( ) {
@@ -3411,11 +3424,13 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
34113424 if let Some ( builder) =
34123425 self . context . report_lint ( & UNRESOLVED_ATTRIBUTE , target)
34133426 {
3414- builder. into_diagnostic ( format_args ! (
3415- "Unresolved attribute `{}` on type `{}`." ,
3416- attribute,
3417- object_ty. display( db)
3418- ) ) ;
3427+ if !allow_instance_attribute_assignments_to_self ( ) {
3428+ builder. into_diagnostic ( format_args ! (
3429+ "Unresolved attribute `{}` on type `{}`." ,
3430+ attribute,
3431+ object_ty. display( db)
3432+ ) ) ;
3433+ }
34193434 }
34203435 }
34213436
0 commit comments