@@ -43,19 +43,14 @@ impl Scope {
4343 }
4444 }
4545
46+ /// Identical to `new_block_scope` today — kept as a separate constructor so that
47+ /// iteration-specific behaviour (e.g. break/continue scoping) can be added later.
4648 pub ( crate ) fn new_iteration_scope (
4749 parent_idx : Option < usize > ,
4850 base_offset : usize ,
4951 function_scope_idx : usize ,
5052 ) -> Self {
51- Self {
52- parent_idx,
53- creates_environment : false ,
54- base_offset,
55- function_scope_idx,
56- identifiers : Vec :: default ( ) ,
57- upvalues : Vec :: default ( ) ,
58- }
53+ Self :: new_block_scope ( parent_idx, base_offset, function_scope_idx)
5954 }
6055
6156 pub ( crate ) fn find_slot_by_name ( & self , find_ident : & str ) -> Option < usize > {
@@ -94,9 +89,7 @@ impl Scope {
9489 } ;
9590
9691 let Some ( param_types) = parameters else {
97- // If this branch happens then the function we're matching against is variadic meaning it's always a match
98- debug_assert ! ( false , "we should never be calling find_function_candidates if there were variadic matches" ) ;
99- return Some ( slot) ;
92+ unreachable ! ( "find_function_candidates should never be called when there are variadic matches" ) ;
10093 } ;
10194
10295 let is_good = param_types. len ( ) == find_types. len ( )
@@ -142,6 +135,13 @@ pub struct ScopeTree {
142135}
143136
144137impl ScopeTree {
138+ /// Build a `ScopeTree` seeded with pre-registered global bindings (native functions etc.).
139+ ///
140+ /// Two root scopes exist by design: `global_scope` holds native/built-in bindings that are
141+ /// always accessible, while `scopes[0]` is the user's top-level function scope where
142+ /// user-defined declarations land. This separation keeps native bindings out of the
143+ /// mutable scope chain so they can be searched as a fallback without interfering with
144+ /// user-level shadowing.
145145 pub fn from_global_scope ( global_scope_map : Vec < ( String , StaticType ) > ) -> Self {
146146 let mut global_scope = Scope :: new_function_scope ( None , 0 ) ;
147147 global_scope. identifiers = global_scope_map;
@@ -406,6 +406,9 @@ impl ScopeTree {
406406 /// Used to allocate the list/map accumulator before analysing the body of a
407407 /// for-comprehension, so that any nested comprehensions receive strictly
408408 /// higher slot numbers and cannot collide with this accumulator.
409+ ///
410+ /// Uses `"\x00"` as a sentinel name that can never collide with user identifiers
411+ /// since the lexer never produces null bytes.
409412 pub ( crate ) fn reserve_anonymous_slot ( & mut self ) -> usize {
410413 self . scopes [ self . current_scope_idx ] . allocate ( "\x00 " . to_string ( ) , StaticType :: Any )
411414 }
0 commit comments