1use crate::{
11 IndexMap, IndexSet,
12 error::{CodegenError, CodegenErrorType},
13};
14use alloc::{borrow::Cow, fmt};
15use bitflags::bitflags;
16use ruff_python_ast as ast;
17use ruff_text_size::{Ranged, TextRange};
18use rustpython_compiler_core::{PositionEncoding, SourceFile, SourceLocation};
19
20#[derive(Clone)]
22pub struct SymbolTable {
23 pub name: String,
25
26 pub typ: CompilerScope,
28
29 pub line_number: u32,
31
32 pub is_nested: bool,
34
35 pub symbols: IndexMap<String, Symbol>,
37
38 pub sub_tables: Vec<SymbolTable>,
41
42 pub next_sub_table: usize,
44
45 pub varnames: Vec<String>,
47
48 pub needs_class_closure: bool,
50
51 pub needs_classdict: bool,
53
54 pub can_see_class_scope: bool,
56
57 pub is_generator: bool,
59
60 pub comp_inlined: bool,
63
64 pub annotation_block: Option<Box<SymbolTable>>,
67
68 pub has_conditional_annotations: bool,
71
72 pub future_annotations: bool,
74
75 pub mangled_names: Option<IndexSet<String>>,
79}
80
81impl SymbolTable {
82 fn new(name: String, typ: CompilerScope, line_number: u32, is_nested: bool) -> Self {
83 Self {
84 name,
85 typ,
86 line_number,
87 is_nested,
88 symbols: IndexMap::default(),
89 sub_tables: vec![],
90 next_sub_table: 0,
91 varnames: Vec::new(),
92 needs_class_closure: false,
93 needs_classdict: false,
94 can_see_class_scope: false,
95 is_generator: false,
96 comp_inlined: false,
97 annotation_block: None,
98 has_conditional_annotations: false,
99 future_annotations: false,
100 mangled_names: None,
101 }
102 }
103
104 pub fn scan_program(
105 program: &ast::ModModule,
106 source_file: SourceFile,
107 ) -> SymbolTableResult<Self> {
108 let mut builder = SymbolTableBuilder::new(source_file);
109 builder.scan_statements(program.body.as_ref())?;
110 builder.finish()
111 }
112
113 pub fn scan_expr(
114 expr: &ast::ModExpression,
115 source_file: SourceFile,
116 ) -> SymbolTableResult<Self> {
117 let mut builder = SymbolTableBuilder::new(source_file);
118 builder.scan_expression(expr.body.as_ref(), ExpressionContext::Load)?;
119 builder.finish()
120 }
121
122 pub fn lookup(&self, name: &str) -> Option<&Symbol> {
123 self.symbols.get(name)
124 }
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub enum CompilerScope {
129 Module,
130 Class,
131 Function,
132 AsyncFunction,
133 Lambda,
134 Comprehension,
135 TypeParams,
136 Annotation,
138}
139
140impl fmt::Display for CompilerScope {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 match self {
143 Self::Module => write!(f, "module"),
144 Self::Class => write!(f, "class"),
145 Self::Function => write!(f, "function"),
146 Self::AsyncFunction => write!(f, "async function"),
147 Self::Lambda => write!(f, "lambda"),
148 Self::Comprehension => write!(f, "comprehension"),
149 Self::TypeParams => write!(f, "type parameter"),
150 Self::Annotation => write!(f, "annotation"),
151 }
157 }
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
163pub enum SymbolScope {
164 Unknown,
165 Local,
166 GlobalExplicit,
167 GlobalImplicit,
168 Free,
169 Cell,
170}
171
172bitflags! {
173 #[derive(Copy, Clone, Debug, PartialEq)]
174 pub struct SymbolFlags: u16 {
175 const REFERENCED = 0x001; const ASSIGNED = 0x002; const PARAMETER = 0x004; const ANNOTATED = 0x008; const IMPORTED = 0x010; const NONLOCAL = 0x020; const ASSIGNED_IN_COMPREHENSION = 0x040;
184 const ITER = 0x080;
187 const FREE_CLASS = 0x100; const GLOBAL = 0x200; const COMP_ITER = 0x400; const COMP_CELL = 0x800; const TYPE_PARAM = 0x1000; const BOUND = Self::ASSIGNED.bits() | Self::PARAMETER.bits() | Self::IMPORTED.bits() | Self::ITER.bits() | Self::TYPE_PARAM.bits();
201 }
202}
203
204#[derive(Debug, Clone)]
207pub struct Symbol {
208 pub name: String,
209 pub scope: SymbolScope,
210 pub flags: SymbolFlags,
211}
212
213impl Symbol {
214 fn new(name: &str) -> Self {
215 Self {
216 name: name.to_owned(),
217 scope: SymbolScope::Unknown,
219 flags: SymbolFlags::empty(),
220 }
221 }
222
223 pub const fn is_global(&self) -> bool {
224 matches!(
225 self.scope,
226 SymbolScope::GlobalExplicit | SymbolScope::GlobalImplicit
227 )
228 }
229
230 pub const fn is_local(&self) -> bool {
231 matches!(self.scope, SymbolScope::Local | SymbolScope::Cell)
232 }
233
234 pub const fn is_bound(&self) -> bool {
235 self.flags.intersects(SymbolFlags::BOUND)
236 }
237}
238
239#[derive(Debug)]
240pub struct SymbolTableError {
241 error: String,
242 location: Option<SourceLocation>,
243}
244
245impl SymbolTableError {
246 pub fn into_codegen_error(self, source_path: String) -> CodegenError {
247 CodegenError {
248 location: self.location,
249 error: CodegenErrorType::SyntaxError(self.error),
250 source_path,
251 }
252 }
253}
254
255type SymbolTableResult<T = ()> = Result<T, SymbolTableError>;
256
257impl core::fmt::Debug for SymbolTable {
258 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
259 write!(
260 f,
261 "SymbolTable({:?} symbols, {:?} sub scopes)",
262 self.symbols.len(),
263 self.sub_tables.len()
264 )
265 }
266}
267
268fn analyze_symbol_table(symbol_table: &mut SymbolTable) -> SymbolTableResult {
272 let mut analyzer = SymbolTableAnalyzer::default();
273 let _newfree = analyzer.analyze_symbol_table(symbol_table, None)?;
276 Ok(())
277}
278
279fn drop_class_free(symbol_table: &mut SymbolTable, newfree: &mut IndexSet<String>) {
288 if newfree.shift_remove("__class__") {
291 symbol_table.needs_class_closure = true;
292 }
293
294 if newfree.shift_remove("__classdict__") {
296 symbol_table.needs_classdict = true;
297 }
298
299 if !symbol_table.needs_classdict && !symbol_table.future_annotations {
302 let has_functions = symbol_table.sub_tables.iter().any(|t| {
303 matches!(
304 t.typ,
305 CompilerScope::Function | CompilerScope::AsyncFunction
306 )
307 });
308 if has_functions {
309 symbol_table.needs_classdict = true;
310 }
311 }
312
313 if newfree.shift_remove("__conditional_annotations__") {
316 symbol_table.has_conditional_annotations = true;
317 }
318}
319
320fn expr_contains_await(expr: &ast::Expr) -> bool {
322 use ast::visitor::Visitor;
323 struct AwaitFinder(bool);
324 impl ast::visitor::Visitor<'_> for AwaitFinder {
325 fn visit_expr(&mut self, expr: &ast::Expr) {
326 if !self.0 {
327 if matches!(expr, ast::Expr::Await(_)) {
328 self.0 = true;
329 } else {
330 ast::visitor::walk_expr(self, expr);
331 }
332 }
333 }
334 }
335 let mut finder = AwaitFinder(false);
336 finder.visit_expr(expr);
337 finder.0
338}
339
340fn inline_comprehension(
343 parent_symbols: &mut SymbolMap,
344 comp: &SymbolTable,
345 comp_free: &mut IndexSet<String>,
346 inlined_cells: &mut IndexSet<String>,
347 parent_type: CompilerScope,
348) {
349 for (name, sub_symbol) in &comp.symbols {
350 if sub_symbol.flags.contains(SymbolFlags::PARAMETER) {
352 continue;
353 }
354
355 if sub_symbol.scope == SymbolScope::Cell
357 || sub_symbol.flags.contains(SymbolFlags::COMP_CELL)
358 {
359 inlined_cells.insert(name.clone());
360 }
361
362 let scope = if sub_symbol.scope == SymbolScope::Free
364 && parent_type == CompilerScope::Class
365 && name == "__class__"
366 {
367 comp_free.swap_remove(name);
368 SymbolScope::GlobalImplicit
369 } else {
370 sub_symbol.scope
371 };
372
373 if let Some(existing) = parent_symbols.get(name) {
374 if existing.is_bound() && parent_type != CompilerScope::Class {
376 let is_free_in_child = comp.sub_tables.iter().any(|child| {
378 child
379 .symbols
380 .get(name)
381 .is_some_and(|s| s.scope == SymbolScope::Free)
382 });
383 if !is_free_in_child {
384 comp_free.swap_remove(name);
385 }
386 }
387 } else {
388 let mut symbol = sub_symbol.clone();
392 symbol.scope = if sub_symbol.is_bound() {
393 SymbolScope::Unknown
394 } else {
395 scope
396 };
397 parent_symbols.insert(name.clone(), symbol);
398 }
399 }
400}
401
402type SymbolMap = IndexMap<String, Symbol>;
403
404mod stack {
405 use alloc::vec::Vec;
406 use core::ptr::NonNull;
407 pub struct StackStack<T> {
408 v: Vec<NonNull<T>>,
409 }
410 impl<T> Default for StackStack<T> {
411 fn default() -> Self {
412 Self { v: Vec::new() }
413 }
414 }
415 impl<T> StackStack<T> {
416 #[cfg(feature = "std")]
419 pub fn with_append<F, R>(&mut self, x: &mut T, f: F) -> R
420 where
421 F: FnOnce(&mut Self) -> R,
422 {
423 self.v.push(x.into());
424 let res = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| f(self)));
425 self.v.pop();
426 res.unwrap_or_else(|x| std::panic::resume_unwind(x))
427 }
428
429 #[cfg(not(feature = "std"))]
434 pub fn with_append<F, R>(&mut self, x: &mut T, f: F) -> R
435 where
436 F: FnOnce(&mut Self) -> R,
437 {
438 self.v.push(x.into());
439 let result = f(self);
440 self.v.pop();
441 result
442 }
443
444 pub fn iter(&self) -> impl DoubleEndedIterator<Item = &T> + '_ {
445 self.as_ref().iter().copied()
446 }
447 pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut T> + '_ {
448 self.as_mut().iter_mut().map(|x| &mut **x)
449 }
450 pub fn len(&self) -> usize {
457 self.v.len()
458 }
459 pub fn is_empty(&self) -> bool {
460 self.len() == 0
461 }
462
463 pub fn as_ref(&self) -> &[&T] {
464 unsafe { &*(self.v.as_slice() as *const [NonNull<T>] as *const [&T]) }
465 }
466
467 pub fn as_mut(&mut self) -> &mut [&mut T] {
468 unsafe { &mut *(self.v.as_mut_slice() as *mut [NonNull<T>] as *mut [&mut T]) }
469 }
470 }
471}
472use stack::StackStack;
473
474#[derive(Default)]
478#[repr(transparent)]
479struct SymbolTableAnalyzer {
480 tables: StackStack<(SymbolMap, CompilerScope)>,
481}
482
483impl SymbolTableAnalyzer {
484 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 let is_class = symbol_table.typ == CompilerScope::Class;
499
500 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 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 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
545 }
546 } else {
547 None
548 };
549 let child_free =
550 inner_scope.analyze_symbol_table(annotation_table, ann_class_entry)?;
551 annotation_free = Some(child_free);
552 }
553 Ok(())
554 })?;
555
556 symbol_table.symbols = info.0;
557
558 let mut inlined_cells: IndexSet<String> = IndexSet::default();
561 let mut newfree = IndexSet::default();
562 for (idx, (mut child_free, is_inlined)) in child_frees.into_iter().enumerate() {
563 if is_inlined {
564 inline_comprehension(
565 &mut symbol_table.symbols,
566 &sub_tables[idx],
567 &mut child_free,
568 &mut inlined_cells,
569 symbol_table.typ,
570 );
571 }
572 newfree.extend(child_free);
573 }
574 if let Some(ann_free) = annotation_free {
575 newfree.extend(ann_free);
579 }
580
581 let sub_tables = &*symbol_table.sub_tables;
582
583 for symbol in symbol_table.symbols.values_mut() {
585 self.analyze_symbol(symbol, symbol_table.typ, sub_tables, class_entry)?;
586
587 if symbol.scope == SymbolScope::Free || symbol.flags.contains(SymbolFlags::FREE_CLASS) {
589 newfree.insert(symbol.name.clone());
590 }
591 }
592
593 for symbol in symbol_table.symbols.values_mut() {
595 if inlined_cells.contains(&symbol.name) {
596 if symbol.scope == SymbolScope::Local {
597 symbol.scope = SymbolScope::Cell;
598 }
599 symbol.flags.insert(SymbolFlags::COMP_CELL);
600 }
601 }
602
603 if symbol_table.typ == CompilerScope::Class {
605 drop_class_free(symbol_table, &mut newfree);
606 }
607
608 Ok(newfree)
609 }
610
611 fn analyze_symbol(
612 &mut self,
613 symbol: &mut Symbol,
614 st_typ: CompilerScope,
615 sub_tables: &[SymbolTable],
616 class_entry: Option<&SymbolMap>,
617 ) -> SymbolTableResult {
618 if symbol
619 .flags
620 .contains(SymbolFlags::ASSIGNED_IN_COMPREHENSION)
621 && st_typ == CompilerScope::Comprehension
622 {
623 self.analyze_symbol_comprehension(symbol, 0)?
628 } else {
629 match symbol.scope {
630 SymbolScope::Free => {
631 if !self.tables.as_ref().is_empty() {
632 let scope_depth = self.tables.as_ref().len();
633 if scope_depth < 2
635 || self.found_in_outer_scope(&symbol.name, st_typ)
636 != Some(SymbolScope::Free)
637 {
638 return Err(SymbolTableError {
639 error: format!("no binding for nonlocal '{}' found", symbol.name),
640 location: None,
642 });
643 }
644 if symbol.flags.contains(SymbolFlags::NONLOCAL) {
646 for (symbols, _typ) in self.tables.iter().rev() {
647 if let Some(sym) = symbols.get(&symbol.name) {
648 if sym.flags.contains(SymbolFlags::TYPE_PARAM) {
649 return Err(SymbolTableError {
650 error: format!(
651 "nonlocal binding not allowed for type parameter '{}'",
652 symbol.name
653 ),
654 location: None,
655 });
656 }
657 if sym.is_bound() {
658 break;
659 }
660 }
661 }
662 }
663 } else {
664 return Err(SymbolTableError {
665 error: format!(
666 "nonlocal {} defined at place without an enclosing scope",
667 symbol.name
668 ),
669 location: None,
671 });
672 }
673 }
674 SymbolScope::GlobalExplicit | SymbolScope::GlobalImplicit => {
675 }
677 SymbolScope::Local | SymbolScope::Cell => {
678 }
680 SymbolScope::Unknown => {
681 let scope = if symbol.is_bound() {
683 self.found_in_inner_scope(sub_tables, &symbol.name, st_typ)
684 .unwrap_or(SymbolScope::Local)
685 } else if let Some(scope) = self.found_in_outer_scope(&symbol.name, st_typ) {
686 scope
688 } else if let Some(class_symbols) = class_entry
689 && let Some(class_sym) = class_symbols.get(&symbol.name)
690 && class_sym.is_bound()
691 && class_sym.scope != SymbolScope::Free
692 {
693 SymbolScope::GlobalImplicit
696 } else if self.tables.is_empty() {
697 SymbolScope::Unknown
699 } else {
700 SymbolScope::GlobalImplicit
702 };
703 symbol.scope = scope;
704 }
705 }
706 }
707 Ok(())
708 }
709
710 fn found_in_outer_scope(&mut self, name: &str, st_typ: CompilerScope) -> Option<SymbolScope> {
711 let mut decl_depth = None;
712 for (i, (symbols, typ)) in self.tables.iter().rev().enumerate() {
713 if matches!(typ, CompilerScope::Module)
714 || matches!(typ, CompilerScope::Class if name != "__class__" && name != "__classdict__" && name != "__conditional_annotations__")
715 {
716 continue;
717 }
718
719 if st_typ == CompilerScope::Annotation
723 && i == 0
724 && matches!(
725 typ,
726 CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Lambda
727 )
728 {
729 continue;
730 }
731
732 if (name == "__class__" || name == "__classdict__")
735 && matches!(typ, CompilerScope::Class)
736 {
737 decl_depth = Some(i);
738 break;
739 }
740
741 if name == "__conditional_annotations__" && matches!(typ, CompilerScope::Class) {
744 decl_depth = Some(i);
745 break;
746 }
747
748 if let Some(sym) = symbols.get(name) {
749 match sym.scope {
750 SymbolScope::GlobalExplicit => return Some(SymbolScope::GlobalExplicit),
751 SymbolScope::GlobalImplicit => {}
752 _ => {
753 if sym.is_bound() {
754 decl_depth = Some(i);
755 break;
756 }
757 }
758 }
759 }
760 }
761
762 if let Some(decl_depth) = decl_depth {
763 let is_class_implicit =
769 name == "__classdict__" || name == "__conditional_annotations__";
770
771 for (table, typ) in self.tables.iter_mut().rev().take(decl_depth) {
772 if let CompilerScope::Class = typ {
773 if let Some(free_class) = table.get_mut(name) {
774 free_class.flags.insert(SymbolFlags::FREE_CLASS)
775 } else {
776 let mut symbol = Symbol::new(name);
777 symbol.flags.insert(SymbolFlags::FREE_CLASS);
778 symbol.scope = SymbolScope::Free;
779 table.insert(name.to_owned(), symbol);
780 }
781 } else if is_class_implicit
782 && matches!(
783 typ,
784 CompilerScope::Function
785 | CompilerScope::AsyncFunction
786 | CompilerScope::Lambda
787 )
788 {
789 } else if !table.contains_key(name) {
792 let mut symbol = Symbol::new(name);
793 symbol.scope = SymbolScope::Free;
794 table.insert(name.to_owned(), symbol);
795 }
796 }
797 }
798
799 decl_depth.map(|_| SymbolScope::Free)
800 }
801
802 fn found_in_inner_scope(
803 &self,
804 sub_tables: &[SymbolTable],
805 name: &str,
806 st_typ: CompilerScope,
807 ) -> Option<SymbolScope> {
808 sub_tables.iter().find_map(|st| {
809 if st.comp_inlined {
812 return self.found_in_inner_scope(&st.sub_tables, name, st_typ);
813 }
814 let sym = st.symbols.get(name)?;
815 if sym.scope == SymbolScope::Free || sym.flags.contains(SymbolFlags::FREE_CLASS) {
816 if st_typ == CompilerScope::Class && name != "__class__" {
817 None
818 } else {
819 Some(SymbolScope::Cell)
820 }
821 } else if sym.scope == SymbolScope::GlobalExplicit && self.tables.is_empty() {
822 Some(SymbolScope::GlobalExplicit)
825 } else {
826 None
827 }
828 })
829 }
830
831 fn analyze_symbol_comprehension(
835 &mut self,
836 symbol: &mut Symbol,
837 parent_offset: usize,
838 ) -> SymbolTableResult {
839 let last = self.tables.iter_mut().rev().nth(parent_offset).unwrap();
841 let symbols = &mut last.0;
842 let table_type = last.1;
843
844 if symbol.flags.contains(SymbolFlags::ITER) {
846 return Err(SymbolTableError {
847 error: format!(
848 "assignment expression cannot rebind comprehension iteration variable {}",
849 symbol.name
850 ),
851 location: None,
853 });
854 }
855
856 match table_type {
857 CompilerScope::Module => {
858 symbol.scope = SymbolScope::GlobalImplicit;
859 }
860 CompilerScope::Class => {
861 return Err(SymbolTableError {
863 error: "assignment expression within a comprehension cannot be used in a class body".to_string(),
864 location: None,
866 });
867 }
868 CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Lambda => {
869 if let Some(parent_symbol) = symbols.get_mut(&symbol.name) {
870 if let SymbolScope::Unknown = parent_symbol.scope {
871 parent_symbol.flags.insert(SymbolFlags::ASSIGNED);
873 }
874
875 symbol.scope = if parent_symbol.is_global() {
876 parent_symbol.scope
877 } else {
878 SymbolScope::Free
879 };
880 } else {
881 let mut cloned_sym = symbol.clone();
882 cloned_sym.scope = SymbolScope::Cell;
883 last.0.insert(cloned_sym.name.to_owned(), cloned_sym);
884 }
885 }
886 CompilerScope::Comprehension => {
887 match symbols.get_mut(&symbol.name) {
889 Some(parent_symbol) => {
890 if parent_symbol.flags.contains(SymbolFlags::ITER) {
892 return Err(SymbolTableError {
893 error: format!(
894 "assignment expression cannot rebind comprehension iteration variable {}",
895 symbol.name
896 ),
897 location: None,
898 });
899 }
900
901 parent_symbol.flags.insert(SymbolFlags::ASSIGNED); }
904 None => {
905 let mut cloned_sym = symbol.clone();
910 cloned_sym.scope = SymbolScope::Free;
911 last.0.insert(cloned_sym.name.to_owned(), cloned_sym);
912 }
913 }
914
915 self.analyze_symbol_comprehension(symbol, parent_offset + 1)?;
916 }
917 CompilerScope::TypeParams => {
918 return Err(SymbolTableError {
920 error: "assignment expression within a comprehension cannot be used within the definition of a generic".to_string(),
921 location: None,
922 });
923 }
924 CompilerScope::Annotation => {
925 return Err(SymbolTableError {
927 error: "named expression cannot be used within an annotation".to_string(),
928 location: None,
929 });
930 }
931 }
932 Ok(())
933 }
934}
935
936#[derive(Clone, Copy, Debug)]
937enum SymbolUsage {
938 Global,
939 Nonlocal,
940 Used,
941 Assigned,
942 Imported,
943 AnnotationAssigned,
944 Parameter,
945 AnnotationParameter,
946 AssignedNamedExprInComprehension,
947 Iter,
948 TypeParam,
949}
950
951struct SymbolTableBuilder {
952 class_name: Option<String>,
953 tables: Vec<SymbolTable>,
955 future_annotations: bool,
956 source_file: SourceFile,
957 current_varnames: Vec<String>,
959 varnames_stack: Vec<Vec<String>>,
961 in_iter_def_exp: bool,
963 in_annotation: bool,
965 in_type_alias: bool,
967 in_comp_inner_loop_target: bool,
969 scope_info: Option<&'static str>,
971 in_conditional_block: bool,
973}
974
975#[derive(Copy, Clone, PartialEq)]
980enum ExpressionContext {
981 Load,
982 Store,
983 Delete,
984 Iter,
985 IterDefinitionExp,
986}
987
988impl SymbolTableBuilder {
989 fn new(source_file: SourceFile) -> Self {
990 let mut this = Self {
991 class_name: None,
992 tables: vec![],
993 future_annotations: false,
994 source_file,
995 current_varnames: Vec::new(),
996 varnames_stack: Vec::new(),
997 in_iter_def_exp: false,
998 in_annotation: false,
999 in_type_alias: false,
1000 in_comp_inner_loop_target: false,
1001 scope_info: None,
1002 in_conditional_block: false,
1003 };
1004 this.enter_scope("top", CompilerScope::Module, 0);
1005 this
1006 }
1007
1008 fn finish(mut self) -> Result<SymbolTable, SymbolTableError> {
1009 assert_eq!(self.tables.len(), 1);
1010 let mut symbol_table = self.tables.pop().unwrap();
1011 symbol_table.varnames = self.current_varnames;
1013 symbol_table.future_annotations = self.future_annotations;
1015 analyze_symbol_table(&mut symbol_table)?;
1016 Ok(symbol_table)
1017 }
1018
1019 fn enter_scope(&mut self, name: &str, typ: CompilerScope, line_number: u32) {
1020 let is_nested = self
1021 .tables
1022 .last()
1023 .map(|table| {
1024 table.is_nested
1025 || matches!(
1026 table.typ,
1027 CompilerScope::Function | CompilerScope::AsyncFunction
1028 )
1029 })
1030 .unwrap_or(false);
1031 let inherited_mangled_names = self
1033 .tables
1034 .last()
1035 .and_then(|t| t.mangled_names.clone())
1036 .filter(|_| typ != CompilerScope::Class);
1037 let mut table = SymbolTable::new(name.to_owned(), typ, line_number, is_nested);
1038 table.future_annotations = self.future_annotations;
1039 table.mangled_names = inherited_mangled_names;
1040 self.tables.push(table);
1041 self.varnames_stack
1043 .push(core::mem::take(&mut self.current_varnames));
1044 }
1045
1046 fn enter_type_param_block(
1047 &mut self,
1048 name: &str,
1049 line_number: u32,
1050 for_class: bool,
1051 ) -> SymbolTableResult {
1052 let in_class = self
1054 .tables
1055 .last()
1056 .is_some_and(|t| t.typ == CompilerScope::Class);
1057
1058 self.enter_scope(name, CompilerScope::TypeParams, line_number);
1059
1060 if let Some(table) = self.tables.last_mut() {
1062 table.can_see_class_scope = in_class;
1063 if for_class {
1066 table.mangled_names = Some(IndexSet::default());
1067 }
1068 }
1069
1070 if in_class {
1072 self.register_name("__classdict__", SymbolUsage::Used, TextRange::default())?;
1073 }
1074
1075 self.register_name(".type_params", SymbolUsage::Assigned, TextRange::default())?;
1077
1078 Ok(())
1079 }
1080
1081 fn leave_scope(&mut self) {
1083 let mut table = self.tables.pop().unwrap();
1084 table.varnames = core::mem::take(&mut self.current_varnames);
1086 self.tables.last_mut().unwrap().sub_tables.push(table);
1087 self.current_varnames = self.varnames_stack.pop().unwrap_or_default();
1089 }
1090
1091 fn enter_annotation_scope(&mut self, line_number: u32) {
1094 let current = self.tables.last_mut().unwrap();
1095 let can_see_class_scope =
1096 current.typ == CompilerScope::Class || current.can_see_class_scope;
1097 let has_conditional = current.has_conditional_annotations;
1098
1099 if current.annotation_block.is_none() {
1101 let mut annotation_table = SymbolTable::new(
1102 "__annotate__".to_owned(),
1103 CompilerScope::Annotation,
1104 line_number,
1105 true, );
1107 annotation_table.can_see_class_scope = can_see_class_scope;
1109 annotation_table.varnames.push("format".to_owned());
1111 current.annotation_block = Some(Box::new(annotation_table));
1112 }
1113
1114 let annotation_table = current.annotation_block.take().unwrap();
1116 self.tables.push(*annotation_table);
1117 self.varnames_stack
1119 .push(core::mem::take(&mut self.current_varnames));
1120 self.current_varnames = self.tables.last().unwrap().varnames.clone();
1121
1122 if can_see_class_scope && !self.future_annotations {
1123 self.add_classdict_freevar();
1124 if has_conditional {
1126 self.add_conditional_annotations_freevar();
1127 }
1128 }
1129 }
1130
1131 fn leave_annotation_scope(&mut self) {
1134 let mut table = self.tables.pop().unwrap();
1135 table.varnames = core::mem::take(&mut self.current_varnames);
1137 let parent = self.tables.last_mut().unwrap();
1139 parent.annotation_block = Some(Box::new(table));
1140 self.current_varnames = self.varnames_stack.pop().unwrap_or_default();
1142 }
1143
1144 fn add_classdict_freevar(&mut self) {
1145 let table = self.tables.last_mut().unwrap();
1146 let name = "__classdict__";
1147 let symbol = table
1148 .symbols
1149 .entry(name.to_owned())
1150 .or_insert_with(|| Symbol::new(name));
1151 symbol.scope = SymbolScope::Free;
1152 symbol
1153 .flags
1154 .insert(SymbolFlags::REFERENCED | SymbolFlags::FREE_CLASS);
1155 }
1156
1157 fn add_conditional_annotations_freevar(&mut self) {
1158 let table = self.tables.last_mut().unwrap();
1159 let name = "__conditional_annotations__";
1160 let symbol = table
1161 .symbols
1162 .entry(name.to_owned())
1163 .or_insert_with(|| Symbol::new(name));
1164 symbol.scope = SymbolScope::Free;
1165 symbol
1166 .flags
1167 .insert(SymbolFlags::REFERENCED | SymbolFlags::FREE_CLASS);
1168 }
1169
1170 fn is_in_async_context(&self) -> bool {
1174 if self.in_annotation {
1177 return false;
1178 }
1179 for table in self.tables.iter().rev() {
1180 match table.typ {
1181 CompilerScope::AsyncFunction => return true,
1182 CompilerScope::Function
1183 | CompilerScope::Lambda
1184 | CompilerScope::Class
1185 | CompilerScope::Module
1186 | CompilerScope::Annotation
1187 | CompilerScope::TypeParams => return false,
1188 CompilerScope::Comprehension => continue,
1190 }
1191 }
1192 false
1193 }
1194
1195 fn line_index_start(&self, range: TextRange) -> u32 {
1196 self.source_file
1197 .to_source_code()
1198 .line_index(range.start())
1199 .get() as _
1200 }
1201
1202 fn scan_statements(&mut self, statements: &[ast::Stmt]) -> SymbolTableResult {
1203 for statement in statements {
1204 self.scan_statement(statement)?;
1205 }
1206 Ok(())
1207 }
1208
1209 fn scan_parameters(&mut self, parameters: &[ast::ParameterWithDefault]) -> SymbolTableResult {
1210 for parameter in parameters {
1211 self.scan_parameter(¶meter.parameter)?;
1212 }
1213 Ok(())
1214 }
1215
1216 fn scan_parameter(&mut self, parameter: &ast::Parameter) -> SymbolTableResult {
1217 self.check_name(
1218 parameter.name.as_str(),
1219 ExpressionContext::Store,
1220 parameter.name.range,
1221 )?;
1222
1223 let usage = if parameter.annotation.is_some() {
1224 SymbolUsage::AnnotationParameter
1225 } else {
1226 SymbolUsage::Parameter
1227 };
1228
1229 let table = self.tables.last().unwrap();
1231 if table.symbols.contains_key(parameter.name.as_str()) {
1232 return Err(SymbolTableError {
1233 error: format!(
1234 "duplicate argument '{}' in function definition",
1235 parameter.name
1236 ),
1237 location: Some(
1238 self.source_file
1239 .to_source_code()
1240 .source_location(parameter.name.range.start(), PositionEncoding::Utf8),
1241 ),
1242 });
1243 }
1244
1245 self.register_ident(¶meter.name, usage)
1246 }
1247
1248 fn scan_annotation(&mut self, annotation: &ast::Expr) -> SymbolTableResult {
1249 self.scan_annotation_inner(annotation, false)
1250 }
1251
1252 fn scan_ann_assign_annotation(&mut self, annotation: &ast::Expr) -> SymbolTableResult {
1254 self.scan_annotation_inner(annotation, true)
1255 }
1256
1257 fn scan_annotation_inner(
1258 &mut self,
1259 annotation: &ast::Expr,
1260 is_ann_assign: bool,
1261 ) -> SymbolTableResult {
1262 let current_scope = self.tables.last().map(|t| t.typ);
1263
1264 if is_ann_assign && !self.future_annotations {
1267 let is_conditional = matches!(current_scope, Some(CompilerScope::Module))
1268 || (matches!(current_scope, Some(CompilerScope::Class))
1269 && self.in_conditional_block);
1270
1271 if is_conditional && !self.tables.last().unwrap().has_conditional_annotations {
1272 self.tables.last_mut().unwrap().has_conditional_annotations = true;
1273 self.register_name(
1274 "__conditional_annotations__",
1275 SymbolUsage::Assigned,
1276 annotation.range(),
1277 )?;
1278 self.register_name(
1279 "__conditional_annotations__",
1280 SymbolUsage::Used,
1281 annotation.range(),
1282 )?;
1283 }
1284 }
1285
1286 let line_number = self.line_index_start(annotation.range());
1288 self.enter_annotation_scope(line_number);
1289
1290 if self.future_annotations {
1291 self.leave_annotation_scope();
1295 return Ok(());
1296 }
1297
1298 let was_in_annotation = self.in_annotation;
1301 self.in_annotation = true;
1302 let result = self.scan_expression(annotation, ExpressionContext::Load);
1303 self.in_annotation = was_in_annotation;
1304
1305 self.leave_annotation_scope();
1306
1307 result
1308 }
1309
1310 fn scan_statement(&mut self, statement: &ast::Stmt) -> SymbolTableResult {
1311 use ast::*;
1312 if let Stmt::ImportFrom(StmtImportFrom { module, names, .. }) = &statement
1313 && module.as_ref().map(|id| id.as_str()) == Some("__future__")
1314 {
1315 self.future_annotations =
1316 self.future_annotations || names.iter().any(|future| &future.name == "annotations");
1317 }
1318
1319 match &statement {
1320 Stmt::Global(StmtGlobal { names, .. }) => {
1321 for name in names {
1322 self.register_ident(name, SymbolUsage::Global)?;
1323 }
1324 }
1325 Stmt::Nonlocal(StmtNonlocal { names, .. }) => {
1326 for name in names {
1327 self.register_ident(name, SymbolUsage::Nonlocal)?;
1328 }
1329 }
1330 Stmt::FunctionDef(StmtFunctionDef {
1331 name,
1332 body,
1333 parameters,
1334 decorator_list,
1335 type_params,
1336 returns,
1337 range,
1338 is_async,
1339 ..
1340 }) => {
1341 self.scan_decorators(decorator_list, ExpressionContext::Load)?;
1342 self.register_ident(name, SymbolUsage::Assigned)?;
1343
1344 let parent_scope_typ = self.tables.last().map(|t| t.typ);
1348 let should_save_annotation_block = matches!(
1349 parent_scope_typ,
1350 Some(CompilerScope::Class)
1351 | Some(CompilerScope::Module)
1352 | Some(CompilerScope::Function)
1353 | Some(CompilerScope::AsyncFunction)
1354 );
1355 let saved_annotation_block = if should_save_annotation_block {
1356 self.tables.last_mut().unwrap().annotation_block.take()
1357 } else {
1358 None
1359 };
1360
1361 let has_type_params = type_params.is_some();
1364 if has_type_params {
1365 self.scan_parameter_defaults(parameters)?;
1366 }
1367
1368 if let Some(type_params) = type_params {
1371 self.enter_type_param_block(
1372 &format!("<generic parameters of {}>", name.as_str()),
1373 self.line_index_start(type_params.range),
1374 false,
1375 )?;
1376 self.scan_type_params(type_params)?;
1377 }
1378 let has_return_annotation = if let Some(expression) = returns {
1379 self.scan_annotation(expression)?;
1380 true
1381 } else {
1382 false
1383 };
1384 self.enter_scope_with_parameters(
1385 name.as_str(),
1386 parameters,
1387 self.line_index_start(*range),
1388 has_return_annotation,
1389 *is_async,
1390 has_type_params, )?;
1392 self.scan_statements(body)?;
1393 self.leave_scope();
1394 if type_params.is_some() {
1395 self.leave_scope();
1396 }
1397
1398 if let Some(block) = saved_annotation_block {
1400 self.tables.last_mut().unwrap().annotation_block = Some(block);
1401 }
1402 }
1403 Stmt::ClassDef(StmtClassDef {
1404 name,
1405 body,
1406 arguments,
1407 decorator_list,
1408 type_params,
1409 range,
1410 node_index: _,
1411 }) => {
1412 let prev_class = self.class_name.take();
1414 if let Some(type_params) = type_params {
1415 self.enter_type_param_block(
1416 &format!("<generic parameters of {}>", name.as_str()),
1417 self.line_index_start(type_params.range),
1418 true, )?;
1420 self.class_name = Some(name.to_string());
1422 self.scan_type_params(type_params)?;
1423 }
1424 self.enter_scope(
1425 name.as_str(),
1426 CompilerScope::Class,
1427 self.line_index_start(*range),
1428 );
1429 let saved_in_conditional = self.in_conditional_block;
1431 self.in_conditional_block = false;
1432 self.class_name = Some(name.to_string());
1433 self.register_name("__module__", SymbolUsage::Assigned, *range)?;
1434 self.register_name("__qualname__", SymbolUsage::Assigned, *range)?;
1435 self.register_name("__doc__", SymbolUsage::Assigned, *range)?;
1436 self.register_name("__class__", SymbolUsage::Assigned, *range)?;
1437 self.scan_statements(body)?;
1438 self.leave_scope();
1439 self.in_conditional_block = saved_in_conditional;
1440 if type_params.is_none() {
1445 self.class_name = prev_class.clone();
1446 }
1447 if let Some(arguments) = arguments {
1448 self.scan_expressions(&arguments.args, ExpressionContext::Load)?;
1449 for keyword in &arguments.keywords {
1450 self.scan_expression(&keyword.value, ExpressionContext::Load)?;
1451 }
1452 }
1453 if type_params.is_some() {
1454 self.leave_scope();
1455 }
1456 self.class_name = prev_class;
1458 self.scan_decorators(decorator_list, ExpressionContext::Load)?;
1459 self.register_ident(name, SymbolUsage::Assigned)?;
1460 }
1461 Stmt::Expr(StmtExpr { value, .. }) => {
1462 self.scan_expression(value, ExpressionContext::Load)?
1463 }
1464 Stmt::If(StmtIf {
1465 test,
1466 body,
1467 elif_else_clauses,
1468 ..
1469 }) => {
1470 self.scan_expression(test, ExpressionContext::Load)?;
1471 let saved_in_conditional_block = self.in_conditional_block;
1473 self.in_conditional_block = true;
1474 self.scan_statements(body)?;
1475 for elif in elif_else_clauses {
1476 if let Some(test) = &elif.test {
1477 self.scan_expression(test, ExpressionContext::Load)?;
1478 }
1479 self.scan_statements(&elif.body)?;
1480 }
1481 self.in_conditional_block = saved_in_conditional_block;
1482 }
1483 Stmt::For(StmtFor {
1484 target,
1485 iter,
1486 body,
1487 orelse,
1488 ..
1489 }) => {
1490 self.scan_expression(target, ExpressionContext::Store)?;
1491 self.scan_expression(iter, ExpressionContext::Load)?;
1492 let saved_in_conditional_block = self.in_conditional_block;
1494 self.in_conditional_block = true;
1495 self.scan_statements(body)?;
1496 self.scan_statements(orelse)?;
1497 self.in_conditional_block = saved_in_conditional_block;
1498 }
1499 Stmt::While(StmtWhile {
1500 test, body, orelse, ..
1501 }) => {
1502 self.scan_expression(test, ExpressionContext::Load)?;
1503 let saved_in_conditional_block = self.in_conditional_block;
1505 self.in_conditional_block = true;
1506 self.scan_statements(body)?;
1507 self.scan_statements(orelse)?;
1508 self.in_conditional_block = saved_in_conditional_block;
1509 }
1510 Stmt::Break(_) | Stmt::Continue(_) | Stmt::Pass(_) => {
1511 }
1513 Stmt::Import(StmtImport { names, .. })
1514 | Stmt::ImportFrom(StmtImportFrom { names, .. }) => {
1515 for name in names {
1516 if let Some(alias) = &name.asname {
1517 self.check_name(alias.as_str(), ExpressionContext::Store, alias.range)?;
1519 self.register_ident(alias, SymbolUsage::Imported)?;
1520 } else if name.name.as_str() == "*" {
1521 if self.tables.last().unwrap().typ != CompilerScope::Module {
1523 return Err(SymbolTableError {
1524 error: "'import *' only allowed at module level".to_string(),
1525 location: Some(self.source_file.to_source_code().source_location(
1526 name.name.range.start(),
1527 PositionEncoding::Utf8,
1528 )),
1529 });
1530 }
1531 } else {
1533 let imported_name = name.name.split('.').next().unwrap();
1535 self.check_name(imported_name, ExpressionContext::Store, name.name.range)?;
1536 self.register_name(imported_name, SymbolUsage::Imported, name.name.range)?;
1537 }
1538 }
1539 }
1540 Stmt::Return(StmtReturn { value, .. }) => {
1541 if let Some(expression) = value {
1542 self.scan_expression(expression, ExpressionContext::Load)?;
1543 }
1544 }
1545 Stmt::Assert(StmtAssert { test, msg, .. }) => {
1546 self.scan_expression(test, ExpressionContext::Load)?;
1547 if let Some(expression) = msg {
1548 self.scan_expression(expression, ExpressionContext::Load)?;
1549 }
1550 }
1551 Stmt::Delete(StmtDelete { targets, .. }) => {
1552 self.scan_expressions(targets, ExpressionContext::Delete)?;
1553 }
1554 Stmt::Assign(StmtAssign { targets, value, .. }) => {
1555 self.scan_expressions(targets, ExpressionContext::Store)?;
1556 self.scan_expression(value, ExpressionContext::Load)?;
1557 }
1558 Stmt::AugAssign(StmtAugAssign { target, value, .. }) => {
1559 self.scan_expression(target, ExpressionContext::Store)?;
1560 self.scan_expression(value, ExpressionContext::Load)?;
1561 }
1562 Stmt::AnnAssign(StmtAnnAssign {
1563 target,
1564 annotation,
1565 value,
1566 simple,
1567 range,
1568 node_index: _,
1569 }) => {
1570 match &**target {
1572 Expr::Name(ast::ExprName { id, .. }) if *simple => {
1573 let id_str = id.as_str();
1574
1575 self.check_name(id_str, ExpressionContext::Store, *range)?;
1576
1577 self.register_name(id_str, SymbolUsage::AnnotationAssigned, *range)?;
1578 let current_scope = self.tables.last().map(|t| t.typ);
1580 match current_scope {
1581 Some(CompilerScope::Module) => {
1582 self.register_name("__annotate__", SymbolUsage::Assigned, *range)?;
1583 }
1584 Some(CompilerScope::Class) => {
1585 self.register_name(
1586 "__annotate_func__",
1587 SymbolUsage::Assigned,
1588 *range,
1589 )?;
1590 }
1591 _ => {}
1592 }
1593 }
1594 _ => {
1595 self.scan_expression(target, ExpressionContext::Store)?;
1596 }
1597 }
1598 let is_simple_name = *simple && matches!(&**target, Expr::Name(_));
1603 if is_simple_name {
1604 self.scan_ann_assign_annotation(annotation)?;
1605 } else {
1606 let was_in_annotation = self.in_annotation;
1609 self.in_annotation = true;
1610 let result = self.scan_expression(annotation, ExpressionContext::Load);
1611 self.in_annotation = was_in_annotation;
1612 result?;
1613 }
1614 if let Some(value) = value {
1615 self.scan_expression(value, ExpressionContext::Load)?;
1616 }
1617 }
1618 Stmt::With(StmtWith { items, body, .. }) => {
1619 for item in items {
1620 self.scan_expression(&item.context_expr, ExpressionContext::Load)?;
1621 if let Some(expression) = &item.optional_vars {
1622 self.scan_expression(expression, ExpressionContext::Store)?;
1623 }
1624 }
1625 let saved_in_conditional_block = self.in_conditional_block;
1627 self.in_conditional_block = true;
1628 self.scan_statements(body)?;
1629 self.in_conditional_block = saved_in_conditional_block;
1630 }
1631 Stmt::Try(StmtTry {
1632 body,
1633 handlers,
1634 orelse,
1635 finalbody,
1636 ..
1637 }) => {
1638 let saved_in_conditional_block = self.in_conditional_block;
1640 self.in_conditional_block = true;
1641 self.scan_statements(body)?;
1642 for handler in handlers {
1643 let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
1644 type_,
1645 name,
1646 body,
1647 ..
1648 }) = &handler;
1649 if let Some(expression) = type_ {
1650 self.scan_expression(expression, ExpressionContext::Load)?;
1651 }
1652 if let Some(name) = name {
1653 self.register_ident(name, SymbolUsage::Assigned)?;
1654 }
1655 self.scan_statements(body)?;
1656 }
1657 self.scan_statements(orelse)?;
1658 self.scan_statements(finalbody)?;
1659 self.in_conditional_block = saved_in_conditional_block;
1660 }
1661 Stmt::Match(StmtMatch { subject, cases, .. }) => {
1662 self.scan_expression(subject, ExpressionContext::Load)?;
1663 let saved_in_conditional_block = self.in_conditional_block;
1665 self.in_conditional_block = true;
1666 for case in cases {
1667 self.scan_pattern(&case.pattern)?;
1668 if let Some(guard) = &case.guard {
1669 self.scan_expression(guard, ExpressionContext::Load)?;
1670 }
1671 self.scan_statements(&case.body)?;
1672 }
1673 self.in_conditional_block = saved_in_conditional_block;
1674 }
1675 Stmt::Raise(StmtRaise { exc, cause, .. }) => {
1676 if let Some(expression) = exc {
1677 self.scan_expression(expression, ExpressionContext::Load)?;
1678 }
1679 if let Some(expression) = cause {
1680 self.scan_expression(expression, ExpressionContext::Load)?;
1681 }
1682 }
1683 Stmt::TypeAlias(StmtTypeAlias {
1684 name,
1685 value,
1686 type_params,
1687 ..
1688 }) => {
1689 let was_in_type_alias = self.in_type_alias;
1690 self.in_type_alias = true;
1691 let in_class = self
1693 .tables
1694 .last()
1695 .is_some_and(|t| t.typ == CompilerScope::Class);
1696 let is_generic = type_params.is_some();
1697 if let Some(type_params) = type_params {
1698 self.enter_type_param_block(
1699 "TypeAlias",
1700 self.line_index_start(type_params.range),
1701 false,
1702 )?;
1703 self.scan_type_params(type_params)?;
1704 }
1705 self.enter_scope(
1707 "TypeAlias",
1708 CompilerScope::TypeParams,
1709 self.line_index_start(value.range()),
1710 );
1711 self.register_name("format", SymbolUsage::Parameter, TextRange::default())?;
1713 if in_class {
1714 if let Some(table) = self.tables.last_mut() {
1715 table.can_see_class_scope = true;
1716 }
1717 self.register_name("__classdict__", SymbolUsage::Used, TextRange::default())?;
1718 }
1719 self.scan_expression(value, ExpressionContext::Load)?;
1720 self.leave_scope();
1721 if is_generic {
1722 self.leave_scope();
1723 }
1724 self.in_type_alias = was_in_type_alias;
1725 self.scan_expression(name, ExpressionContext::Store)?;
1726 }
1727 Stmt::IpyEscapeCommand(_) => todo!(),
1728 }
1729 Ok(())
1730 }
1731
1732 fn scan_decorators(
1733 &mut self,
1734 decorators: &[ast::Decorator],
1735 context: ExpressionContext,
1736 ) -> SymbolTableResult {
1737 for decorator in decorators {
1738 self.scan_expression(&decorator.expression, context)?;
1739 }
1740 Ok(())
1741 }
1742
1743 fn scan_expressions(
1744 &mut self,
1745 expressions: &[ast::Expr],
1746 context: ExpressionContext,
1747 ) -> SymbolTableResult {
1748 for expression in expressions {
1749 self.scan_expression(expression, context)?;
1750 }
1751 Ok(())
1752 }
1753
1754 fn scan_expression(
1755 &mut self,
1756 expression: &ast::Expr,
1757 context: ExpressionContext,
1758 ) -> SymbolTableResult {
1759 use ast::*;
1760
1761 if let Some(keyword) = match expression {
1764 Expr::Yield(_) | Expr::YieldFrom(_) => Some("yield"),
1765 Expr::Await(_) => Some("await"),
1766 Expr::Named(_) => Some("named"),
1767 _ => None,
1768 } {
1769 let context_name = if let Some(scope_info) = self.scope_info {
1772 Some(scope_info)
1773 } else if let Some(table) = self.tables.last()
1774 && table.typ == CompilerScope::TypeParams
1775 {
1776 Some("a type parameter")
1777 } else if self.in_annotation {
1778 Some("an annotation")
1779 } else if self.in_type_alias {
1780 Some("a type alias")
1781 } else {
1782 None
1783 };
1784
1785 if let Some(context_name) = context_name {
1786 return Err(SymbolTableError {
1787 error: format!("{keyword} expression cannot be used within {context_name}"),
1788 location: Some(
1789 self.source_file
1790 .to_source_code()
1791 .source_location(expression.range().start(), PositionEncoding::Utf8),
1792 ),
1793 });
1794 }
1795 }
1796
1797 match expression {
1798 Expr::BinOp(ExprBinOp {
1799 left,
1800 right,
1801 range: _,
1802 ..
1803 }) => {
1804 self.scan_expression(left, context)?;
1805 self.scan_expression(right, context)?;
1806 }
1807 Expr::BoolOp(ExprBoolOp {
1808 values, range: _, ..
1809 }) => {
1810 self.scan_expressions(values, context)?;
1811 }
1812 Expr::Compare(ExprCompare {
1813 left,
1814 comparators,
1815 range: _,
1816 ..
1817 }) => {
1818 self.scan_expression(left, context)?;
1819 self.scan_expressions(comparators, context)?;
1820 }
1821 Expr::Subscript(ExprSubscript {
1822 value,
1823 slice,
1824 range: _,
1825 ..
1826 }) => {
1827 self.scan_expression(value, ExpressionContext::Load)?;
1828 self.scan_expression(slice, ExpressionContext::Load)?;
1829 }
1830 Expr::Attribute(ExprAttribute {
1831 value, attr, range, ..
1832 }) => {
1833 self.check_name(attr.as_str(), context, *range)?;
1834 self.scan_expression(value, ExpressionContext::Load)?;
1835 }
1836 Expr::Dict(ExprDict {
1837 items,
1838 node_index: _,
1839 range: _,
1840 }) => {
1841 for item in items {
1842 if let Some(key) = &item.key {
1843 self.scan_expression(key, context)?;
1844 }
1845 self.scan_expression(&item.value, context)?;
1846 }
1847 }
1848 Expr::Await(ExprAwait {
1849 value,
1850 node_index: _,
1851 range: _,
1852 }) => {
1853 self.scan_expression(value, context)?;
1854 }
1855 Expr::Yield(ExprYield {
1856 value,
1857 node_index: _,
1858 range: _,
1859 }) => {
1860 self.tables.last_mut().unwrap().is_generator = true;
1861 if let Some(expression) = value {
1862 self.scan_expression(expression, context)?;
1863 }
1864 }
1865 Expr::YieldFrom(ExprYieldFrom {
1866 value,
1867 node_index: _,
1868 range: _,
1869 }) => {
1870 self.tables.last_mut().unwrap().is_generator = true;
1871 self.scan_expression(value, context)?;
1872 }
1873 Expr::UnaryOp(ExprUnaryOp {
1874 operand, range: _, ..
1875 }) => {
1876 self.scan_expression(operand, context)?;
1877 }
1878 Expr::Starred(ExprStarred {
1879 value, range: _, ..
1880 }) => {
1881 self.scan_expression(value, context)?;
1882 }
1883 Expr::Tuple(ExprTuple { elts, range: _, .. })
1884 | Expr::Set(ExprSet { elts, range: _, .. })
1885 | Expr::List(ExprList { elts, range: _, .. }) => {
1886 self.scan_expressions(elts, context)?;
1887 }
1888 Expr::Slice(ExprSlice {
1889 lower,
1890 upper,
1891 step,
1892 node_index: _,
1893 range: _,
1894 }) => {
1895 if let Some(lower) = lower {
1896 self.scan_expression(lower, context)?;
1897 }
1898 if let Some(upper) = upper {
1899 self.scan_expression(upper, context)?;
1900 }
1901 if let Some(step) = step {
1902 self.scan_expression(step, context)?;
1903 }
1904 }
1905 Expr::Generator(ExprGenerator {
1906 elt,
1907 generators,
1908 range,
1909 ..
1910 }) => {
1911 let was_in_iter_def_exp = self.in_iter_def_exp;
1912 if context == ExpressionContext::IterDefinitionExp {
1913 self.in_iter_def_exp = true;
1914 }
1915 self.scan_comprehension("<genexpr>", elt, None, generators, *range, true)?;
1917 self.in_iter_def_exp = was_in_iter_def_exp;
1918 }
1919 Expr::ListComp(ExprListComp {
1920 elt,
1921 generators,
1922 range,
1923 node_index: _,
1924 }) => {
1925 let was_in_iter_def_exp = self.in_iter_def_exp;
1926 if context == ExpressionContext::IterDefinitionExp {
1927 self.in_iter_def_exp = true;
1928 }
1929 self.scan_comprehension("<listcomp>", elt, None, generators, *range, false)?;
1931 self.in_iter_def_exp = was_in_iter_def_exp;
1932 }
1933 Expr::SetComp(ExprSetComp {
1934 elt,
1935 generators,
1936 range,
1937 node_index: _,
1938 }) => {
1939 let was_in_iter_def_exp = self.in_iter_def_exp;
1940 if context == ExpressionContext::IterDefinitionExp {
1941 self.in_iter_def_exp = true;
1942 }
1943 self.scan_comprehension("<setcomp>", elt, None, generators, *range, false)?;
1945 self.in_iter_def_exp = was_in_iter_def_exp;
1946 }
1947 Expr::DictComp(ExprDictComp {
1948 key,
1949 value,
1950 generators,
1951 range,
1952 node_index: _,
1953 }) => {
1954 let was_in_iter_def_exp = self.in_iter_def_exp;
1955 if context == ExpressionContext::IterDefinitionExp {
1956 self.in_iter_def_exp = true;
1957 }
1958 self.scan_comprehension("<dictcomp>", key, Some(value), generators, *range, false)?;
1960 self.in_iter_def_exp = was_in_iter_def_exp;
1961 }
1962 Expr::Call(ExprCall {
1963 func,
1964 arguments,
1965 node_index: _,
1966 range: _,
1967 }) => {
1968 match context {
1969 ExpressionContext::IterDefinitionExp => {
1970 self.scan_expression(func, ExpressionContext::IterDefinitionExp)?;
1971 }
1972 _ => {
1973 self.scan_expression(func, ExpressionContext::Load)?;
1974 }
1975 }
1976
1977 self.scan_expressions(&arguments.args, ExpressionContext::Load)?;
1978 for keyword in &arguments.keywords {
1979 if let Some(arg) = &keyword.arg {
1980 self.check_name(arg.as_str(), ExpressionContext::Store, keyword.range)?;
1981 }
1982 self.scan_expression(&keyword.value, ExpressionContext::Load)?;
1983 }
1984 }
1985 Expr::Name(ExprName { id, range, .. }) => {
1986 let id = id.as_str();
1987
1988 self.check_name(id, context, *range)?;
1989
1990 match context {
1992 ExpressionContext::Delete => {
1993 self.register_name(id, SymbolUsage::Assigned, *range)?;
1994 self.register_name(id, SymbolUsage::Used, *range)?;
1995 }
1996 ExpressionContext::Load | ExpressionContext::IterDefinitionExp => {
1997 self.register_name(id, SymbolUsage::Used, *range)?;
1998 }
1999 ExpressionContext::Store => {
2000 self.register_name(id, SymbolUsage::Assigned, *range)?;
2001 }
2002 ExpressionContext::Iter => {
2003 self.register_name(id, SymbolUsage::Iter, *range)?;
2004 }
2005 }
2006 if context == ExpressionContext::Load
2009 && matches!(
2010 self.tables.last().unwrap().typ,
2011 CompilerScope::Function | CompilerScope::AsyncFunction
2012 )
2013 && id == "super"
2014 {
2015 self.register_name("__class__", SymbolUsage::Used, *range)?;
2016 }
2017 }
2018 Expr::Lambda(ExprLambda {
2019 body,
2020 parameters,
2021 node_index: _,
2022 range: _,
2023 }) => {
2024 if let Some(parameters) = parameters {
2025 self.enter_scope_with_parameters(
2026 "lambda",
2027 parameters,
2028 self.line_index_start(expression.range()),
2029 false, false, false, )?;
2033 } else {
2034 self.enter_scope(
2035 "lambda",
2036 CompilerScope::Lambda,
2037 self.line_index_start(expression.range()),
2038 );
2039 }
2040 match context {
2041 ExpressionContext::IterDefinitionExp => {
2042 self.scan_expression(body, ExpressionContext::IterDefinitionExp)?;
2043 }
2044 _ => {
2045 self.scan_expression(body, ExpressionContext::Load)?;
2046 }
2047 }
2048 self.leave_scope();
2049 }
2050 Expr::FString(ExprFString { value, .. }) => {
2051 for expr in value.elements().filter_map(|x| x.as_interpolation()) {
2052 self.scan_expression(&expr.expression, ExpressionContext::Load)?;
2053 if let Some(format_spec) = &expr.format_spec {
2054 for element in format_spec.elements.interpolations() {
2055 self.scan_expression(&element.expression, ExpressionContext::Load)?
2056 }
2057 }
2058 }
2059 }
2060 Expr::TString(tstring) => {
2061 for expr in tstring
2063 .value
2064 .elements()
2065 .filter_map(|x| x.as_interpolation())
2066 {
2067 self.scan_expression(&expr.expression, ExpressionContext::Load)?;
2068 if let Some(format_spec) = &expr.format_spec {
2069 for element in format_spec.elements.interpolations() {
2070 self.scan_expression(&element.expression, ExpressionContext::Load)?
2071 }
2072 }
2073 }
2074 }
2075 Expr::StringLiteral(_)
2077 | Expr::BytesLiteral(_)
2078 | Expr::NumberLiteral(_)
2079 | Expr::BooleanLiteral(_)
2080 | Expr::NoneLiteral(_)
2081 | Expr::EllipsisLiteral(_) => {}
2082 Expr::IpyEscapeCommand(_) => todo!(),
2083 Expr::If(ExprIf {
2084 test,
2085 body,
2086 orelse,
2087 node_index: _,
2088 range: _,
2089 }) => {
2090 self.scan_expression(test, ExpressionContext::Load)?;
2091 self.scan_expression(body, ExpressionContext::Load)?;
2092 self.scan_expression(orelse, ExpressionContext::Load)?;
2093 }
2094
2095 Expr::Named(ExprNamed {
2096 target,
2097 value,
2098 range,
2099 node_index: _,
2100 }) => {
2101 if context == ExpressionContext::IterDefinitionExp || self.in_iter_def_exp {
2104 return Err(SymbolTableError {
2105 error: "assignment expression cannot be used in a comprehension iterable expression".to_string(),
2106 location: Some(self.source_file.to_source_code().source_location(target.range().start(), PositionEncoding::Utf8)),
2107 });
2108 }
2109
2110 self.scan_expression(value, ExpressionContext::Load)?;
2111
2112 if let Expr::Name(ExprName { id, .. }) = &**target {
2117 let id = id.as_str();
2118 self.check_name(id, ExpressionContext::Store, *range)?;
2119 let table = self.tables.last().unwrap();
2120 if table.typ == CompilerScope::Comprehension {
2121 self.register_name(
2122 id,
2123 SymbolUsage::AssignedNamedExprInComprehension,
2124 *range,
2125 )?;
2126 } else {
2127 self.register_name(id, SymbolUsage::Assigned, *range)?;
2131 }
2132 } else {
2133 self.scan_expression(target, ExpressionContext::Store)?;
2134 }
2135 }
2136 }
2137 Ok(())
2138 }
2139
2140 fn scan_comprehension(
2141 &mut self,
2142 scope_name: &str,
2143 elt1: &ast::Expr,
2144 elt2: Option<&ast::Expr>,
2145 generators: &[ast::Comprehension],
2146 range: TextRange,
2147 is_generator: bool,
2148 ) -> SymbolTableResult {
2149 let has_async_gen = generators.iter().any(|g| g.is_async);
2152 if has_async_gen && !is_generator && !self.is_in_async_context() {
2153 return Err(SymbolTableError {
2154 error: "asynchronous comprehension outside of an asynchronous function".to_owned(),
2155 location: Some(
2156 self.source_file
2157 .to_source_code()
2158 .source_location(range.start(), PositionEncoding::Utf8),
2159 ),
2160 });
2161 }
2162
2163 self.enter_scope(
2165 scope_name,
2166 CompilerScope::Comprehension,
2167 self.line_index_start(range),
2168 );
2169 self.tables.last_mut().unwrap().is_generator = is_generator;
2171
2172 let element_has_await = expr_contains_await(elt1) || elt2.is_some_and(expr_contains_await);
2178 if !is_generator && !has_async_gen && !element_has_await {
2179 let parent = self.tables.iter().rev().nth(1);
2180 let parent_can_see_class = parent.is_some_and(|t| t.can_see_class_scope);
2181 let parent_is_func = parent.is_some_and(|t| {
2182 matches!(
2183 t.typ,
2184 CompilerScope::Function
2185 | CompilerScope::AsyncFunction
2186 | CompilerScope::Lambda
2187 | CompilerScope::Comprehension
2188 )
2189 });
2190 if !parent_can_see_class && parent_is_func {
2191 self.tables.last_mut().unwrap().comp_inlined = true;
2192 }
2193 }
2194
2195 self.register_name(".0", SymbolUsage::Parameter, range)?;
2197
2198 self.scan_expression(elt1, ExpressionContext::Load)?;
2199 if let Some(elt2) = elt2 {
2200 self.scan_expression(elt2, ExpressionContext::Load)?;
2201 }
2202
2203 let mut is_first_generator = true;
2204 for generator in generators {
2205 if !is_first_generator {
2207 self.in_comp_inner_loop_target = true;
2208 }
2209 self.scan_expression(&generator.target, ExpressionContext::Iter)?;
2210 self.in_comp_inner_loop_target = false;
2211
2212 if is_first_generator {
2213 is_first_generator = false;
2214 } else {
2215 self.scan_expression(&generator.iter, ExpressionContext::IterDefinitionExp)?;
2216 }
2217
2218 for if_expr in &generator.ifs {
2219 self.scan_expression(if_expr, ExpressionContext::Load)?;
2220 }
2221 }
2222
2223 self.leave_scope();
2224
2225 assert!(!generators.is_empty());
2227 self.scan_expression(&generators[0].iter, ExpressionContext::IterDefinitionExp)?;
2228
2229 Ok(())
2230 }
2231
2232 fn scan_type_param_bound_or_default(
2235 &mut self,
2236 expr: &ast::Expr,
2237 scope_name: &str,
2238 scope_info: &'static str,
2239 ) -> SymbolTableResult {
2240 let in_class = self.tables.last().is_some_and(|t| t.can_see_class_scope);
2243 let line_number = self.line_index_start(expr.range());
2244 self.enter_scope(scope_name, CompilerScope::TypeParams, line_number);
2245 self.register_name("format", SymbolUsage::Parameter, TextRange::default())?;
2247
2248 if in_class {
2249 if let Some(table) = self.tables.last_mut() {
2250 table.can_see_class_scope = true;
2251 }
2252 self.register_name("__classdict__", SymbolUsage::Used, TextRange::default())?;
2253 }
2254
2255 let old_scope_info = self.scope_info;
2257 self.scope_info = Some(scope_info);
2258
2259 let result = self.scan_expression(expr, ExpressionContext::Load);
2261
2262 self.scope_info = old_scope_info;
2264 self.leave_scope();
2265
2266 result
2267 }
2268
2269 fn scan_type_params(&mut self, type_params: &ast::TypeParams) -> SymbolTableResult {
2270 let mut seen_names: IndexSet<&str> = IndexSet::default();
2272 let mut default_seen = false;
2274 for type_param in &type_params.type_params {
2275 let (name, range, has_default) = match type_param {
2276 ast::TypeParam::TypeVar(tv) => (tv.name.as_str(), tv.range, tv.default.is_some()),
2277 ast::TypeParam::ParamSpec(ps) => (ps.name.as_str(), ps.range, ps.default.is_some()),
2278 ast::TypeParam::TypeVarTuple(tvt) => {
2279 (tvt.name.as_str(), tvt.range, tvt.default.is_some())
2280 }
2281 };
2282 if !seen_names.insert(name) {
2283 return Err(SymbolTableError {
2284 error: format!("duplicate type parameter '{}'", name),
2285 location: Some(
2286 self.source_file
2287 .to_source_code()
2288 .source_location(range.start(), PositionEncoding::Utf8),
2289 ),
2290 });
2291 }
2292 if has_default {
2293 default_seen = true;
2294 } else if default_seen {
2295 return Err(SymbolTableError {
2296 error: format!(
2297 "non-default type parameter '{}' follows default type parameter",
2298 name
2299 ),
2300 location: Some(
2301 self.source_file
2302 .to_source_code()
2303 .source_location(range.start(), PositionEncoding::Utf8),
2304 ),
2305 });
2306 }
2307 }
2308
2309 self.register_name(".type_params", SymbolUsage::TypeParam, type_params.range)?;
2311
2312 for type_param in &type_params.type_params {
2314 match type_param {
2315 ast::TypeParam::TypeVar(ast::TypeParamTypeVar {
2316 name,
2317 bound,
2318 range: type_var_range,
2319 default,
2320 node_index: _,
2321 }) => {
2322 self.register_name(name.as_str(), SymbolUsage::TypeParam, *type_var_range)?;
2323
2324 if let Some(binding) = bound {
2326 let (scope_name, scope_info) = if binding.is_tuple_expr() {
2327 (
2328 format!("<TypeVar constraint of {name}>"),
2329 "a TypeVar constraint",
2330 )
2331 } else {
2332 (format!("<TypeVar bound of {name}>"), "a TypeVar bound")
2333 };
2334 self.scan_type_param_bound_or_default(binding, &scope_name, scope_info)?;
2335 }
2336
2337 if let Some(default_value) = default {
2339 let scope_name = format!("<TypeVar default of {name}>");
2340 self.scan_type_param_bound_or_default(
2341 default_value,
2342 &scope_name,
2343 "a TypeVar default",
2344 )?;
2345 }
2346 }
2347 ast::TypeParam::ParamSpec(ast::TypeParamParamSpec {
2348 name,
2349 range: param_spec_range,
2350 default,
2351 node_index: _,
2352 }) => {
2353 self.register_name(name, SymbolUsage::TypeParam, *param_spec_range)?;
2354
2355 if let Some(default_value) = default {
2357 let scope_name = format!("<ParamSpec default of {name}>");
2358 self.scan_type_param_bound_or_default(
2359 default_value,
2360 &scope_name,
2361 "a ParamSpec default",
2362 )?;
2363 }
2364 }
2365 ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple {
2366 name,
2367 range: type_var_tuple_range,
2368 default,
2369 node_index: _,
2370 }) => {
2371 self.register_name(name, SymbolUsage::TypeParam, *type_var_tuple_range)?;
2372
2373 if let Some(default_value) = default {
2375 let scope_name = format!("<TypeVarTuple default of {name}>");
2376 self.scan_type_param_bound_or_default(
2377 default_value,
2378 &scope_name,
2379 "a TypeVarTuple default",
2380 )?;
2381 }
2382 }
2383 }
2384 }
2385 Ok(())
2386 }
2387
2388 fn scan_patterns(&mut self, patterns: &[ast::Pattern]) -> SymbolTableResult {
2389 for pattern in patterns {
2390 self.scan_pattern(pattern)?;
2391 }
2392 Ok(())
2393 }
2394
2395 fn scan_pattern(&mut self, pattern: &ast::Pattern) -> SymbolTableResult {
2396 use ast::Pattern::*;
2397 match pattern {
2398 MatchValue(ast::PatternMatchValue { value, .. }) => {
2399 self.scan_expression(value, ExpressionContext::Load)?
2400 }
2401 MatchSingleton(_) => {}
2402 MatchSequence(ast::PatternMatchSequence { patterns, .. }) => {
2403 self.scan_patterns(patterns)?
2404 }
2405 MatchMapping(ast::PatternMatchMapping {
2406 keys,
2407 patterns,
2408 rest,
2409 ..
2410 }) => {
2411 self.scan_expressions(keys, ExpressionContext::Load)?;
2412 self.scan_patterns(patterns)?;
2413 if let Some(rest) = rest {
2414 self.register_ident(rest, SymbolUsage::Assigned)?;
2415 }
2416 }
2417 MatchClass(ast::PatternMatchClass { cls, arguments, .. }) => {
2418 self.scan_expression(cls, ExpressionContext::Load)?;
2419 self.scan_patterns(&arguments.patterns)?;
2420 for kw in &arguments.keywords {
2421 self.scan_pattern(&kw.pattern)?;
2422 }
2423 }
2424 MatchStar(ast::PatternMatchStar { name, .. }) => {
2425 if let Some(name) = name {
2426 self.register_ident(name, SymbolUsage::Assigned)?;
2427 }
2428 }
2429 MatchAs(ast::PatternMatchAs { pattern, name, .. }) => {
2430 if let Some(pattern) = pattern {
2431 self.scan_pattern(pattern)?;
2432 }
2433 if let Some(name) = name {
2434 self.register_ident(name, SymbolUsage::Assigned)?;
2435 }
2436 }
2437 MatchOr(ast::PatternMatchOr { patterns, .. }) => self.scan_patterns(patterns)?,
2438 }
2439 Ok(())
2440 }
2441
2442 fn scan_parameter_defaults(&mut self, parameters: &ast::Parameters) -> SymbolTableResult {
2444 for default in parameters
2445 .posonlyargs
2446 .iter()
2447 .chain(parameters.args.iter())
2448 .chain(parameters.kwonlyargs.iter())
2449 .filter_map(|arg| arg.default.as_ref())
2450 {
2451 self.scan_expression(default, ExpressionContext::Load)?;
2452 }
2453 Ok(())
2454 }
2455
2456 fn enter_scope_with_parameters(
2457 &mut self,
2458 name: &str,
2459 parameters: &ast::Parameters,
2460 line_number: u32,
2461 has_return_annotation: bool,
2462 is_async: bool,
2463 skip_defaults: bool,
2464 ) -> SymbolTableResult {
2465 if !skip_defaults {
2467 self.scan_parameter_defaults(parameters)?;
2468 }
2469
2470 for annotation in parameters
2472 .posonlyargs
2473 .iter()
2474 .chain(parameters.args.iter())
2475 .chain(parameters.kwonlyargs.iter())
2476 .filter_map(|arg| arg.parameter.annotation.as_ref())
2477 {
2478 self.scan_annotation(annotation)?;
2479 }
2480 if let Some(annotation) = parameters
2481 .vararg
2482 .as_ref()
2483 .and_then(|arg| arg.annotation.as_ref())
2484 {
2485 self.scan_annotation(annotation)?;
2486 }
2487 if let Some(annotation) = parameters
2488 .kwarg
2489 .as_ref()
2490 .and_then(|arg| arg.annotation.as_ref())
2491 {
2492 self.scan_annotation(annotation)?;
2493 }
2494
2495 let has_param_annotations = parameters
2497 .posonlyargs
2498 .iter()
2499 .chain(parameters.args.iter())
2500 .chain(parameters.kwonlyargs.iter())
2501 .any(|p| p.parameter.annotation.is_some())
2502 || parameters
2503 .vararg
2504 .as_ref()
2505 .is_some_and(|p| p.annotation.is_some())
2506 || parameters
2507 .kwarg
2508 .as_ref()
2509 .is_some_and(|p| p.annotation.is_some());
2510
2511 let has_any_annotations = has_param_annotations || has_return_annotation;
2512
2513 let annotation_block = if has_any_annotations {
2517 self.tables.last_mut().unwrap().annotation_block.take()
2518 } else {
2519 None
2520 };
2521
2522 let scope_type = if is_async {
2523 CompilerScope::AsyncFunction
2524 } else {
2525 CompilerScope::Function
2526 };
2527 self.enter_scope(name, scope_type, line_number);
2528
2529 if let Some(block) = annotation_block {
2531 self.tables.last_mut().unwrap().annotation_block = Some(block);
2532 }
2533
2534 self.scan_parameters(¶meters.posonlyargs)?;
2536 self.scan_parameters(¶meters.args)?;
2537 self.scan_parameters(¶meters.kwonlyargs)?;
2538 if let Some(name) = ¶meters.vararg {
2539 self.scan_parameter(name)?;
2540 }
2541 if let Some(name) = ¶meters.kwarg {
2542 self.scan_parameter(name)?;
2543 }
2544 Ok(())
2545 }
2546
2547 fn register_ident(&mut self, ident: &ast::Identifier, role: SymbolUsage) -> SymbolTableResult {
2548 self.register_name(ident.as_str(), role, ident.range)
2549 }
2550
2551 fn check_name(
2552 &self,
2553 name: &str,
2554 context: ExpressionContext,
2555 range: TextRange,
2556 ) -> SymbolTableResult {
2557 if name == "__debug__" {
2558 let location = Some(
2559 self.source_file
2560 .to_source_code()
2561 .source_location(range.start(), PositionEncoding::Utf8),
2562 );
2563 match context {
2564 ExpressionContext::Store | ExpressionContext::Iter => {
2565 return Err(SymbolTableError {
2566 error: "cannot assign to __debug__".to_owned(),
2567 location,
2568 });
2569 }
2570 ExpressionContext::Delete => {
2571 return Err(SymbolTableError {
2572 error: "cannot delete __debug__".to_owned(),
2573 location,
2574 });
2575 }
2576 _ => {}
2577 }
2578 }
2579 Ok(())
2580 }
2581
2582 fn register_name(
2583 &mut self,
2584 name: &str,
2585 role: SymbolUsage,
2586 range: TextRange,
2587 ) -> SymbolTableResult {
2588 let location = self
2589 .source_file
2590 .to_source_code()
2591 .source_location(range.start(), PositionEncoding::Utf8);
2592 let location = Some(location);
2593
2594 let scope_depth = self.tables.len();
2597 let table = self.tables.last_mut().unwrap();
2598
2599 if matches!(role, SymbolUsage::TypeParam)
2601 && let Some(ref mut set) = table.mangled_names
2602 {
2603 set.insert(name.to_owned());
2604 }
2605
2606 let name = maybe_mangle_name(
2607 self.class_name.as_deref(),
2608 table.mangled_names.as_ref(),
2609 name,
2610 );
2611 let symbol = if let Some(symbol) = table.symbols.get_mut(name.as_ref()) {
2613 let flags = &symbol.flags;
2614
2615 if self.in_comp_inner_loop_target
2620 && flags.contains(SymbolFlags::ASSIGNED_IN_COMPREHENSION)
2621 {
2622 return Err(SymbolTableError {
2623 error: format!(
2624 "comprehension inner loop cannot rebind assignment expression target '{}'",
2625 name
2626 ),
2627 location,
2628 });
2629 }
2630
2631 match role {
2633 SymbolUsage::Global if !symbol.is_global() => {
2634 if flags.contains(SymbolFlags::PARAMETER) {
2635 return Err(SymbolTableError {
2636 error: format!("name '{name}' is parameter and global"),
2637 location,
2638 });
2639 }
2640 if flags.contains(SymbolFlags::REFERENCED) {
2641 return Err(SymbolTableError {
2642 error: format!("name '{name}' is used prior to global declaration"),
2643 location,
2644 });
2645 }
2646 if flags.contains(SymbolFlags::ANNOTATED) {
2647 return Err(SymbolTableError {
2648 error: format!("annotated name '{name}' can't be global"),
2649 location,
2650 });
2651 }
2652 if flags.contains(SymbolFlags::ASSIGNED) {
2653 return Err(SymbolTableError {
2654 error: format!(
2655 "name '{name}' is assigned to before global declaration"
2656 ),
2657 location,
2658 });
2659 }
2660 }
2661 SymbolUsage::Nonlocal => {
2662 if flags.contains(SymbolFlags::PARAMETER) {
2663 return Err(SymbolTableError {
2664 error: format!("name '{name}' is parameter and nonlocal"),
2665 location,
2666 });
2667 }
2668 if flags.contains(SymbolFlags::REFERENCED) {
2669 return Err(SymbolTableError {
2670 error: format!("name '{name}' is used prior to nonlocal declaration"),
2671 location,
2672 });
2673 }
2674 if flags.contains(SymbolFlags::ANNOTATED) {
2675 return Err(SymbolTableError {
2676 error: format!("annotated name '{name}' can't be nonlocal"),
2677 location,
2678 });
2679 }
2680 if flags.contains(SymbolFlags::ASSIGNED) {
2681 return Err(SymbolTableError {
2682 error: format!(
2683 "name '{name}' is assigned to before nonlocal declaration"
2684 ),
2685 location,
2686 });
2687 }
2688 }
2689 _ => {
2690 }
2692 }
2693 symbol
2694 } else {
2695 match role {
2698 SymbolUsage::Nonlocal if scope_depth < 2 => {
2699 return Err(SymbolTableError {
2700 error: format!("cannot define nonlocal '{name}' at top level."),
2701 location,
2702 });
2703 }
2704 _ => {
2705 }
2707 }
2708 let symbol = Symbol::new(name.as_ref());
2710 table.symbols.entry(name.into_owned()).or_insert(symbol)
2711 };
2712
2713 let flags = &mut symbol.flags;
2715 match role {
2716 SymbolUsage::Nonlocal => {
2717 symbol.scope = SymbolScope::Free;
2718 flags.insert(SymbolFlags::NONLOCAL);
2719 }
2720 SymbolUsage::Imported => {
2721 flags.insert(SymbolFlags::ASSIGNED | SymbolFlags::IMPORTED);
2722 }
2723 SymbolUsage::Parameter => {
2724 flags.insert(SymbolFlags::PARAMETER);
2725 let name_str = symbol.name.clone();
2727 if !self.current_varnames.contains(&name_str) {
2728 self.current_varnames.push(name_str);
2729 }
2730 }
2731 SymbolUsage::AnnotationParameter => {
2732 flags.insert(SymbolFlags::PARAMETER | SymbolFlags::ANNOTATED);
2733 let name_str = symbol.name.clone();
2735 if !self.current_varnames.contains(&name_str) {
2736 self.current_varnames.push(name_str);
2737 }
2738 }
2739 SymbolUsage::AnnotationAssigned => {
2740 flags.insert(SymbolFlags::ASSIGNED | SymbolFlags::ANNOTATED);
2741 }
2742 SymbolUsage::Assigned => {
2743 flags.insert(SymbolFlags::ASSIGNED);
2744 if symbol.scope == SymbolScope::Local {
2747 let name_str = symbol.name.clone();
2748 if !self.current_varnames.contains(&name_str) {
2749 self.current_varnames.push(name_str);
2750 }
2751 }
2752 }
2753 SymbolUsage::AssignedNamedExprInComprehension => {
2754 flags.insert(SymbolFlags::ASSIGNED | SymbolFlags::ASSIGNED_IN_COMPREHENSION);
2755 if symbol.scope == SymbolScope::Local {
2757 let name_str = symbol.name.clone();
2758 if !self.current_varnames.contains(&name_str) {
2759 self.current_varnames.push(name_str);
2760 }
2761 }
2762 }
2763 SymbolUsage::Global => {
2764 symbol.scope = SymbolScope::GlobalExplicit;
2765 flags.insert(SymbolFlags::GLOBAL);
2766 }
2767 SymbolUsage::Used => {
2768 flags.insert(SymbolFlags::REFERENCED);
2769 }
2770 SymbolUsage::Iter => {
2771 flags.insert(SymbolFlags::ITER);
2772 }
2773 SymbolUsage::TypeParam => {
2774 flags.insert(SymbolFlags::ASSIGNED | SymbolFlags::TYPE_PARAM);
2775 }
2776 }
2777
2778 if flags.contains(SymbolFlags::ITER)
2781 && flags.contains(SymbolFlags::ASSIGNED_IN_COMPREHENSION)
2782 {
2783 return Err(SymbolTableError {
2784 error: format!(
2785 "assignment expression cannot rebind comprehension iteration variable '{}'",
2786 symbol.name
2787 ),
2788 location,
2789 });
2790 }
2791 Ok(())
2792 }
2793}
2794
2795pub(crate) fn mangle_name<'a>(class_name: Option<&str>, name: &'a str) -> Cow<'a, str> {
2796 let class_name = match class_name {
2797 Some(n) => n,
2798 None => return name.into(),
2799 };
2800 if !name.starts_with("__") || name.ends_with("__") || name.contains('.') {
2801 return name.into();
2802 }
2803 let class_name = class_name.trim_start_matches('_');
2805 let mut ret = String::with_capacity(1 + class_name.len() + name.len());
2806 ret.push('_');
2807 ret.push_str(class_name);
2808 ret.push_str(name);
2809 ret.into()
2810}
2811
2812pub(crate) fn maybe_mangle_name<'a>(
2816 class_name: Option<&str>,
2817 mangled_names: Option<&IndexSet<String>>,
2818 name: &'a str,
2819) -> Cow<'a, str> {
2820 if let Some(set) = mangled_names
2821 && !set.contains(name)
2822 {
2823 return name.into();
2824 }
2825 mangle_name(class_name, name)
2826}