@@ -4,7 +4,6 @@ use aether_syntax::AnyRValue;
44use aether_syntax:: RArgumentList ;
55use aether_syntax:: RBinaryExpression ;
66use aether_syntax:: RExpressionList ;
7- use aether_syntax:: RForStatement ;
87use aether_syntax:: RFunctionDefinition ;
98use aether_syntax:: RParameter ;
109use aether_syntax:: RParameters ;
@@ -28,7 +27,6 @@ use crate::semantic_index::ScopeId;
2827use crate :: semantic_index:: ScopeKind ;
2928use crate :: semantic_index:: SemanticIndex ;
3029use crate :: semantic_index:: SymbolFlags ;
31- use crate :: semantic_index:: SymbolId ;
3230use crate :: semantic_index:: SymbolTableBuilder ;
3331use crate :: semantic_index:: Use ;
3432use crate :: semantic_index:: UseId ;
@@ -182,7 +180,7 @@ impl SemanticIndexBuilder {
182180
183181 let builder = self . use_def_builder_mut ( target_scope) ;
184182 builder. ensure_symbol ( target_symbol) ;
185- builder. append_definition ( target_symbol, target_def_id) ;
183+ builder. record_deferred_definition ( target_symbol, target_def_id) ;
186184 }
187185
188186 // Walk up from the parent scope looking for a scope where `name` already
@@ -353,9 +351,8 @@ impl SemanticIndexBuilder {
353351
354352 if let Ok ( body) = stmt. body ( ) {
355353 let first_use = self . uses [ self . current_scope ] . next_id ( ) ;
356- let loop_header = self . build_loop_header ( body. syntax ( ) ) ;
357354 self . collect_expression ( & body) ;
358- self . finish_loop_header ( & loop_header , first_use) ;
355+ self . current_use_def . finish_loop_defs ( & pre_loop , first_use) ;
359356 }
360357
361358 self . current_use_def . merge ( pre_loop) ;
@@ -398,9 +395,8 @@ impl SemanticIndexBuilder {
398395
399396 if let Ok ( body) = stmt. body ( ) {
400397 let first_use = self . uses [ self . current_scope ] . next_id ( ) ;
401- let loop_header = self . build_loop_header ( body. syntax ( ) ) ;
402398 self . collect_expression ( & body) ;
403- self . finish_loop_header ( & loop_header , first_use) ;
399+ self . current_use_def . finish_loop_defs ( & pre_loop , first_use) ;
404400 }
405401
406402 // Body may not execute
@@ -410,10 +406,10 @@ impl SemanticIndexBuilder {
410406 AnyRExpression :: RRepeatStatement ( stmt) => {
411407 // Body always executes at least once, no snapshot needed
412408 if let Ok ( body) = stmt. body ( ) {
409+ let pre_loop = self . current_use_def . snapshot ( ) ;
413410 let first_use = self . uses [ self . current_scope ] . next_id ( ) ;
414- let loop_header = self . build_loop_header ( body. syntax ( ) ) ;
415411 self . collect_expression ( & body) ;
416- self . finish_loop_header ( & loop_header , first_use) ;
412+ self . current_use_def . finish_loop_defs ( & pre_loop , first_use) ;
417413 }
418414 } ,
419415
@@ -553,87 +549,6 @@ impl SemanticIndexBuilder {
553549 }
554550 }
555551
556- // Pre-walk a loop body to find all symbols that will be bound, then
557- // create `LoopHeader` placeholder definitions for each. These are
558- // recorded as additional (non-shadowing) bindings so that uses at the
559- // top of the body can see definitions from a previous iteration.
560- // After the body is visited, `finish_loop_header` resolves each
561- // placeholder to the real definitions that are live at the end of
562- // the body.
563- //
564- // Skips function bodies (different scope) and super-assignments (don't
565- // affect local flow).
566- fn build_loop_header ( & mut self , body : & RSyntaxNode ) -> Vec < ( SymbolId , DefinitionId ) > {
567- let names = Self :: collect_loop_bound_names ( body) ;
568- let mut loop_header = Vec :: new ( ) ;
569-
570- for name in names {
571- let symbol_id =
572- self . symbol_tables [ self . current_scope ] . intern ( & name, SymbolFlags :: IS_BOUND ) ;
573- let def_id = self . definitions [ self . current_scope ] . push ( Definition {
574- symbol : symbol_id,
575- kind : DefinitionKind :: LoopHeader ,
576- range : body. text_trimmed_range ( ) ,
577- } ) ;
578-
579- self . current_use_def . ensure_symbol ( symbol_id) ;
580- self . current_use_def . append_definition ( symbol_id, def_id) ;
581- loop_header. push ( ( symbol_id, def_id) ) ;
582- }
583-
584- loop_header
585- }
586-
587- fn finish_loop_header ( & mut self , loop_header : & [ ( SymbolId , DefinitionId ) ] , first_use : UseId ) {
588- for & ( symbol_id, placeholder_id) in loop_header {
589- self . current_use_def
590- . resolve_placeholder ( symbol_id, placeholder_id, first_use) ;
591- }
592- }
593-
594- // Keep in sync with `collect_expression`: Every construct that creates
595- // a definition there must be matched here so that loop headers account
596- // for all bindings in the body.
597- fn collect_loop_bound_names ( body : & RSyntaxNode ) -> Vec < String > {
598- let mut names = Vec :: new ( ) ;
599- let mut preorder = body. preorder ( ) ;
600-
601- while let Some ( event) = preorder. next ( ) {
602- let WalkEvent :: Enter ( node) = event else {
603- continue ;
604- } ;
605-
606- match node. kind ( ) {
607- // Function bodies are separate scopes. In the future we'll need
608- // an indirection here to handle other kinds of local scopes, in
609- // particular from NSE functions like `local()`.
610- RSyntaxKind :: R_FUNCTION_DEFINITION => {
611- preorder. skip_subtree ( ) ;
612- } ,
613-
614- RSyntaxKind :: R_BINARY_EXPRESSION => {
615- let op: RBinaryExpression = node. cast ( ) . unwrap ( ) ;
616- if let Some ( ( name, _) ) = assignment_target ( & op) {
617- names. push ( name) ;
618- }
619- } ,
620-
621- RSyntaxKind :: R_FOR_STATEMENT => {
622- let for_stmt: RForStatement = node. cast ( ) . unwrap ( ) ;
623- if let Ok ( variable) = for_stmt. variable ( ) {
624- names. push ( identifier_text ( & variable) ) ;
625- }
626- } ,
627-
628- _ => { } ,
629- }
630- }
631-
632- names. sort ( ) ;
633- names. dedup ( ) ;
634- names
635- }
636-
637552 fn collect_arguments ( & mut self , args : & RArgumentList ) {
638553 for item in args. iter ( ) {
639554 let Ok ( arg) = item else { continue } ;
@@ -709,18 +624,6 @@ fn string_value_text(s: &aether_syntax::RStringValue) -> Option<String> {
709624 Some ( text[ 1 ..text. len ( ) - 1 ] . to_string ( ) )
710625}
711626
712- /// For a local (non-super) assignment, extract the binding name and range.
713- /// Returns `None` if the expression is not an assignment, is a
714- /// super-assignment, or has a complex target (`x$foo`, `x[1]`, etc.).
715- fn assignment_target ( bin : & RBinaryExpression ) -> Option < ( String , TextRange ) > {
716- if !is_assignment ( bin) || is_super_assignment ( bin) {
717- return None ;
718- }
719- let right = is_right_assignment ( bin) ;
720- let target = if right { bin. right ( ) } else { bin. left ( ) } . ok ( ) ?;
721- assignment_target_name ( & target)
722- }
723-
724627/// Extract the binding name and range from an assignment target expression.
725628/// Returns `None` for complex targets (`x$foo`, `x[1]`, etc.) that don't
726629/// represent simple name bindings.
0 commit comments