Analyze a symbol table and return the set of free variables. See symtable.c analyze_block(). class_entry: PEP 649 - enclosing class symbols for annotation scopes
(
&mut self,
symbol_table: &mut SymbolTable,
class_entry: Option<&SymbolMap>,
)
| 485 | /// See symtable.c analyze_block(). |
| 486 | /// class_entry: PEP 649 - enclosing class symbols for annotation scopes |
| 487 | fn analyze_symbol_table( |
| 488 | &mut self, |
| 489 | symbol_table: &mut SymbolTable, |
| 490 | class_entry: Option<&SymbolMap>, |
| 491 | ) -> SymbolTableResult<IndexSet<String>> { |
| 492 | let symbols = core::mem::take(&mut symbol_table.symbols); |
| 493 | let sub_tables = &mut *symbol_table.sub_tables; |
| 494 | |
| 495 | let annotation_block = &mut symbol_table.annotation_block; |
| 496 | |
| 497 | // PEP 649: Determine class_entry to pass to children |
| 498 | let is_class = symbol_table.typ == CompilerScope::Class; |
| 499 | |
| 500 | // Clone class symbols if needed for child scopes with can_see_class_scope |
| 501 | let needs_class_symbols = (is_class |
| 502 | && (sub_tables.iter().any(|st| st.can_see_class_scope) |
| 503 | || annotation_block |
| 504 | .as_ref() |
| 505 | .is_some_and(|b| b.can_see_class_scope))) |
| 506 | || (!is_class |
| 507 | && class_entry.is_some() |
| 508 | && sub_tables.iter().any(|st| st.can_see_class_scope)); |
| 509 | |
| 510 | let class_symbols_clone = if is_class && needs_class_symbols { |
| 511 | Some(symbols.clone()) |
| 512 | } else { |
| 513 | None |
| 514 | }; |
| 515 | |
| 516 | // Collect (child_free, is_inlined) pairs from child scopes. |
| 517 | // We need to process inlined comprehensions after the closure |
| 518 | // when we have access to symbol_table.symbols. |
| 519 | let mut child_frees: Vec<(IndexSet<String>, bool)> = Vec::new(); |
| 520 | let mut annotation_free: Option<IndexSet<String>> = None; |
| 521 | |
| 522 | let mut info = (symbols, symbol_table.typ); |
| 523 | self.tables.with_append(&mut info, |list| { |
| 524 | let inner_scope = unsafe { &mut *(list as *mut _ as *mut Self) }; |
| 525 | for sub_table in sub_tables.iter_mut() { |
| 526 | let child_class_entry = if sub_table.can_see_class_scope { |
| 527 | if is_class { |
| 528 | class_symbols_clone.as_ref() |
| 529 | } else { |
| 530 | class_entry |
| 531 | } |
| 532 | } else { |
| 533 | None |
| 534 | }; |
| 535 | let child_free = inner_scope.analyze_symbol_table(sub_table, child_class_entry)?; |
| 536 | child_frees.push((child_free, sub_table.comp_inlined)); |
| 537 | } |
| 538 | // PEP 649: Analyze annotation block if present |
| 539 | if let Some(annotation_table) = annotation_block { |
| 540 | let ann_class_entry = if annotation_table.can_see_class_scope { |
| 541 | if is_class { |
| 542 | class_symbols_clone.as_ref() |
| 543 | } else { |
| 544 | class_entry |
no test coverage detected