@@ -14,14 +14,15 @@ use crate::ast_node_ref::AstNodeRef;
1414use crate :: module_name:: ModuleName ;
1515use crate :: semantic_index:: ast_ids:: node_key:: ExpressionNodeKey ;
1616use crate :: semantic_index:: ast_ids:: AstIdsBuilder ;
17+ use crate :: semantic_index:: attribute_assignment:: { AttributeAssignment , AttributeAssignments } ;
1718use crate :: semantic_index:: constraint:: PatternConstraintKind ;
1819use crate :: semantic_index:: definition:: {
1920 AssignmentDefinitionNodeRef , ComprehensionDefinitionNodeRef , Definition , DefinitionNodeKey ,
2021 DefinitionNodeRef , ForStmtDefinitionNodeRef , ImportFromDefinitionNodeRef ,
2122} ;
22- use crate :: semantic_index:: expression:: Expression ;
23+ use crate :: semantic_index:: expression:: { Expression , ExpressionKind } ;
2324use crate :: semantic_index:: symbol:: {
24- FileScopeId , NodeWithScopeKey , NodeWithScopeRef , Scope , ScopeId , ScopedSymbolId ,
25+ FileScopeId , NodeWithScopeKey , NodeWithScopeRef , Scope , ScopeId , ScopeKind , ScopedSymbolId ,
2526 SymbolTableBuilder ,
2627} ;
2728use crate :: semantic_index:: use_def:: {
@@ -53,17 +54,24 @@ impl LoopState {
5354 }
5455}
5556
57+ struct ScopeInfo {
58+ file_scope_id : FileScopeId ,
59+ loop_state : LoopState ,
60+ }
61+
5662pub ( super ) struct SemanticIndexBuilder < ' db > {
5763 // Builder state
5864 db : & ' db dyn Db ,
5965 file : File ,
6066 module : & ' db ParsedModule ,
61- scope_stack : Vec < ( FileScopeId , LoopState ) > ,
67+ scope_stack : Vec < ScopeInfo > ,
6268 /// The assignments we're currently visiting, with
6369 /// the most recent visit at the end of the Vec
6470 current_assignments : Vec < CurrentAssignment < ' db > > ,
6571 /// The match case we're currently visiting.
6672 current_match_case : Option < CurrentMatchCase < ' db > > ,
73+ /// The name of the first function parameter of the innermost function that we're currently visiting.
74+ current_first_parameter_name : Option < & ' db str > ,
6775
6876 /// Flow states at each `break` in the current loop.
6977 loop_break_states : Vec < FlowSnapshot > ,
@@ -84,6 +92,7 @@ pub(super) struct SemanticIndexBuilder<'db> {
8492 definitions_by_node : FxHashMap < DefinitionNodeKey , Definition < ' db > > ,
8593 expressions_by_node : FxHashMap < ExpressionNodeKey , Expression < ' db > > ,
8694 imported_modules : FxHashSet < ModuleName > ,
95+ attribute_assignments : FxHashMap < FileScopeId , AttributeAssignments < ' db > > ,
8796}
8897
8998impl < ' db > SemanticIndexBuilder < ' db > {
@@ -95,6 +104,7 @@ impl<'db> SemanticIndexBuilder<'db> {
95104 scope_stack : Vec :: new ( ) ,
96105 current_assignments : vec ! [ ] ,
97106 current_match_case : None ,
107+ current_first_parameter_name : None ,
98108 loop_break_states : vec ! [ ] ,
99109 try_node_context_stack_manager : TryNodeContextStackManager :: default ( ) ,
100110
@@ -112,6 +122,8 @@ impl<'db> SemanticIndexBuilder<'db> {
112122 expressions_by_node : FxHashMap :: default ( ) ,
113123
114124 imported_modules : FxHashSet :: default ( ) ,
125+
126+ attribute_assignments : FxHashMap :: default ( ) ,
115127 } ;
116128
117129 builder. push_scope_with_parent ( NodeWithScopeRef :: Module , None ) ;
@@ -123,22 +135,40 @@ impl<'db> SemanticIndexBuilder<'db> {
123135 * self
124136 . scope_stack
125137 . last ( )
126- . map ( |( scope , _ ) | scope )
138+ . map ( |ScopeInfo { file_scope_id , .. } | file_scope_id )
127139 . expect ( "Always to have a root scope" )
128140 }
129141
130142 fn loop_state ( & self ) -> LoopState {
131143 self . scope_stack
132144 . last ( )
133145 . expect ( "Always to have a root scope" )
134- . 1
146+ . loop_state
147+ }
148+
149+ /// Returns the scope ID of the surrounding class body scope if the current scope
150+ /// is a method inside a class body. Returns `None` otherwise, e.g. if the current
151+ /// scope is a function body outside of a class, or if the current scope is not a
152+ /// function body.
153+ fn is_method_of_class ( & self ) -> Option < FileScopeId > {
154+ let mut scopes_rev = self . scope_stack . iter ( ) . rev ( ) ;
155+ let current = scopes_rev. next ( ) ?;
156+ let parent = scopes_rev. next ( ) ?;
157+
158+ match (
159+ self . scopes [ current. file_scope_id ] . kind ( ) ,
160+ self . scopes [ parent. file_scope_id ] . kind ( ) ,
161+ ) {
162+ ( ScopeKind :: Function , ScopeKind :: Class ) => Some ( parent. file_scope_id ) ,
163+ _ => None ,
164+ }
135165 }
136166
137167 fn set_inside_loop ( & mut self , state : LoopState ) {
138168 self . scope_stack
139169 . last_mut ( )
140170 . expect ( "Always to have a root scope" )
141- . 1 = state;
171+ . loop_state = state;
142172 }
143173
144174 fn push_scope ( & mut self , node : NodeWithScopeRef ) {
@@ -171,16 +201,20 @@ impl<'db> SemanticIndexBuilder<'db> {
171201
172202 debug_assert_eq ! ( ast_id_scope, file_scope_id) ;
173203
174- self . scope_stack . push ( ( file_scope_id, LoopState :: NotInLoop ) ) ;
204+ self . scope_stack . push ( ScopeInfo {
205+ file_scope_id,
206+ loop_state : LoopState :: NotInLoop ,
207+ } ) ;
175208 }
176209
177210 fn pop_scope ( & mut self ) -> FileScopeId {
178- let ( id, _) = self . scope_stack . pop ( ) . expect ( "Root scope to be present" ) ;
211+ let ScopeInfo { file_scope_id, .. } =
212+ self . scope_stack . pop ( ) . expect ( "Root scope to be present" ) ;
179213 let children_end = self . scopes . next_index ( ) ;
180- let scope = & mut self . scopes [ id ] ;
214+ let scope = & mut self . scopes [ file_scope_id ] ;
181215 scope. descendents = scope. descendents . start ..children_end;
182216 self . try_node_context_stack_manager . exit_scope ( ) ;
183- id
217+ file_scope_id
184218 }
185219
186220 fn current_symbol_table ( & mut self ) -> & mut SymbolTableBuilder {
@@ -404,6 +438,32 @@ impl<'db> SemanticIndexBuilder<'db> {
404438 self . current_assignments . last_mut ( )
405439 }
406440
441+ /// Records the fact that we saw an attribute assignment of the form
442+ /// `object.attr: <annotation>( = …)` or `object.attr = <value>`.
443+ fn register_attribute_assignment (
444+ & mut self ,
445+ object : & ast:: Expr ,
446+ attr : & ' db ast:: Identifier ,
447+ attribute_assignment : AttributeAssignment < ' db > ,
448+ ) {
449+ if let Some ( class_body_scope) = self . is_method_of_class ( ) {
450+ // We only care about attribute assignments to the first parameter of a method,
451+ // i.e. typically `self` or `cls`.
452+ let accessed_object_refers_to_first_parameter =
453+ object. as_name_expr ( ) . map ( |name| name. id . as_str ( ) )
454+ == self . current_first_parameter_name ;
455+
456+ if accessed_object_refers_to_first_parameter {
457+ self . attribute_assignments
458+ . entry ( class_body_scope)
459+ . or_default ( )
460+ . entry ( attr. id ( ) . clone ( ) )
461+ . or_default ( )
462+ . push ( attribute_assignment) ;
463+ }
464+ }
465+ }
466+
407467 fn add_pattern_constraint (
408468 & mut self ,
409469 subject : Expression < ' db > ,
@@ -457,6 +517,20 @@ impl<'db> SemanticIndexBuilder<'db> {
457517 /// Record an expression that needs to be a Salsa ingredient, because we need to infer its type
458518 /// standalone (type narrowing tests, RHS of an assignment.)
459519 fn add_standalone_expression ( & mut self , expression_node : & ast:: Expr ) -> Expression < ' db > {
520+ self . add_standalone_expression_impl ( expression_node, ExpressionKind :: Normal )
521+ }
522+
523+ /// Same as [`SemanticIndexBuilder::add_standalone_expression`], but marks the expression as a
524+ /// *type* expression, which makes sure that it will later be inferred as such.
525+ fn add_standalone_type_expression ( & mut self , expression_node : & ast:: Expr ) -> Expression < ' db > {
526+ self . add_standalone_expression_impl ( expression_node, ExpressionKind :: TypeExpression )
527+ }
528+
529+ fn add_standalone_expression_impl (
530+ & mut self ,
531+ expression_node : & ast:: Expr ,
532+ expression_kind : ExpressionKind ,
533+ ) -> Expression < ' db > {
460534 let expression = Expression :: new (
461535 self . db ,
462536 self . file ,
@@ -465,6 +539,7 @@ impl<'db> SemanticIndexBuilder<'db> {
465539 unsafe {
466540 AstNodeRef :: new ( self . module . clone ( ) , expression_node)
467541 } ,
542+ expression_kind,
468543 countme:: Count :: default ( ) ,
469544 ) ;
470545 self . expressions_by_node
@@ -668,6 +743,11 @@ impl<'db> SemanticIndexBuilder<'db> {
668743 use_def_maps,
669744 imported_modules : Arc :: new ( self . imported_modules ) ,
670745 has_future_annotations : self . has_future_annotations ,
746+ attribute_assignments : self
747+ . attribute_assignments
748+ . into_iter ( )
749+ . map ( |( k, v) | ( k, Arc :: new ( v) ) )
750+ . collect ( ) ,
671751 }
672752 }
673753}
@@ -706,7 +786,17 @@ where
706786
707787 builder. declare_parameters ( parameters) ;
708788
789+ let mut first_parameter_name = parameters
790+ . iter_non_variadic_params ( )
791+ . next ( )
792+ . map ( |first_param| first_param. parameter . name . id ( ) . as_str ( ) ) ;
793+ std:: mem:: swap (
794+ & mut builder. current_first_parameter_name ,
795+ & mut first_parameter_name,
796+ ) ;
709797 builder. visit_body ( body) ;
798+ builder. current_first_parameter_name = first_parameter_name;
799+
710800 builder. pop_scope ( )
711801 } ,
712802 ) ;
@@ -840,6 +930,19 @@ where
840930 unpack : None ,
841931 first : false ,
842932 } ) ,
933+ ast:: Expr :: Attribute ( ast:: ExprAttribute {
934+ value : object,
935+ attr,
936+ ..
937+ } ) => {
938+ self . register_attribute_assignment (
939+ object,
940+ attr,
941+ AttributeAssignment :: Unannotated { value } ,
942+ ) ;
943+
944+ None
945+ }
843946 _ => None ,
844947 } ;
845948
@@ -858,6 +961,7 @@ where
858961 ast:: Stmt :: AnnAssign ( node) => {
859962 debug_assert_eq ! ( & self . current_assignments, & [ ] ) ;
860963 self . visit_expr ( & node. annotation ) ;
964+ let annotation = self . add_standalone_type_expression ( & node. annotation ) ;
861965 if let Some ( value) = & node. value {
862966 self . visit_expr ( value) ;
863967 }
@@ -869,6 +973,20 @@ where
869973 ) {
870974 self . push_assignment ( node. into ( ) ) ;
871975 self . visit_expr ( & node. target ) ;
976+
977+ if let ast:: Expr :: Attribute ( ast:: ExprAttribute {
978+ value : object,
979+ attr,
980+ ..
981+ } ) = & * node. target
982+ {
983+ self . register_attribute_assignment (
984+ object,
985+ attr,
986+ AttributeAssignment :: Annotated { annotation } ,
987+ ) ;
988+ }
989+
872990 self . pop_assignment ( ) ;
873991 } else {
874992 self . visit_expr ( & node. target ) ;
0 commit comments