1#![allow(clippy::collapsible_if, clippy::needless_return)]
2
3use llmcc_core::context::CompileUnit;
4use llmcc_core::ir::{HirNode, HirScope};
5use llmcc_core::scope::Scope;
6use llmcc_core::symbol::{
7 SYM_KIND_ALL, SYM_KIND_CALLABLE, SYM_KIND_IMPL_TARGETS, SYM_KIND_TYPES, SymKind, SymKindSet,
8 Symbol,
9};
10use llmcc_resolver::{BinderScopes, ResolverOption};
11
12use crate::infer::infer_type;
13use crate::pattern::bind_pattern_types;
14use crate::token::AstVisitorRust;
15use crate::token::LangRust;
16
17type ScopeEnterFn<'tcx> =
18 Box<dyn FnOnce(&CompileUnit<'tcx>, &'tcx HirScope<'tcx>, &mut BinderScopes<'tcx>) + 'tcx>;
19
20#[derive(Debug)]
22pub struct BinderVisitor<'tcx> {
23 #[allow(dead_code)]
24 config: ResolverOption,
25 phantom: std::marker::PhantomData<&'tcx ()>,
26}
27
28impl<'tcx> BinderVisitor<'tcx> {
29 fn new(config: ResolverOption) -> Self {
30 Self {
31 config,
32 phantom: std::marker::PhantomData,
33 }
34 }
35
36 #[tracing::instrument(skip_all)]
37 #[allow(clippy::too_many_arguments)]
38 fn visit_scoped_named(
40 &mut self,
41 unit: &CompileUnit<'tcx>,
42 node: &HirNode<'tcx>,
43 sn: &'tcx HirScope<'tcx>,
44 scopes: &mut BinderScopes<'tcx>,
45 namespace: &'tcx Scope<'tcx>,
46 parent: Option<&Symbol>,
47 on_scope_enter: Option<ScopeEnterFn<'tcx>>,
48 ) {
49 tracing::trace!(
50 "visiting scoped named node kind: {:?}, namespace id: {:?}, parent: {:?}",
51 node.kind_id(),
52 namespace.id(),
53 parent.map(|p| p.format(Some(unit.interner()))),
54 );
55 let depth = scopes.scope_depth();
56
57 if let Some(_vis_modifier) = node.child_by_kind(unit, LangRust::visibility_modifier)
59 && let Some(sym) = sn.opt_symbol()
60 {
61 sym.set_is_global(true);
62 scopes.globals().insert(sym);
63 }
64
65 let child_parent = sn.opt_symbol().or(parent);
66
67 scopes.push_scope_node(sn);
69
70 if let Some(scope_enter) = on_scope_enter {
71 scope_enter(unit, sn, scopes);
72 }
73 self.visit_children(unit, node, scopes, scopes.top(), child_parent);
74 scopes.pop_until(depth);
75 }
76}
77
78impl<'tcx> AstVisitorRust<'tcx, BinderScopes<'tcx>> for BinderVisitor<'tcx> {
79 fn visit_source_file(
83 &mut self,
84 unit: &CompileUnit<'tcx>,
85 node: &HirNode<'tcx>,
86 scopes: &mut BinderScopes<'tcx>,
87 _namespace: &'tcx Scope<'tcx>,
88 _parent: Option<&Symbol>,
89 ) {
90 let file_path = unit.file_path().unwrap();
91 let depth = scopes.scope_depth();
92 let meta = unit.unit_meta();
93
94 tracing::trace!("binding source_file: {}", file_path);
95 if let Some(ref crate_name) = meta.package_name
96 && let Some(symbol) =
97 scopes.lookup_symbol(crate_name, SymKindSet::from_kind(SymKind::Crate))
98 && let Some(scope_id) = symbol.opt_scope()
99 {
100 tracing::trace!("pushing crate scope {:?}", scope_id);
101 scopes.push_scope(scope_id);
102 }
103
104 if let Some(ref module_name) = meta.module_name
105 && let Some(symbol) =
106 scopes.lookup_symbol(module_name, SymKindSet::from_kind(SymKind::Module))
107 && let Some(scope_id) = symbol.opt_scope()
108 {
109 tracing::trace!("pushing module scope {:?}", scope_id);
110 scopes.push_scope(scope_id);
111 }
112
113 if let Some(ref file_name) = meta.file_name
114 && let Some(file_sym) =
115 scopes.lookup_symbol(file_name, SymKindSet::from_kind(SymKind::File))
116 && let Some(scope_id) = file_sym.opt_scope()
117 {
118 tracing::trace!("pushing file scope {} {:?}", file_path, scope_id);
119 scopes.push_scope(scope_id);
120
121 let file_scope = unit.get_scope(scope_id);
122 self.visit_children(unit, node, scopes, file_scope, Some(file_sym));
123 scopes.pop_until(depth);
124 }
125 }
126
127 #[tracing::instrument(skip_all)]
129 fn visit_identifier(
130 &mut self,
131 _unit: &CompileUnit<'tcx>,
132 node: &HirNode<'tcx>,
133 scopes: &mut BinderScopes<'tcx>,
134 _namespace: &'tcx Scope<'tcx>,
135 _parent: Option<&Symbol>,
136 ) {
137 let ident = node.as_ident().unwrap();
138 if let Some(existing) = ident.opt_symbol()
139 && existing.kind().is_resolved()
140 {
141 return;
142 }
143
144 if let Some(symbol) = scopes.lookup_symbol(ident.name, SYM_KIND_ALL) {
145 ident.set_symbol(symbol);
146 }
147 }
148
149 #[tracing::instrument(skip_all)]
151 fn visit_type_identifier(
152 &mut self,
153 _unit: &CompileUnit<'tcx>,
154 node: &HirNode<'tcx>,
155 scopes: &mut BinderScopes<'tcx>,
156 _namespace: &'tcx Scope<'tcx>,
157 _parent: Option<&Symbol>,
158 ) {
159 let ident = node.as_ident().unwrap();
160 if let Some(existing) = ident.opt_symbol()
161 && existing.kind().is_resolved()
162 {
163 return;
164 }
165
166 if let Some(symbol) = scopes.lookup_symbol(ident.name, SYM_KIND_TYPES) {
167 ident.set_symbol(symbol);
168 }
169 }
170
171 #[tracing::instrument(skip_all)]
173 fn visit_primitive_type(
174 &mut self,
175 _unit: &CompileUnit<'tcx>,
176 node: &HirNode<'tcx>,
177 scopes: &mut BinderScopes<'tcx>,
178 _namespace: &'tcx Scope<'tcx>,
179 _parent: Option<&Symbol>,
180 ) {
181 let ident = node.as_ident().unwrap();
182 if let Some(symbol) =
183 scopes.lookup_global(ident.name, SymKindSet::from_kind(SymKind::Primitive))
184 {
185 ident.set_symbol(symbol);
186 }
187 }
188
189 #[tracing::instrument(skip_all)]
192 fn visit_type_parameter(
193 &mut self,
194 unit: &CompileUnit<'tcx>,
195 node: &HirNode<'tcx>,
196 scopes: &mut BinderScopes<'tcx>,
197 namespace: &'tcx Scope<'tcx>,
198 parent: Option<&Symbol>,
199 ) {
200 self.visit_children(unit, node, scopes, namespace, parent);
201
202 if let Some(type_param_sym) = node.ident_symbol_by_field(unit, LangRust::field_name) {
204 if let Some(bounds_node) = node.child_by_field(unit, LangRust::field_bounds) {
206 if let Some(first_bound) = infer_type(unit, scopes, &bounds_node) {
208 type_param_sym.set_type_of(first_bound.id());
209 tracing::trace!(
210 "type parameter '{}' has bound '{}'",
211 type_param_sym.format(Some(unit.interner())),
212 first_bound.format(Some(unit.interner())),
213 );
214 return;
215 }
216 }
217 if let Some(default_node) = node.child_by_field(unit, LangRust::field_default_type) {
219 if let Some(default_type) = infer_type(unit, scopes, &default_node) {
220 type_param_sym.set_type_of(default_type.id());
221 tracing::trace!(
222 "type parameter '{}' has default '{}'",
223 type_param_sym.format(Some(unit.interner())),
224 default_type.format(Some(unit.interner())),
225 );
226 }
227 }
228 }
229 }
230
231 fn visit_block(
233 &mut self,
234 unit: &CompileUnit<'tcx>,
235 node: &HirNode<'tcx>,
236 scopes: &mut BinderScopes<'tcx>,
237 namespace: &'tcx Scope<'tcx>,
238 parent: Option<&Symbol>,
239 ) {
240 let sn = node.as_scope().unwrap();
241 scopes.push_scope(sn.scope().id());
242 self.visit_children(unit, node, scopes, namespace, parent);
243 scopes.pop_scope();
244 }
245
246 #[tracing::instrument(skip_all)]
248 fn visit_mod_item(
249 &mut self,
250 unit: &CompileUnit<'tcx>,
251 node: &HirNode<'tcx>,
252 scopes: &mut BinderScopes<'tcx>,
253 namespace: &'tcx Scope<'tcx>,
254 parent: Option<&Symbol>,
255 ) {
256 if node.child_by_field(unit, LangRust::field_body).is_none() {
257 return;
258 }
259
260 let sn = node.as_scope().unwrap();
261 self.visit_scoped_named(unit, node, sn, scopes, namespace, parent, None);
262 }
263
264 #[tracing::instrument(skip_all)]
266 fn visit_function_signature_item(
267 &mut self,
268 unit: &CompileUnit<'tcx>,
269 node: &HirNode<'tcx>,
270 scopes: &mut BinderScopes<'tcx>,
271 namespace: &'tcx Scope<'tcx>,
272 parent: Option<&Symbol>,
273 ) {
274 self.visit_function_item(unit, node, scopes, namespace, parent);
275 }
276
277 #[tracing::instrument(skip_all)]
279 fn visit_function_item(
280 &mut self,
281 unit: &CompileUnit<'tcx>,
282 node: &HirNode<'tcx>,
283 scopes: &mut BinderScopes<'tcx>,
284 namespace: &'tcx Scope<'tcx>,
285 parent: Option<&Symbol>,
286 ) {
287 let sn = node.as_scope().unwrap();
288 self.visit_scoped_named(unit, node, sn, scopes, namespace, parent, None);
289
290 let Some(fn_sym) = sn.opt_symbol() else {
291 return;
292 };
293
294 if let Some(return_type) = node.ident_symbol_by_field(unit, LangRust::field_return_type) {
295 tracing::trace!(
296 "binding function return type '{}' to '{}'",
297 return_type.format(Some(unit.interner())),
298 fn_sym.format(Some(unit.interner()))
299 );
300 fn_sym.set_type_of(return_type.id());
301 }
302
303 if let Some(return_type_node) = node.child_by_field(unit, LangRust::field_return_type) {
305 extract_nested_types(unit, scopes, &return_type_node, fn_sym);
306 }
307
308 if unit.resolve_name(fn_sym.name) == "main" {
309 fn_sym.set_is_global(true);
310 scopes.globals().insert(fn_sym);
311 }
312 }
313
314 #[tracing::instrument(skip_all)]
316 fn visit_field_identifier(
317 &mut self,
318 unit: &CompileUnit<'tcx>,
319 node: &HirNode<'tcx>,
320 scopes: &mut BinderScopes<'tcx>,
321 namespace: &'tcx Scope<'tcx>,
322 parent: Option<&Symbol>,
323 ) {
324 self.visit_identifier(unit, node, scopes, namespace, parent);
325 }
326
327 #[tracing::instrument(skip_all)]
329 fn visit_struct_item(
330 &mut self,
331 unit: &CompileUnit<'tcx>,
332 node: &HirNode<'tcx>,
333 scopes: &mut BinderScopes<'tcx>,
334 namespace: &'tcx Scope<'tcx>,
335 parent: Option<&Symbol>,
336 ) {
337 let sn = node.as_scope().unwrap();
338 self.visit_scoped_named(
339 unit,
340 node,
341 sn,
342 scopes,
343 namespace,
344 parent,
345 Some(Box::new(|unit, sn, scopes| {
346 for key in ["Self", "self"] {
347 if let Some(self_sym) =
348 scopes.lookup_symbol(key, SymKindSet::from_kind(SymKind::TypeAlias))
349 && let Some(struct_sym) = sn.opt_symbol()
350 {
351 tracing::trace!(
352 "binding '{}' to struct type '{}'",
353 key,
354 struct_sym.format(Some(unit.interner())),
355 );
356 self_sym.set_type_of(struct_sym.id());
357 if let Some(struct_scope) = struct_sym.opt_scope() {
359 self_sym.set_scope(struct_scope);
360 }
361 }
362 }
363 })),
364 );
365 }
366
367 #[tracing::instrument(skip_all)]
370 fn visit_trait_item(
371 &mut self,
372 unit: &CompileUnit<'tcx>,
373 node: &HirNode<'tcx>,
374 scopes: &mut BinderScopes<'tcx>,
375 namespace: &'tcx Scope<'tcx>,
376 parent: Option<&Symbol>,
377 ) {
378 let sn = node.as_scope().unwrap();
379 self.visit_scoped_named(
380 unit,
381 node,
382 sn,
383 scopes,
384 namespace,
385 parent,
386 Some(Box::new(|unit, sn, scopes| {
387 for key in ["Self", "self"] {
388 if let Some(self_sym) =
389 scopes.lookup_symbol(key, SymKindSet::from_kind(SymKind::TypeAlias))
390 && let Some(trait_sym) = sn.opt_symbol()
391 {
392 tracing::trace!(
393 "binding '{}' to trait type '{}'",
394 key,
395 trait_sym.format(Some(unit.interner())),
396 );
397 self_sym.set_type_of(trait_sym.id());
398 if let Some(trait_scope) = trait_sym.opt_scope() {
400 self_sym.set_scope(trait_scope);
401 }
402 }
403 }
404 })),
405 );
406 }
407
408 #[tracing::instrument(skip_all)]
410 fn visit_field_declaration(
411 &mut self,
412 unit: &CompileUnit<'tcx>,
413 node: &HirNode<'tcx>,
414 scopes: &mut BinderScopes<'tcx>,
415 namespace: &'tcx Scope<'tcx>,
416 parent: Option<&Symbol>,
417 ) {
418 self.visit_children(unit, node, scopes, namespace, parent);
419
420 if let Some(field_sym) = node.ident_symbol_by_field(unit, LangRust::field_name) {
421 if let Some(struct_sym) = namespace.opt_symbol() {
422 field_sym.set_field_of(struct_sym.id());
423 }
424
425 if let Some(type_node) = node.child_by_field(unit, LangRust::field_type)
426 && let Some(field_type) = infer_type(unit, scopes, &type_node)
427 {
428 field_sym.set_type_of(field_type.id());
429 if let Some(struct_sym) = namespace.opt_symbol() {
430 struct_sym.add_nested_type(field_type.id());
431 }
432 extract_nested_types(unit, scopes, &type_node, field_sym);
436 }
437 }
438 }
439
440 #[tracing::instrument(skip_all)]
442 fn visit_impl_item(
443 &mut self,
444 unit: &CompileUnit<'tcx>,
445 node: &HirNode<'tcx>,
446 scopes: &mut BinderScopes<'tcx>,
447 _namespace: &'tcx Scope<'tcx>,
448 _parent: Option<&Symbol>,
449 ) {
450 let target_ident = node.ident_by_field(unit, LangRust::field_type);
451 if let Some(target_ident) = target_ident
452 && let Some(target_sym) = target_ident.opt_symbol()
453 {
454 let target_resolved = scopes.lookup_symbol(target_ident.name, SYM_KIND_IMPL_TARGETS);
456
457 if target_sym.kind() == SymKind::UnresolvedType {
458 if let Some(resolved) = target_resolved
460 && resolved.id() != target_sym.id()
461 && !matches!(resolved.kind(), SymKind::UnresolvedType)
462 {
463 tracing::trace!(
464 "resolving impl target type '{}' to '{}'",
465 target_sym.format(Some(unit.interner())),
466 resolved.format(Some(unit.interner())),
467 );
468 target_sym.set_type_of(resolved.id());
470 target_sym.set_kind(resolved.kind());
471 target_sym.set_is_global(resolved.is_global());
472
473 if let Some(resolved_scope) = resolved.opt_scope()
474 && let Some(target_scoped) = target_sym.opt_scope()
475 {
476 tracing::trace!(
478 "connecting impl target '{}' and resolved type '{}'",
479 resolved_scope,
480 target_scoped
481 );
482 let target_scope = unit.get_scope(target_scoped);
483 let resolved_scope = unit.get_scope(resolved_scope);
484 target_scope.add_parent(resolved_scope);
485 resolved_scope.add_parent(target_scope);
486 }
487 }
488 }
489
490 if let Some(trait_node) = node.child_by_field(unit, LangRust::field_trait)
491 && let Some(trait_ident) = trait_node.find_ident(unit)
492 {
493 let trait_sym =
497 scopes.lookup_symbol(trait_ident.name, SymKindSet::from_kind(SymKind::Trait));
498
499 if let Some(trait_sym) = trait_sym {
500 trait_ident.set_symbol(trait_sym);
502
503 if let Some(target_resolved) = target_resolved
505 && let Some(target_scope) = target_resolved.opt_scope()
506 && let Some(trait_scope) = trait_sym.opt_scope()
507 {
508 let target_scope = unit.get_scope(target_scope);
509 let trait_scope = unit.get_scope(trait_scope);
510 tracing::trace!(
511 "adding impl realtion: target '{}' implements trait '{}'",
512 target_resolved.format(Some(unit.interner())),
513 trait_sym.format(Some(unit.interner())),
514 );
515 target_scope.add_parent(trait_scope);
516 }
517 }
518
519 if let Some(type_args) =
523 trait_node.child_by_field(unit, LangRust::field_type_arguments)
524 {
525 for &child_id in type_args.child_ids() {
526 let child = unit.hir_node(child_id);
527 if child.is_trivia() || child.kind_id() == LangRust::lifetime {
528 continue;
529 }
530 if let Some(type_arg_sym) = infer_type(unit, scopes, &child) {
531 if type_arg_sym.kind().is_defined_type() {
532 target_sym.add_nested_type(type_arg_sym.id());
533 tracing::trace!(
534 "impl type arg: {} -> {}",
535 type_arg_sym.format(Some(unit.interner())),
536 target_sym.format(Some(unit.interner())),
537 );
538 }
539 }
540 }
541 }
542 }
543
544 let sn = node.as_scope().unwrap();
545 let target_scope = unit.get_scope(target_sym.opt_scope().unwrap());
546 self.visit_scoped_named(unit, node, sn, scopes, target_scope, Some(target_sym), None);
547 }
548 }
549
550 #[tracing::instrument(skip_all)]
554 fn visit_call_expression(
555 &mut self,
556 unit: &CompileUnit<'tcx>,
557 node: &HirNode<'tcx>,
558 scopes: &mut BinderScopes<'tcx>,
559 namespace: &'tcx Scope<'tcx>,
560 parent: Option<&Symbol>,
561 ) {
562 self.visit_children(unit, node, scopes, namespace, parent);
563
564 if let Some(func_node) = node.child_by_field(unit, LangRust::field_function)
567 && func_node.kind_id() == LangRust::identifier
568 && let Some(ident) = func_node.as_ident()
569 && ident.opt_symbol().is_none()
570 && let Some(symbol) = scopes.lookup_symbol(ident.name, SYM_KIND_CALLABLE)
571 {
572 ident.set_symbol(symbol);
573 }
574 }
575
576 #[tracing::instrument(skip_all)]
578 fn visit_enum_item(
579 &mut self,
580 unit: &CompileUnit<'tcx>,
581 node: &HirNode<'tcx>,
582 scopes: &mut BinderScopes<'tcx>,
583 namespace: &'tcx Scope<'tcx>,
584 parent: Option<&Symbol>,
585 ) {
586 let sn = node.as_scope().unwrap();
587 self.visit_scoped_named(unit, node, sn, scopes, namespace, parent, None);
588 }
589
590 fn visit_macro_definition(
592 &mut self,
593 unit: &CompileUnit<'tcx>,
594 node: &HirNode<'tcx>,
595 scopes: &mut BinderScopes<'tcx>,
596 namespace: &'tcx Scope<'tcx>,
597 parent: Option<&Symbol>,
598 ) {
599 let sn = node.as_scope().unwrap();
600 self.visit_scoped_named(unit, node, sn, scopes, namespace, parent, None);
601 }
602
603 fn visit_macro_invocation(
605 &mut self,
606 unit: &CompileUnit<'tcx>,
607 node: &HirNode<'tcx>,
608 scopes: &mut BinderScopes<'tcx>,
609 namespace: &'tcx Scope<'tcx>,
610 parent: Option<&Symbol>,
611 ) {
612 self.visit_children(unit, node, scopes, namespace, parent);
613 }
614
615 fn visit_generic_type(
616 &mut self,
617 unit: &CompileUnit<'tcx>,
618 node: &HirNode<'tcx>,
619 scopes: &mut BinderScopes<'tcx>,
620 namespace: &'tcx Scope<'tcx>,
621 parent: Option<&Symbol>,
622 ) {
623 self.visit_children(unit, node, scopes, namespace, parent);
624 }
625
626 fn visit_const_item(
628 &mut self,
629 unit: &CompileUnit<'tcx>,
630 node: &HirNode<'tcx>,
631 scopes: &mut BinderScopes<'tcx>,
632 namespace: &'tcx Scope<'tcx>,
633 parent: Option<&Symbol>,
634 ) {
635 self.visit_children(unit, node, scopes, namespace, parent);
636
637 if let Some(const_sym) = node.ident_symbol_by_field(unit, LangRust::field_name)
638 && let Some(const_ty) = node.child_by_field(unit, LangRust::field_type)
639 && let Some(ty) = infer_type(unit, scopes, &const_ty)
640 {
641 const_sym.set_type_of(ty.id());
642 }
643 }
644
645 fn visit_static_item(
647 &mut self,
648 unit: &CompileUnit<'tcx>,
649 node: &HirNode<'tcx>,
650 scopes: &mut BinderScopes<'tcx>,
651 namespace: &'tcx Scope<'tcx>,
652 parent: Option<&Symbol>,
653 ) {
654 self.visit_const_item(unit, node, scopes, namespace, parent);
655 }
656
657 #[tracing::instrument(skip_all)]
659 fn visit_type_item(
660 &mut self,
661 unit: &CompileUnit<'tcx>,
662 node: &HirNode<'tcx>,
663 scopes: &mut BinderScopes<'tcx>,
664 namespace: &'tcx Scope<'tcx>,
665 parent: Option<&Symbol>,
666 ) {
667 self.visit_children(unit, node, scopes, namespace, parent);
668
669 if let Some(name_sym) = node.ident_symbol(unit)
670 && let Some(type_sym) = node.ident_symbol_by_field(unit, LangRust::field_type)
671 {
672 name_sym.set_type_of(type_sym.id());
673 }
674 }
675
676 fn visit_array_type(
678 &mut self,
679 unit: &CompileUnit<'tcx>,
680 node: &HirNode<'tcx>,
681 scopes: &mut BinderScopes<'tcx>,
682 namespace: &'tcx Scope<'tcx>,
683 parent: Option<&Symbol>,
684 ) {
685 let sn = node.as_scope().unwrap();
686 self.visit_children(unit, node, scopes, namespace, parent);
687
688 if let Some(ident) = sn.opt_ident()
689 && let Some(symbol) =
690 scopes.lookup_symbol(ident.name, SymKindSet::from_kind(SymKind::CompositeType))
691 && symbol.nested_types().is_none()
692 {
693 if let Some(array_type_sym) = node.ident_symbol_by_field(unit, LangRust::field_element)
694 {
695 symbol.add_nested_type(array_type_sym.id());
696 }
697 }
698 }
699
700 fn visit_tuple_type(
702 &mut self,
703 unit: &CompileUnit<'tcx>,
704 node: &HirNode<'tcx>,
705 scopes: &mut BinderScopes<'tcx>,
706 namespace: &'tcx Scope<'tcx>,
707 parent: Option<&Symbol>,
708 ) {
709 let sn = node.as_scope().unwrap();
710 self.visit_children(unit, node, scopes, namespace, parent);
711
712 if let Some(tuple_ident) = sn.opt_ident()
713 && let Some(tuple_symbol) = scopes.lookup_symbol(
714 tuple_ident.name,
715 SymKindSet::from_kind(SymKind::CompositeType),
716 )
717 && tuple_symbol.nested_types().is_none()
718 {
719 for type_ident in node.collect_idents(unit) {
720 if let Some(type_sym) = type_ident.opt_symbol() {
721 tuple_symbol.add_nested_type(type_sym.id());
722 }
723 }
724 }
725 }
726
727 fn visit_abstract_type(
729 &mut self,
730 unit: &CompileUnit<'tcx>,
731 node: &HirNode<'tcx>,
732 scopes: &mut BinderScopes<'tcx>,
733 namespace: &'tcx Scope<'tcx>,
734 parent: Option<&Symbol>,
735 ) {
736 self.visit_children(unit, node, scopes, namespace, parent);
737 }
738
739 #[tracing::instrument(skip_all)]
741 fn visit_enum_variant(
742 &mut self,
743 unit: &CompileUnit<'tcx>,
744 node: &HirNode<'tcx>,
745 scopes: &mut BinderScopes<'tcx>,
746 namespace: &'tcx Scope<'tcx>,
747 parent: Option<&Symbol>,
748 ) {
749 self.visit_struct_item(unit, node, scopes, namespace, parent);
750 }
751
752 #[tracing::instrument(skip_all)]
754 fn visit_field_expression(
755 &mut self,
756 unit: &CompileUnit<'tcx>,
757 node: &HirNode<'tcx>,
758 scopes: &mut BinderScopes<'tcx>,
759 namespace: &'tcx Scope<'tcx>,
760 parent: Option<&Symbol>,
761 ) {
762 self.visit_children(unit, node, scopes, namespace, parent);
763
764 if let Some(value_sym) = node.ident_symbol_by_field(unit, LangRust::field_value)
765 && let Some(field_node) = node.child_by_field(unit, LangRust::field_field)
766 {
767 if field_node.kind_id() == LangRust::integer_literal {
769 if let Some(field_sym) = field_node.ident_symbol(unit) {
770 field_sym.set_field_of(value_sym.id());
771
772 if let Some(text) = field_node.as_text().map(|s| s.text()) {
774 if let Ok(index) = text.parse::<usize>() {
775 if let Some(value_type_id) = value_sym.type_of()
776 && let Some(value_type) = unit.opt_get_symbol(value_type_id)
777 && let Some(nested) = value_type.nested_types()
778 && index < nested.len()
779 {
780 field_sym.set_type_of(nested[index]);
781 tracing::trace!(
782 "tuple indexing: {} has type from nested_types[{}]",
783 field_sym.format(Some(unit.interner())),
784 index
785 );
786 }
787 }
788 }
789 }
790 }
791 else if let Some(field_ident) = field_node.find_ident(unit) {
793 if let Some(field_sym) = field_ident.opt_symbol() {
794 field_sym.set_field_of(value_sym.id());
795 }
796 }
797 }
798 }
799
800 fn visit_scoped_identifier(
806 &mut self,
807 unit: &CompileUnit<'tcx>,
808 node: &HirNode<'tcx>,
809 scopes: &mut BinderScopes<'tcx>,
810 namespace: &'tcx Scope<'tcx>,
811 parent: Option<&Symbol>,
812 ) {
813 self.visit_children(unit, node, scopes, namespace, parent);
814
815 let name_ident = node.ident_by_field(unit, LangRust::field_name);
816 let path_node = node.child_by_field(unit, LangRust::field_path);
817
818 if let Some(name_ident) = name_ident
819 && let Some(path_node) = path_node
820 {
821 let path_sym = if path_node.kind_id() == LangRust::scoped_identifier {
823 path_node
826 .ident_by_field(unit, LangRust::field_name)
827 .and_then(|i| i.opt_symbol())
828 } else if path_node.kind_id() == LangRust::identifier {
829 let path_ident = path_node.as_ident();
831 if let Some(ident) = path_ident {
832 if let Some(sym) = ident.opt_symbol() {
833 Some(sym)
834 } else {
835 let sym = scopes.lookup_symbol(ident.name, SymKindSet::empty());
837 if let Some(s) = sym {
838 ident.set_symbol(s);
839 }
840 sym
841 }
842 } else {
843 None
844 }
845 } else {
846 None
847 };
848
849 if let Some(path_sym) = path_sym {
850 if let Some(name_sym) = scopes.lookup_member_symbol(path_sym, name_ident.name, None)
851 {
852 name_ident.set_symbol(name_sym);
853 }
854 }
855 }
856 }
857
858 #[tracing::instrument(skip_all)]
860 fn visit_parameter(
861 &mut self,
862 unit: &CompileUnit<'tcx>,
863 node: &HirNode<'tcx>,
864 scopes: &mut BinderScopes<'tcx>,
865 namespace: &'tcx Scope<'tcx>,
866 parent: Option<&Symbol>,
867 ) {
868 self.visit_children(unit, node, scopes, namespace, parent);
869
870 if let Some(type_node) = node.child_by_field(unit, LangRust::field_type)
871 && let Some(pattern) = node.child_by_field_recursive(unit, LangRust::field_pattern)
872 {
873 if let Some(type_sym) = infer_type(unit, scopes, &type_node) {
874 bind_pattern_types(unit, scopes, &pattern, type_sym);
875 }
876 }
877 }
878
879 fn visit_self_param(
882 &mut self,
883 unit: &CompileUnit<'tcx>,
884 node: &HirNode<'tcx>,
885 scopes: &mut BinderScopes<'tcx>,
886 namespace: &'tcx Scope<'tcx>,
887 parent: Option<&Symbol>,
888 ) {
889 self.visit_children(unit, node, scopes, namespace, parent);
890
891 if let Some(self_sym) =
894 scopes.lookup_symbol("self", SymKindSet::from_kind(SymKind::TypeAlias))
895 {
896 for &child_id in node.child_ids() {
898 let child = unit.hir_node(child_id);
899 if let Some(ident) = child.as_ident() {
900 if ident.name == "self" {
901 ident.set_symbol(self_sym);
902 }
903 }
904 }
905 }
906 }
907
908 fn visit_scoped_type_identifier(
910 &mut self,
911 unit: &CompileUnit<'tcx>,
912 node: &HirNode<'tcx>,
913 scopes: &mut BinderScopes<'tcx>,
914 namespace: &'tcx Scope<'tcx>,
915 parent: Option<&Symbol>,
916 ) {
917 self.visit_scoped_identifier(unit, node, scopes, namespace, parent);
918 }
919
920 #[tracing::instrument(skip_all)]
922 fn visit_let_declaration(
923 &mut self,
924 unit: &CompileUnit<'tcx>,
925 node: &HirNode<'tcx>,
926 scopes: &mut BinderScopes<'tcx>,
927 namespace: &'tcx Scope<'tcx>,
928 parent: Option<&Symbol>,
929 ) {
930 self.visit_children(unit, node, scopes, namespace, parent);
931
932 if let Some(type_node) = node.child_by_field(unit, LangRust::field_type)
935 && let Some(pattern) = node.child_by_field_recursive(unit, LangRust::field_pattern)
936 {
937 if let Some(type_sym) = infer_type(unit, scopes, &type_node) {
938 bind_pattern_types(unit, scopes, &pattern, type_sym);
939 return;
940 }
941 if let Some(type_sym) = type_node.ident_symbol(unit) {
943 bind_pattern_types(unit, scopes, &pattern, type_sym);
944 return;
945 }
946 }
947
948 if let Some(value_node) = node.child_by_field(unit, LangRust::field_value)
950 && let Some(pattern) = node.child_by_field_recursive(unit, LangRust::field_pattern)
951 && let Some(type_sym) = infer_type(unit, scopes, &value_node)
952 {
953 bind_pattern_types(unit, scopes, &pattern, type_sym);
954 return;
955 }
956 }
957
958 fn visit_tuple_struct_pattern(
960 &mut self,
961 unit: &CompileUnit<'tcx>,
962 node: &HirNode<'tcx>,
963 scopes: &mut BinderScopes<'tcx>,
964 namespace: &'tcx Scope<'tcx>,
965 parent: Option<&Symbol>,
966 ) {
967 self.visit_children(unit, node, scopes, namespace, parent);
968
969 let type_node = node.child_by_field(unit, LangRust::field_type);
970 if let Some(type_node) = type_node
971 && let Some(type_ident) = type_node.find_ident(unit)
972 && let Some(type_sym) = type_ident.opt_symbol()
974 {
975 if type_sym.nested_types().is_some() {
976 for (i, child) in node.collect_idents(unit).into_iter().enumerate() {
977 if let Some(child_sym) = child.opt_symbol()
978 && let Some(nested_types) = type_sym.nested_types()
979 && i >= 2
980 && i < nested_types.len()
981 {
982 child_sym.set_type_of(nested_types[i]);
983 }
984 }
985 }
986 }
987 }
988
989 fn visit_struct_expression(
991 &mut self,
992 unit: &CompileUnit<'tcx>,
993 node: &HirNode<'tcx>,
994 scopes: &mut BinderScopes<'tcx>,
995 namespace: &'tcx Scope<'tcx>,
996 parent: Option<&Symbol>,
997 ) {
998 self.visit_children(unit, node, scopes, namespace, parent);
999 }
1000
1001 #[tracing::instrument(skip_all)]
1003 fn visit_match_expression(
1004 &mut self,
1005 unit: &CompileUnit<'tcx>,
1006 node: &HirNode<'tcx>,
1007 scopes: &mut BinderScopes<'tcx>,
1008 namespace: &'tcx Scope<'tcx>,
1009 parent: Option<&Symbol>,
1010 ) {
1011 self.visit_children(unit, node, scopes, namespace, parent);
1012 }
1013
1014 #[tracing::instrument(skip_all)]
1016 fn visit_match_block(
1017 &mut self,
1018 unit: &CompileUnit<'tcx>,
1019 node: &HirNode<'tcx>,
1020 scopes: &mut BinderScopes<'tcx>,
1021 namespace: &'tcx Scope<'tcx>,
1022 parent: Option<&Symbol>,
1023 ) {
1024 self.visit_block(unit, node, scopes, namespace, parent);
1025 }
1026}
1027
1028fn extract_nested_types<'tcx>(
1032 unit: &CompileUnit<'tcx>,
1033 scopes: &BinderScopes<'tcx>,
1034 type_node: &HirNode<'tcx>,
1035 target_sym: &Symbol,
1036) {
1037 if type_node.kind_id() == LangRust::generic_type {
1039 if let Some(type_args) = type_node.child_by_field(unit, LangRust::field_type_arguments) {
1041 for &child_id in type_args.child_ids() {
1042 let child = unit.hir_node(child_id);
1043 if child.is_trivia() || child.kind_id() == LangRust::lifetime {
1044 continue;
1045 }
1046 if let Some(type_arg_sym) = infer_type(unit, scopes, &child) {
1048 target_sym.add_nested_type(type_arg_sym.id());
1049 }
1050 extract_nested_types(unit, scopes, &child, target_sym);
1052 }
1053 }
1054 }
1055 else if type_node.kind_id() == LangRust::scoped_type_identifier {
1057 if let Some(type_args) = type_node.child_by_field(unit, LangRust::field_type_arguments) {
1058 for &child_id in type_args.child_ids() {
1059 let child = unit.hir_node(child_id);
1060 if child.is_trivia() || child.kind_id() == LangRust::lifetime {
1061 continue;
1062 }
1063 if let Some(type_arg_sym) = infer_type(unit, scopes, &child) {
1064 target_sym.add_nested_type(type_arg_sym.id());
1065 }
1066 extract_nested_types(unit, scopes, &child, target_sym);
1067 }
1068 }
1069 }
1070}
1071
1072pub fn bind_symbols<'tcx>(
1073 unit: CompileUnit<'tcx>,
1074 node: &HirNode<'tcx>,
1075 namespace: &'tcx Scope<'tcx>,
1076 config: &ResolverOption,
1077) {
1078 let mut scopes = BinderScopes::new(unit, namespace);
1079 let mut visit = BinderVisitor::new(config.clone());
1080 visit.visit_node(&unit, node, &mut scopes, namespace, None);
1081}