1use llmcc_core::context::CompileUnit;
2use llmcc_core::ir::{HirId, HirIdent, HirNode, HirScope};
3use llmcc_core::next_hir_id;
4use llmcc_core::scope::{Scope, ScopeStack};
5use llmcc_core::symbol::{ScopeId, SymKind, SymKindSet, Symbol};
6use llmcc_resolver::{CollectorScopes, ResolverOption};
7
8use std::collections::HashMap;
9
10use crate::LangRust;
11use crate::token::AstVisitorRust;
12
13fn is_method_context(parent: Option<&Symbol>) -> bool {
16 parent.is_some_and(|p| {
17 matches!(
18 p.kind(),
19 SymKind::Struct | SymKind::Enum | SymKind::Trait | SymKind::UnresolvedType
20 )
21 })
22}
23
24type ScopeEntryCallback<'tcx> = Box<dyn FnOnce(&HirNode<'tcx>, &mut CollectorScopes<'tcx>) + 'tcx>;
26
27#[derive(Debug)]
28pub struct CollectorVisitor<'tcx> {
29 scope_map: HashMap<ScopeId, &'tcx Scope<'tcx>>,
30}
31
32impl<'tcx> CollectorVisitor<'tcx> {
33 fn new() -> Self {
34 Self {
35 scope_map: HashMap::new(),
36 }
37 }
38
39 fn declare_symbol(
41 &self,
42 unit: &CompileUnit<'tcx>,
43 node: &HirNode<'tcx>,
44 scopes: &CollectorScopes<'tcx>,
45 kind: SymKind,
46 field_id: u16,
47 ) -> Option<&'tcx Symbol> {
48 let ident = node
50 .ident_by_field(unit, field_id)
51 .or_else(|| node.as_scope().and_then(|sn| sn.opt_ident()))?;
52
53 tracing::trace!("declaring symbol '{}' of kind {:?}", ident.name, kind);
54 let sym = scopes.lookup_or_insert(ident.name, node, kind)?;
55 ident.set_symbol(sym);
56
57 if let Some(sn) = node.as_scope() {
59 sn.set_ident(ident);
60 }
61
62 Some(sym)
63 }
64
65 fn collect_pattern_identifiers(
67 unit: &CompileUnit<'tcx>,
68 node: &HirNode<'tcx>,
69 scopes: &CollectorScopes<'tcx>,
70 kind: SymKind,
71 ) -> Vec<&'tcx Symbol> {
72 let mut symbols = Vec::new();
73 Self::collect_pattern_identifiers_impl(unit, node, scopes, kind, &mut symbols);
74 symbols
75 }
76
77 fn collect_pattern_identifiers_impl(
83 unit: &CompileUnit<'tcx>,
84 node: &HirNode<'tcx>,
85 scopes: &CollectorScopes<'tcx>,
86 kind: SymKind,
87 symbols: &mut Vec<&'tcx Symbol>,
88 ) {
89 if matches!(
90 node.kind_id(),
91 LangRust::type_identifier | LangRust::primitive_type | LangRust::field_identifier |
93 LangRust::scoped_identifier | LangRust::scoped_type_identifier
95 ) {
96 return;
97 }
98
99 if let Some(ident) = node.as_ident() {
100 let name = ident.name.to_string();
101 let sym = scopes.lookup_or_insert(&name, node, kind);
102
103 if let Some(sym) = sym {
104 ident.set_symbol(sym);
105 symbols.push(sym);
106 }
107 }
108 for &child_id in node.child_ids() {
109 let child = unit.hir_node(child_id);
110 Self::collect_pattern_identifiers_impl(unit, &child, scopes, kind, symbols);
111 }
112 }
113
114 fn alloc_scope(&mut self, unit: &CompileUnit<'tcx>, symbol: &'tcx Symbol) -> &'tcx Scope<'tcx> {
115 let scope = unit.cc.alloc_scope(symbol.owner());
116 scope.set_symbol(symbol);
117 self.scope_map.insert(scope.id(), scope);
118 scope
119 }
120
121 fn get_scope(&self, scope_id: ScopeId) -> Option<&'tcx Scope<'tcx>> {
122 self.scope_map.get(&scope_id).copied()
123 }
124
125 fn lookup_or_convert(
127 &mut self,
128 unit: &CompileUnit<'tcx>,
129 scopes: &mut CollectorScopes<'tcx>,
130 name: &str,
131 node: &HirNode<'tcx>,
132 kind: SymKind,
133 ) -> Option<&'tcx Symbol> {
134 tracing::trace!(
135 "looking up or converting symbol '{}' of kind {:?}",
136 name,
137 kind
138 );
139
140 if let Some(symbol) = scopes.lookup_symbol(name, SymKindSet::from_kind(kind)) {
142 tracing::trace!(
143 "found existing symbol '{}' of kind {:?} {:?}",
144 name,
145 kind,
146 symbol,
147 );
148 return Some(symbol);
149 }
150
151 if let Some(symbol) =
153 scopes.lookup_symbol(name, SymKindSet::from_kind(SymKind::UnresolvedType))
154 {
155 tracing::trace!(
156 "found existing unresolved symbol '{}', converting to {:?}, {:?}",
157 name,
158 kind,
159 symbol,
160 );
161 symbol.set_kind(kind);
163 return Some(symbol);
164 }
165
166 if let Some(symbol) = scopes.lookup_or_insert(name, node, kind) {
168 tracing::trace!("inserting new symbol '{}' of kind {:?}", name, kind,);
169 if symbol.opt_scope().is_none() {
171 let scope = self.alloc_scope(unit, symbol);
172 symbol.set_scope(scope.id());
173 }
174 return Some(symbol);
175 }
176
177 None
178 }
179
180 #[allow(clippy::too_many_arguments)]
183 #[tracing::instrument(skip_all)]
184 fn visit_with_scope(
185 &mut self,
186 unit: &CompileUnit<'tcx>,
187 node: &HirNode<'tcx>,
188 scopes: &mut CollectorScopes<'tcx>,
189 sym: &'tcx Symbol,
190 sn: &'tcx HirScope<'tcx>,
191 ident: &'tcx HirIdent<'tcx>,
192 on_scope_enter: Option<ScopeEntryCallback<'tcx>>,
193 ) {
194 tracing::trace!(
195 "visiting with scope for symbol {}",
196 sym.format(Some(scopes.interner()))
197 );
198 ident.set_symbol(sym);
199 sn.set_ident(ident);
200
201 let scope = if sym.opt_scope().is_none() {
202 tracing::trace!(
203 "allocating new scope for symbol {}",
204 sym.format(Some(scopes.interner()))
205 );
206 self.alloc_scope(unit, sym)
207 } else {
208 tracing::trace!(
209 "use existing scope for symbol {}",
210 sym.format(Some(scopes.interner()))
211 );
212 match self.get_scope(sym.scope()) {
213 Some(s) => s,
214 None => {
215 tracing::warn!(
216 "scope not found for symbol {}, allocating new",
217 sym.format(Some(scopes.interner()))
218 );
219 self.alloc_scope(unit, sym)
220 }
221 }
222 };
223 sym.set_scope(scope.id());
224 sn.set_scope(scope);
225
226 scopes.push_scope(scope);
227 if let Some(callback) = on_scope_enter {
228 callback(node, scopes);
229 }
230 self.visit_children(unit, node, scopes, scope, Some(sym));
231 scopes.pop_scope();
232 }
233
234 #[allow(clippy::too_many_arguments)]
237 #[tracing::instrument(skip_all)]
238 fn visit_scoped_named(
239 &mut self,
240 unit: &CompileUnit<'tcx>,
241 node: &HirNode<'tcx>,
242 scopes: &mut CollectorScopes<'tcx>,
243 _namespace: &'tcx Scope<'tcx>,
244 _parent: Option<&Symbol>,
245 kind: SymKind,
246 field_id: u16,
247 on_scope_enter: Option<ScopeEntryCallback<'tcx>>,
248 ) {
249 if let Some((sn, ident)) = node.scope_and_ident_by_field(unit, field_id) {
250 tracing::trace!(
251 "visiting scoped named node with kind '{:?}' '{}'",
252 kind,
253 ident.name
254 );
255 if let Some(sym) = self.lookup_or_convert(unit, scopes, ident.name, node, kind) {
256 self.visit_with_scope(unit, node, scopes, sym, sn, ident, on_scope_enter);
257 }
258 } else {
259 tracing::warn!("scoped named node is missing scope or ident, skipping");
260 }
261 }
262}
263
264impl<'tcx> AstVisitorRust<'tcx, CollectorScopes<'tcx>> for CollectorVisitor<'tcx> {
265 #[tracing::instrument(skip_all)]
271 fn visit_block(
272 &mut self,
273 unit: &CompileUnit<'tcx>,
274 node: &HirNode<'tcx>,
275 scopes: &mut CollectorScopes<'tcx>,
276 _namespace: &'tcx Scope<'tcx>,
277 parent: Option<&Symbol>,
278 ) {
279 if let Some(sn) = node.as_scope() {
280 let scope = unit.cc.alloc_scope(node.id());
281 sn.set_scope(scope);
282
283 scopes.push_scope(scope);
284 self.visit_children(unit, node, scopes, scope, parent);
285 scopes.pop_scope();
286 }
287 }
288
289 fn visit_match_block(
290 &mut self,
291 unit: &CompileUnit<'tcx>,
292 node: &HirNode<'tcx>,
293 scopes: &mut CollectorScopes<'tcx>,
294 namespace: &'tcx Scope<'tcx>,
295 parent: Option<&Symbol>,
296 ) {
297 self.visit_block(unit, node, scopes, namespace, parent);
298 }
299
300 #[rustfmt::skip]
303 #[tracing::instrument(skip_all)]
304 fn visit_source_file(
305 &mut self,
306 unit: &CompileUnit<'tcx>,
307 node: &HirNode<'tcx>,
308 scopes: &mut CollectorScopes<'tcx>,
309 namespace: &'tcx Scope<'tcx>,
310 parent: Option<&Symbol>,
311 ) {
312 let start_depth = scopes.scope_depth();
313 let meta = unit.unit_meta();
314
315 let mut crate_scope: Option<&'tcx Scope<'tcx>> = None;
317
318 if let Some(ref crate_name) = meta.package_name
320 && let Some(symbol) = scopes.lookup_or_insert_global(crate_name, node, SymKind::Crate)
321 {
322 tracing::trace!("insert crate symbol in globals '{}'", crate_name);
323 scopes.push_scope_with(node, Some(symbol));
324 crate_scope = scopes.top();
325 }
326
327 let mut module_wrapper_scope: Option<&'tcx Scope<'tcx>> = None;
330 if let Some(ref module_name) = meta.module_name
331 && let Some(module_sym) = scopes.lookup_or_insert_global(module_name, node, SymKind::Module)
332 {
333 tracing::trace!("insert module symbol in globals '{}'", module_name);
334 let mod_scope = self.alloc_scope(unit, module_sym);
337 if let Some(crate_s) = crate_scope {
338 mod_scope.add_parent(crate_s);
339 }
340 module_wrapper_scope = Some(mod_scope);
341 }
344
345 let sn = node.as_scope().unwrap();
346 if let Some(ref file_name) = meta.file_name
347 && let Some(file_sym) = scopes.lookup_or_insert(file_name, node, SymKind::File)
348 {
349 tracing::trace!("insert file symbol '{}' in current scope", file_name);
350 let arena_name = unit.cc.arena().alloc_str(file_name);
351 let ident = unit.cc.alloc_file_ident(next_hir_id(), arena_name, file_sym);
352 ident.set_symbol(file_sym);
353 sn.set_ident(ident);
354
355 let scope = self.alloc_scope(unit, file_sym);
356 file_sym.set_scope(scope.id());
357 sn.set_scope(scope);
358
359 if let Some(crate_s) = crate_scope {
361 scope.add_parent(crate_s);
362 }
363 if let Some(module_s) = module_wrapper_scope {
364 scope.add_parent(module_s);
365 }
366
367 scopes.push_scope(scope);
368
369 if let Some(crate_sym) = scopes.lookup_or_insert_global("crate", node, SymKind::Module) {
370 tracing::trace!("insert 'crate' symbol in globals");
371 crate_sym.set_scope(scopes.scopes().globals().id());
373 }
374
375 if file_name != "lib" && file_name != "main" && module_wrapper_scope.is_none() {
381 if let Some(mod_sym) = scopes.insert_in_global(file_name, node, SymKind::Module) {
383 tracing::trace!("link file '{}' as module in global scope", file_name);
384 mod_sym.set_scope(scope.id());
385 }
386 if let Some(crate_s) = crate_scope
388 && let Some(mod_sym) =
389 scopes.insert_in_scope(crate_s, file_name, node, SymKind::Module)
390 {
391 tracing::trace!(
392 "link file '{}' as module in crate scope {:?}",
393 file_name,
394 crate_s.id()
395 );
396 mod_sym.set_scope(scope.id());
397 }
398 }
399 }
400
401 self.visit_children(unit, node, scopes, namespace, parent);
403
404 scopes.pop_until(start_depth);
405 }
406
407 #[tracing::instrument(skip_all)]
410 fn visit_mod_item(
411 &mut self,
412 unit: &CompileUnit<'tcx>,
413 node: &HirNode<'tcx>,
414 scopes: &mut CollectorScopes<'tcx>,
415 namespace: &'tcx Scope<'tcx>,
416 parent: Option<&Symbol>,
417 ) {
418 if node.child_by_field(unit, LangRust::field_body).is_none() {
419 return;
420 }
421
422 let parent_scope_id = scopes.top().map(|s| s.id()).unwrap_or(namespace.id());
424
425 let on_scope_enter: ScopeEntryCallback<'tcx> = Box::new(move |node, scopes| {
427 if let Some(super_sym) = scopes.lookup_or_insert("super", node, SymKind::Module) {
429 super_sym.set_scope(parent_scope_id);
430 tracing::trace!(
431 "inserted 'super' symbol pointing to scope {:?}",
432 parent_scope_id
433 );
434 }
435 });
436
437 self.visit_scoped_named(
438 unit,
439 node,
440 scopes,
441 namespace,
442 parent,
443 SymKind::Namespace,
444 LangRust::field_name,
445 Some(on_scope_enter),
446 );
447 }
448
449 #[tracing::instrument(skip_all)]
452 fn visit_function_item(
453 &mut self,
454 unit: &CompileUnit<'tcx>,
455 node: &HirNode<'tcx>,
456 scopes: &mut CollectorScopes<'tcx>,
457 namespace: &'tcx Scope<'tcx>,
458 parent: Option<&Symbol>,
459 ) {
460 let is_method = is_method_context(parent);
462 let kind = if is_method {
463 SymKind::Method
464 } else {
465 SymKind::Function
466 };
467
468 self.visit_scoped_named(
469 unit,
470 node,
471 scopes,
472 namespace,
473 parent,
474 kind,
475 LangRust::field_name,
476 None,
477 );
478
479 if !is_method
482 && let Some((_, ident)) = node.scope_and_ident_by_field(unit, LangRust::field_name)
483 && let Some(sym) = scopes.lookup_symbol(ident.name, SymKindSet::from_kind(kind))
484 {
485 scopes.globals().insert(sym);
486 }
487 }
488
489 #[tracing::instrument(skip_all)]
492 fn visit_function_signature_item(
493 &mut self,
494 unit: &CompileUnit<'tcx>,
495 node: &HirNode<'tcx>,
496 scopes: &mut CollectorScopes<'tcx>,
497 namespace: &'tcx Scope<'tcx>,
498 parent: Option<&Symbol>,
499 ) {
500 let kind = if is_method_context(parent) {
502 SymKind::Method
503 } else {
504 SymKind::Function
505 };
506 self.visit_scoped_named(
507 unit,
508 node,
509 scopes,
510 namespace,
511 parent,
512 kind,
513 LangRust::field_name,
514 None,
515 );
516 }
517
518 #[tracing::instrument(skip_all)]
521 fn visit_struct_item(
522 &mut self,
523 unit: &CompileUnit<'tcx>,
524 node: &HirNode<'tcx>,
525 scopes: &mut CollectorScopes<'tcx>,
526 namespace: &'tcx Scope<'tcx>,
527 parent: Option<&Symbol>,
528 ) {
529 self.visit_scoped_named(
530 unit,
531 node,
532 scopes,
533 namespace,
534 parent,
535 SymKind::Struct,
536 LangRust::field_name,
537 Some(Box::new(|node, scopes| {
538 let _ = scopes.lookup_or_insert("self", node, SymKind::TypeAlias);
539 let _ = scopes.lookup_or_insert("Self", node, SymKind::TypeAlias);
540 })),
541 );
542
543 if let Some((_, ident)) = node.scope_and_ident_by_field(unit, LangRust::field_name)
545 && let Some(sym) =
546 scopes.lookup_symbol(ident.name, SymKindSet::from_kind(SymKind::Struct))
547 {
548 scopes.globals().insert(sym);
549 }
550 }
551
552 #[tracing::instrument(skip_all)]
555 fn visit_enum_item(
556 &mut self,
557 unit: &CompileUnit<'tcx>,
558 node: &HirNode<'tcx>,
559 scopes: &mut CollectorScopes<'tcx>,
560 namespace: &'tcx Scope<'tcx>,
561 parent: Option<&Symbol>,
562 ) {
563 self.visit_scoped_named(
564 unit,
565 node,
566 scopes,
567 namespace,
568 parent,
569 SymKind::Enum,
570 LangRust::field_name,
571 None,
572 );
573
574 if let Some((_, ident)) = node.scope_and_ident_by_field(unit, LangRust::field_name)
576 && let Some(sym) =
577 scopes.lookup_symbol(ident.name, SymKindSet::from_kind(SymKind::Enum))
578 {
579 scopes.globals().insert(sym);
580 }
581 }
582
583 #[tracing::instrument(skip_all)]
586 fn visit_trait_item(
587 &mut self,
588 unit: &CompileUnit<'tcx>,
589 node: &HirNode<'tcx>,
590 scopes: &mut CollectorScopes<'tcx>,
591 namespace: &'tcx Scope<'tcx>,
592 parent: Option<&Symbol>,
593 ) {
594 self.visit_scoped_named(
595 unit,
596 node,
597 scopes,
598 namespace,
599 parent,
600 SymKind::Trait,
601 LangRust::field_name,
602 Some(Box::new(|node, scopes| {
603 let _ = scopes.lookup_or_insert("self", node, SymKind::TypeAlias);
604 let _ = scopes.lookup_or_insert("Self", node, SymKind::TypeAlias);
605 })),
606 );
607
608 if let Some((_, ident)) = node.scope_and_ident_by_field(unit, LangRust::field_name)
610 && let Some(sym) =
611 scopes.lookup_symbol(ident.name, SymKindSet::from_kind(SymKind::Trait))
612 {
613 scopes.globals().insert(sym);
614 }
615 }
616
617 #[tracing::instrument(skip_all)]
620 fn visit_impl_item(
621 &mut self,
622 unit: &CompileUnit<'tcx>,
623 node: &HirNode<'tcx>,
624 scopes: &mut CollectorScopes<'tcx>,
625 _namespace: &'tcx Scope<'tcx>,
626 _parent: Option<&Symbol>,
627 ) {
628 if let Some(ti) = node.ident_by_field(unit, LangRust::field_trait) {
630 let symbol = scopes
632 .lookup_symbol(ti.name, SymKindSet::from_kind(SymKind::Trait))
633 .or_else(|| {
635 scopes.lookup_symbol(ti.name, SymKindSet::from_kind(SymKind::UnresolvedType))
636 })
637 .or_else(|| scopes.lookup_or_insert(ti.name, node, SymKind::UnresolvedType));
639 if let Some(symbol) = symbol {
640 ti.set_symbol(symbol);
641 }
642 }
643
644 if let Some((sn, ti)) = node.scope_and_ident_by_field(unit, LangRust::field_type)
645 && let Some(symbol) =
646 self.lookup_or_convert(unit, scopes, ti.name, node, SymKind::UnresolvedType)
647 {
648 tracing::trace!(
649 "visiting impl for type '{}', {:?}",
650 ti.name,
651 symbol.format(Some(scopes.interner())),
652 );
653 ti.set_symbol(symbol);
654 self.visit_with_scope(unit, node, scopes, symbol, sn, ti, None);
655 }
656 }
657
658 #[tracing::instrument(skip_all)]
661 fn visit_macro_definition(
662 &mut self,
663 unit: &CompileUnit<'tcx>,
664 node: &HirNode<'tcx>,
665 scopes: &mut CollectorScopes<'tcx>,
666 namespace: &'tcx Scope<'tcx>,
667 parent: Option<&Symbol>,
668 ) {
669 self.visit_scoped_named(
670 unit,
671 node,
672 scopes,
673 namespace,
674 parent,
675 SymKind::Macro,
676 LangRust::field_name,
677 None,
678 );
679 }
680
681 #[tracing::instrument(skip_all)]
684 fn visit_const_item(
685 &mut self,
686 unit: &CompileUnit<'tcx>,
687 node: &HirNode<'tcx>,
688 scopes: &mut CollectorScopes<'tcx>,
689 namespace: &'tcx Scope<'tcx>,
690 _parent: Option<&Symbol>,
691 ) {
692 if let Some(symbol) =
693 self.declare_symbol(unit, node, scopes, SymKind::Const, LangRust::field_name)
694 {
695 self.visit_children(unit, node, scopes, namespace, Some(symbol));
696 }
697 }
698
699 #[tracing::instrument(skip_all)]
702 fn visit_static_item(
703 &mut self,
704 unit: &CompileUnit<'tcx>,
705 node: &HirNode<'tcx>,
706 scopes: &mut CollectorScopes<'tcx>,
707 namespace: &'tcx Scope<'tcx>,
708 _parent: Option<&Symbol>,
709 ) {
710 if let Some(symbol) =
711 self.declare_symbol(unit, node, scopes, SymKind::Static, LangRust::field_name)
712 {
713 self.visit_children(unit, node, scopes, namespace, Some(symbol));
714 }
715 }
716
717 #[tracing::instrument(skip_all)]
720 fn visit_type_item(
721 &mut self,
722 unit: &CompileUnit<'tcx>,
723 node: &HirNode<'tcx>,
724 scopes: &mut CollectorScopes<'tcx>,
725 namespace: &'tcx Scope<'tcx>,
726 _parent: Option<&Symbol>,
727 ) {
728 if let Some(symbol) =
729 self.declare_symbol(unit, node, scopes, SymKind::TypeAlias, LangRust::field_name)
730 {
731 self.visit_children(unit, node, scopes, namespace, Some(symbol));
732 }
733 }
734
735 #[tracing::instrument(skip_all)]
738 fn visit_type_parameter(
739 &mut self,
740 unit: &CompileUnit<'tcx>,
741 node: &HirNode<'tcx>,
742 scopes: &mut CollectorScopes<'tcx>,
743 namespace: &'tcx Scope<'tcx>,
744 parent: Option<&Symbol>,
745 ) {
746 let _ = self.declare_symbol(
747 unit,
748 node,
749 scopes,
750 SymKind::TypeParameter,
751 LangRust::field_name,
752 );
753 self.visit_children(unit, node, scopes, namespace, parent);
754 }
755
756 #[tracing::instrument(skip_all)]
759 fn visit_const_parameter(
760 &mut self,
761 unit: &CompileUnit<'tcx>,
762 node: &HirNode<'tcx>,
763 scopes: &mut CollectorScopes<'tcx>,
764 namespace: &'tcx Scope<'tcx>,
765 parent: Option<&Symbol>,
766 ) {
767 let _ = self.declare_symbol(unit, node, scopes, SymKind::Const, LangRust::field_name);
768 self.visit_children(unit, node, scopes, namespace, parent);
769 }
770
771 #[tracing::instrument(skip_all)]
774 fn visit_associated_type(
775 &mut self,
776 unit: &CompileUnit<'tcx>,
777 node: &HirNode<'tcx>,
778 scopes: &mut CollectorScopes<'tcx>,
779 namespace: &'tcx Scope<'tcx>,
780 parent: Option<&Symbol>,
781 ) {
782 let _ = self.declare_symbol(unit, node, scopes, SymKind::TypeAlias, LangRust::field_name);
783 self.visit_children(unit, node, scopes, namespace, parent);
784 }
785
786 #[tracing::instrument(skip_all)]
789 fn visit_where_predicate(
790 &mut self,
791 unit: &CompileUnit<'tcx>,
792 node: &HirNode<'tcx>,
793 scopes: &mut CollectorScopes<'tcx>,
794 namespace: &'tcx Scope<'tcx>,
795 parent: Option<&Symbol>,
796 ) {
797 self.visit_children(unit, node, scopes, namespace, parent);
799 }
800
801 #[tracing::instrument(skip_all)]
804 fn visit_array_type(
805 &mut self,
806 unit: &CompileUnit<'tcx>,
807 node: &HirNode<'tcx>,
808 scopes: &mut CollectorScopes<'tcx>,
809 namespace: &'tcx Scope<'tcx>,
810 parent: Option<&Symbol>,
811 ) {
812 let _ = self.declare_symbol(
813 unit,
814 node,
815 scopes,
816 SymKind::CompositeType,
817 LangRust::field_name,
818 );
819 self.visit_children(unit, node, scopes, namespace, parent);
820 }
821
822 #[tracing::instrument(skip_all)]
825 fn visit_tuple_type(
826 &mut self,
827 unit: &CompileUnit<'tcx>,
828 node: &HirNode<'tcx>,
829 scopes: &mut CollectorScopes<'tcx>,
830 namespace: &'tcx Scope<'tcx>,
831 parent: Option<&Symbol>,
832 ) {
833 self.visit_array_type(unit, node, scopes, namespace, parent);
834 }
835
836 #[tracing::instrument(skip_all)]
839 fn visit_primitive_type(
840 &mut self,
841 unit: &CompileUnit<'tcx>,
842 node: &HirNode<'tcx>,
843 scopes: &mut CollectorScopes<'tcx>,
844 namespace: &'tcx Scope<'tcx>,
845 parent: Option<&Symbol>,
846 ) {
847 self.visit_children(unit, node, scopes, namespace, parent);
848 }
849
850 fn visit_abstract_type(
853 &mut self,
854 unit: &CompileUnit<'tcx>,
855 node: &HirNode<'tcx>,
856 scopes: &mut CollectorScopes<'tcx>,
857 namespace: &'tcx Scope<'tcx>,
858 parent: Option<&Symbol>,
859 ) {
860 self.visit_children(unit, node, scopes, namespace, parent);
861 }
862
863 fn visit_field_declaration(
866 &mut self,
867 unit: &CompileUnit<'tcx>,
868 node: &HirNode<'tcx>,
869 scopes: &mut CollectorScopes<'tcx>,
870 namespace: &'tcx Scope<'tcx>,
871 parent: Option<&Symbol>,
872 ) {
873 let _ = self.declare_symbol(unit, node, scopes, SymKind::Field, LangRust::field_name);
874 self.visit_children(unit, node, scopes, namespace, parent);
875 }
876
877 fn visit_enum_variant(
880 &mut self,
881 unit: &CompileUnit<'tcx>,
882 node: &HirNode<'tcx>,
883 scopes: &mut CollectorScopes<'tcx>,
884 namespace: &'tcx Scope<'tcx>,
885 parent: Option<&Symbol>,
886 ) {
887 let parent_enum = parent.or_else(|| namespace.opt_symbol());
889
890 self.visit_scoped_named(
891 unit,
892 node,
893 scopes,
894 namespace,
895 parent,
896 SymKind::EnumVariant,
897 LangRust::field_name,
898 None,
899 );
900
901 if let Some(enum_sym) = parent_enum
903 && let Some(ident) = node.ident_by_field(unit, LangRust::field_name)
904 && let Some(variant_sym) =
905 scopes.lookup_symbol(ident.name, SymKindSet::from_kind(SymKind::EnumVariant))
906 {
907 variant_sym.set_type_of(enum_sym.id);
908 }
909 }
910
911 fn visit_parameter(
914 &mut self,
915 unit: &CompileUnit<'tcx>,
916 node: &HirNode<'tcx>,
917 scopes: &mut CollectorScopes<'tcx>,
918 namespace: &'tcx Scope<'tcx>,
919 _parent: Option<&Symbol>,
920 ) {
921 if let Some(ident) = node.ident_by_field(unit, LangRust::field_pattern)
923 && ident.name == "self"
924 && let Some(symbol) =
925 scopes.lookup_symbol(ident.name, SymKindSet::from_kind(SymKind::Field))
926 {
927 ident.set_symbol(symbol);
929 self.visit_children(unit, node, scopes, namespace, Some(symbol));
930 return;
931 }
932
933 if let Some(pattern) = node.child_by_field(unit, LangRust::field_pattern) {
935 if pattern.as_ident().is_some() {
937 if let Some(symbol) = self.declare_symbol(
939 unit,
940 node,
941 scopes,
942 SymKind::Variable,
943 LangRust::field_pattern,
944 ) {
945 self.visit_children(unit, node, scopes, namespace, Some(symbol));
946 return;
947 }
948 } else {
949 let _ =
951 Self::collect_pattern_identifiers(unit, &pattern, scopes, SymKind::Variable);
952 self.visit_children(unit, node, scopes, namespace, None);
953 return;
954 }
955 }
956
957 if let Some(symbol) = self.declare_symbol(
959 unit,
960 node,
961 scopes,
962 SymKind::Variable,
963 LangRust::field_pattern,
964 ) {
965 self.visit_children(unit, node, scopes, namespace, Some(symbol));
966 }
967 }
968
969 fn visit_closure_expression(
972 &mut self,
973 unit: &CompileUnit<'tcx>,
974 node: &HirNode<'tcx>,
975 scopes: &mut CollectorScopes<'tcx>,
976 namespace: &'tcx Scope<'tcx>,
977 parent: Option<&Symbol>,
978 ) {
979 if let Some(sn) = node.as_scope() {
981 let scope = unit.cc.alloc_scope(node.id());
982 sn.set_scope(scope);
983
984 scope.add_parent(namespace);
986
987 scopes.push_scope(scope);
988
989 if let Some(params) = node.child_by_field(unit, LangRust::field_parameters) {
991 let _ = Self::collect_pattern_identifiers(unit, ¶ms, scopes, SymKind::Variable);
992 }
993
994 self.visit_children(unit, node, scopes, scope, parent);
995 scopes.pop_scope();
996 }
997 }
998
999 fn visit_let_declaration(
1002 &mut self,
1003 unit: &CompileUnit<'tcx>,
1004 node: &HirNode<'tcx>,
1005 scopes: &mut CollectorScopes<'tcx>,
1006 namespace: &'tcx Scope<'tcx>,
1007 parent: Option<&Symbol>,
1008 ) {
1009 let is_closure = node
1011 .child_by_field(unit, LangRust::field_value)
1012 .map(|v| v.kind_id() == LangRust::closure_expression)
1013 .unwrap_or(false);
1014
1015 let kind = if is_closure {
1016 SymKind::Closure
1017 } else {
1018 SymKind::Variable
1019 };
1020
1021 let let_syms = if let Some(pattern) = node.child_by_field(unit, LangRust::field_pattern) {
1023 Self::collect_pattern_identifiers(unit, &pattern, scopes, kind)
1024 } else {
1025 vec![]
1026 };
1027
1028 if is_closure && !let_syms.is_empty() {
1031 self.visit_children(unit, node, scopes, namespace, Some(let_syms[0]));
1032 } else {
1033 self.visit_children(unit, node, scopes, namespace, parent);
1034 }
1035 }
1036}
1037
1038pub fn collect_symbols<'tcx>(
1039 unit: CompileUnit<'tcx>,
1040 node: &HirNode<'tcx>,
1041 scope_stack: ScopeStack<'tcx>,
1042 _config: &ResolverOption,
1043) -> &'tcx Scope<'tcx> {
1044 let cc = unit.cc;
1045 let arena = cc.arena();
1046 let unit_globals_val = Scope::new(HirId(unit.index));
1047 let scope_id = unit_globals_val.id().0;
1048 let unit_globals = arena.alloc_with_id(scope_id, unit_globals_val);
1049 let mut scopes = CollectorScopes::new(cc, unit.index, scope_stack, unit_globals);
1050
1051 let mut visit = CollectorVisitor::new();
1052 visit.visit_node(&unit, node, &mut scopes, unit_globals, None);
1053
1054 unit_globals
1055}