1pub(crate) mod refinement_resolver;
2
3use flux_common::{
4 bug,
5 result::{ErrorCollector, ResultExt},
6};
7use flux_errors::{Errors, FluxSession};
8use flux_middle::{
9 ResolverOutput, Specs,
10 def_id::{FluxDefId, FluxLocalDefId, MaybeExternId},
11 fhir,
12 global_env::GlobalEnv,
13};
14use flux_syntax::surface::{self, Ident, visit::Visitor as _};
15use hir::{ItemId, ItemKind, OwnerId, def::DefKind};
16use rustc_data_structures::unord::{ExtendUnord, UnordMap};
17use rustc_errors::ErrorGuaranteed;
18use rustc_hash::FxHashMap;
19use rustc_hir::{
20 self as hir, AmbigArg, CRATE_HIR_ID, CRATE_OWNER_ID, ParamName, PrimTy,
21 def::{
22 Namespace::{self, *},
23 PerNS,
24 },
25 def_id::{CRATE_DEF_ID, LocalDefId},
26};
27use rustc_middle::{metadata::ModChild, ty::TyCtxt};
28use rustc_span::{Span, Symbol, def_id::DefId, sym, symbol::kw};
29
30use self::refinement_resolver::RefinementResolver;
31
32type Result<T = ()> = std::result::Result<T, ErrorGuaranteed>;
33
34pub(crate) fn resolve_crate(genv: GlobalEnv) -> ResolverOutput {
35 match try_resolve_crate(genv) {
36 Ok(output) => output,
37 Err(err) => genv.sess().abort(err),
38 }
39}
40
41fn try_resolve_crate(genv: GlobalEnv) -> Result<ResolverOutput> {
42 let specs = genv.collect_specs();
43 let mut resolver = CrateResolver::new(genv, specs);
44
45 genv.tcx().hir_walk_toplevel_module(&mut resolver);
46
47 resolver.into_output()
48}
49
50pub(crate) struct EnumVariants {
51 variants: FxHashMap<Symbol, DefId>,
52}
53
54pub(crate) struct CrateResolver<'genv, 'tcx> {
55 genv: GlobalEnv<'genv, 'tcx>,
56 specs: &'genv Specs,
57 output: ResolverOutput,
58 ribs: PerNS<Vec<Rib>>,
59 crates: UnordMap<Symbol, DefId>,
62 prelude: PerNS<Rib>,
63 qualifiers: UnordMap<Symbol, FluxLocalDefId>,
64 func_decls: UnordMap<Symbol, fhir::SpecFuncKind>,
65 sort_decls: UnordMap<Symbol, fhir::SortDecl>,
66 prim_props: UnordMap<Symbol, FluxDefId>,
67 enum_variants: FxHashMap<DefId, EnumVariants>,
68 err: Option<ErrorGuaranteed>,
69 current_module: OwnerId,
72}
73
74impl<'genv, 'tcx> CrateResolver<'genv, 'tcx> {
75 pub fn new(genv: GlobalEnv<'genv, 'tcx>, specs: &'genv Specs) -> Self {
76 Self {
77 genv,
78 output: ResolverOutput::default(),
79 specs,
80 ribs: PerNS { type_ns: vec![], value_ns: vec![], macro_ns: vec![] },
81 crates: mk_crate_mapping(genv.tcx()),
82 prelude: PerNS {
83 type_ns: builtin_types_rib(),
84 value_ns: Rib::new(RibKind::Normal),
85 macro_ns: Rib::new(RibKind::Normal),
86 },
87 err: None,
88 qualifiers: Default::default(),
89 func_decls: Default::default(),
90 prim_props: Default::default(),
91 sort_decls: Default::default(),
92 enum_variants: Default::default(),
93 current_module: CRATE_OWNER_ID,
94 }
95 }
96
97 #[allow(clippy::disallowed_methods, reason = "`flux_items_by_parent` is the source of truth")]
98 fn define_flux_global_items(&mut self) {
99 for (parent, items) in &self.specs.flux_items_by_parent {
100 for item in items {
101 match item {
102 surface::Item::Qualifier(qual) => {
103 let def_id = FluxLocalDefId::new(parent.def_id, qual.name.name);
104 self.qualifiers.insert(qual.name.name, def_id);
105 }
106 surface::Item::FuncDef(defn) => {
107 let parent = parent.def_id.to_def_id();
108 let def_id = FluxDefId::new(parent, defn.name.name);
109 let kind = if defn.body.is_some() {
110 fhir::SpecFuncKind::Def(def_id)
111 } else {
112 fhir::SpecFuncKind::Uif(def_id)
113 };
114 self.func_decls.insert(defn.name.name, kind);
115 }
116 surface::Item::PrimProp(prim_prop) => {
117 let name = prim_prop.name.name;
118 let parent = parent.def_id.to_def_id();
119 let def_id = FluxDefId::new(parent, name);
120 self.prim_props.insert(name, def_id);
121 }
122 surface::Item::SortDecl(sort_decl) => {
123 self.sort_decls.insert(
124 sort_decl.name.name,
125 fhir::SortDecl { name: sort_decl.name.name, span: sort_decl.name.span },
126 );
127 }
128 }
129 }
130 }
131
132 self.func_decls.extend_unord(
133 flux_middle::THEORY_FUNCS
134 .items()
135 .map(|(_, itf)| (itf.name, fhir::SpecFuncKind::Thy(itf.itf))),
136 );
137 self.func_decls
138 .insert(Symbol::intern("char_to_int"), fhir::SpecFuncKind::CharToInt);
139 }
140
141 fn define_items(&mut self, item_ids: impl IntoIterator<Item = &'tcx ItemId>) {
142 for item_id in item_ids {
143 let item = self.genv.tcx().hir_item(*item_id);
144 let def_kind = match item.kind {
145 ItemKind::Use(path, kind) => {
146 match kind {
147 hir::UseKind::Single(ident) => {
148 let name = ident.name;
149 if let Some(res) = path.res.value_ns
150 && let Ok(res) = fhir::Res::try_from(res)
151 {
152 self.define_res_in(name, res, ValueNS);
153 }
154 if let Some(res) = path.res.type_ns
155 && let Ok(res) = fhir::Res::try_from(res)
156 {
157 self.define_res_in(name, res, TypeNS);
158 }
159 }
160 hir::UseKind::Glob => {
161 let is_prelude = is_prelude_import(self.genv.tcx(), item);
162 for mod_child in self.glob_imports(path) {
163 if let Some(ns @ (TypeNS | ValueNS)) = mod_child.res.ns()
164 && let Ok(res) = fhir::Res::try_from(mod_child.res)
165 {
166 let name = mod_child.ident.name;
167 if is_prelude {
168 self.define_in_prelude(name, res, ns);
169 } else {
170 self.define_res_in(name, res, ns);
171 }
172 }
173 }
174 }
175 hir::UseKind::ListStem => {}
176 }
177 continue;
178 }
179 ItemKind::TyAlias(..) => DefKind::TyAlias,
180 ItemKind::Enum(_, _, enum_def) => {
181 self.define_enum_variants(&enum_def);
182 DefKind::Enum
183 }
184 ItemKind::Struct(..) => DefKind::Struct,
185 ItemKind::Trait(..) => DefKind::Trait,
186 ItemKind::Mod(..) => DefKind::Mod,
187 ItemKind::Const(..) => DefKind::Const,
188 ItemKind::ForeignMod { items, .. } => {
189 self.define_foreign_items(items);
190 continue;
191 }
192 _ => continue,
193 };
194 if let Some(ns) = def_kind.ns()
195 && let Some(ident) = item.kind.ident()
196 {
197 self.define_res_in(
198 ident.name,
199 fhir::Res::Def(def_kind, item.owner_id.to_def_id()),
200 ns,
201 );
202 }
203 }
204 }
205
206 fn define_foreign_items(&mut self, items: &[rustc_hir::ForeignItemRef]) {
207 for item_ref in items {
208 let item = self.genv.tcx().hir_foreign_item(item_ref.id);
209 match item.kind {
210 rustc_hir::ForeignItemKind::Type => {
211 self.define_res_in(
212 item.ident.name,
213 fhir::Res::Def(DefKind::ForeignTy, item.owner_id.to_def_id()),
214 TypeNS,
215 );
216 }
217 rustc_hir::ForeignItemKind::Fn(..) | rustc_hir::ForeignItemKind::Static(..) => {}
218 }
219 }
220 }
221
222 fn define_enum_variants(&mut self, enum_def: &rustc_hir::EnumDef) {
223 let Some(v0) = enum_def.variants.first() else { return };
224 let enum_def_id = self.genv.tcx().parent(v0.def_id.to_def_id());
225
226 let mut variants = FxHashMap::default();
227 for variant in enum_def.variants {
228 let name = variant.ident.name;
229 variants.insert(name, variant.def_id.to_def_id());
230 }
231 self.enum_variants
232 .insert(enum_def_id, EnumVariants { variants });
233 }
234
235 fn define_res_in(&mut self, name: Symbol, res: fhir::Res, ns: Namespace) {
236 self.ribs[ns].last_mut().unwrap().bindings.insert(name, res);
237 }
238
239 fn define_in_prelude(&mut self, name: Symbol, res: fhir::Res, ns: Namespace) {
240 self.prelude[ns].bindings.insert(name, res);
241 }
242
243 fn push_rib(&mut self, ns: Namespace, kind: RibKind) {
244 self.ribs[ns].push(Rib::new(kind));
245 }
246
247 fn pop_rib(&mut self, ns: Namespace) {
248 self.ribs[ns].pop();
249 }
250
251 fn define_generics(&mut self, def_id: MaybeExternId<OwnerId>) {
252 let generics = self
253 .genv
254 .tcx()
255 .hir_get_generics(def_id.local_id().def_id)
256 .unwrap();
257 for param in generics.params {
258 let def_kind = self.genv.tcx().def_kind(param.def_id);
259 if let ParamName::Plain(name) = param.name
260 && let Some(ns) = def_kind.ns()
261 {
262 debug_assert!(matches!(def_kind, DefKind::TyParam | DefKind::ConstParam));
263 let param_id = self.genv.maybe_extern_id(param.def_id).resolved_id();
264 self.define_res_in(name.name, fhir::Res::Def(def_kind, param_id), ns);
265 }
266 }
267 }
268
269 fn resolve_flux_items(&mut self, parent: OwnerId) {
270 let Some(items) = self.specs.flux_items_by_parent.get(&parent) else { return };
271 for item in items {
272 match item {
273 surface::Item::Qualifier(qual) => {
274 RefinementResolver::resolve_qualifier(self, qual).collect_err(&mut self.err);
275 }
276 surface::Item::FuncDef(defn) => {
277 RefinementResolver::resolve_defn(self, defn).collect_err(&mut self.err);
278 }
279 surface::Item::SortDecl(_) => {}
280 surface::Item::PrimProp(prim_prop) => {
281 RefinementResolver::resolve_prim_prop(self, prim_prop)
282 .collect_err(&mut self.err);
283 }
284 }
285 }
286 }
287
288 fn resolve_trait(&mut self, owner_id: MaybeExternId<OwnerId>) -> Result {
289 let trait_ = &self.specs.traits[&owner_id.local_id()];
290 ItemResolver::run(self, owner_id, |item_resolver| {
291 item_resolver.visit_trait(trait_);
292 })?;
293 RefinementResolver::resolve_trait(self, trait_)
294 }
295
296 fn resolve_impl(&mut self, owner_id: MaybeExternId<OwnerId>) -> Result {
297 let impl_ = &self.specs.impls[&owner_id.local_id()];
298 ItemResolver::run(self, owner_id, |item_resolver| {
299 item_resolver.visit_impl(impl_);
300 })?;
301 RefinementResolver::resolve_impl(self, impl_)
302 }
303
304 fn resolve_type_alias(&mut self, owner_id: MaybeExternId<OwnerId>) -> Result {
305 if let Some(ty_alias) = &self.specs.ty_aliases[&owner_id.local_id()] {
306 ItemResolver::run(self, owner_id, |item_resolver| {
307 item_resolver.visit_ty_alias(ty_alias);
308 })?;
309 RefinementResolver::resolve_ty_alias(self, ty_alias)?;
310 }
311 Ok(())
312 }
313
314 fn resolve_struct_def(&mut self, owner_id: MaybeExternId<OwnerId>) -> Result {
315 let struct_def = &self.specs.structs[&owner_id.local_id()];
316 ItemResolver::run(self, owner_id, |item_resolver| {
317 item_resolver.visit_struct_def(struct_def);
318 })?;
319 RefinementResolver::resolve_struct_def(self, struct_def)
320 }
321
322 fn resolve_enum_def(&mut self, owner_id: MaybeExternId<OwnerId>) -> Result {
323 let enum_def = &self.specs.enums[&owner_id.local_id()];
324 ItemResolver::run(self, owner_id, |item_resolver| {
325 item_resolver.visit_enum_def(enum_def);
326 })?;
327 RefinementResolver::resolve_enum_def(self, enum_def)
328 }
329
330 fn resolve_constant(&mut self, owner_id: MaybeExternId<OwnerId>) -> Result {
331 if let Some(constant) = self.specs.constants.get(&owner_id.local_id()) {
332 ItemResolver::run(self, owner_id, |item_resolver| {
333 item_resolver.visit_constant(constant);
334 })?;
335 RefinementResolver::resolve_constant(self, constant)?;
336 }
337 Ok(())
338 }
339
340 fn resolve_fn_sig(&mut self, owner_id: MaybeExternId<OwnerId>) -> Result {
341 let fn_spec = &self.specs.fn_sigs[&owner_id.local_id()];
342
343 if let Some(owner_id) = owner_id.as_local() {
344 self.resolve_qualifiers(owner_id, fn_spec.qual_names.as_ref())?;
345 self.resolve_reveals(owner_id, fn_spec.reveal_names.as_ref())?;
346 }
347 if let Some(fn_sig) = &fn_spec.fn_sig {
348 ItemResolver::run(self, owner_id, |item_resolver| {
349 item_resolver.visit_fn_sig(fn_sig);
350 })?;
351 RefinementResolver::resolve_fn_sig(self, fn_sig)?;
352 }
353 Ok(())
354 }
355
356 fn resolve_qualifiers(
357 &mut self,
358 owner_id: OwnerId,
359 quals: Option<&surface::QualNames>,
360 ) -> Result {
361 let qual_names = quals.map_or(&[][..], |q| &q.names[..]);
362 let mut qualifiers = Vec::with_capacity(qual_names.len());
363 for qual in qual_names {
364 if let Some(def_id) = self.qualifiers.get(&qual.name) {
365 qualifiers.push(*def_id);
366 } else {
367 return Err(self
368 .genv
369 .sess()
370 .emit_err(errors::UnknownQualifier::new(qual.span)));
371 }
372 }
373 self.output.qualifier_res_map.insert(owner_id, qualifiers);
374 Ok(())
375 }
376
377 fn resolve_reveals(
378 &mut self,
379 owner_id: OwnerId,
380 reveals: Option<&surface::RevealNames>,
381 ) -> Result {
382 let reveal_names = reveals.map_or(&[][..], |q| &q.names[..]);
383 let mut reveals = Vec::with_capacity(reveal_names.len());
384 for reveal in reveal_names {
385 if let Some(spec) = self.func_decls.get(&reveal.name)
386 && let Some(def_id) = spec.def_id()
387 {
388 reveals.push(def_id);
389 } else {
390 return Err(self
391 .genv
392 .sess()
393 .emit_err(errors::UnknownRevealDefinition::new(reveal.span)));
394 }
395 }
396 self.output.reveal_res_map.insert(owner_id, reveals);
397 Ok(())
398 }
399
400 fn resolve_path_with_ribs<S: Segment>(
401 &mut self,
402 segments: &[S],
403 ns: Namespace,
404 ) -> Option<fhir::PartialRes> {
405 let mut module: Option<Module> = None;
406 for (segment_idx, segment) in segments.iter().enumerate() {
407 let is_last = segment_idx + 1 == segments.len();
408 let ns = if is_last { ns } else { TypeNS };
409
410 let base_res = if let Some(module) = &module {
411 self.resolve_ident_in_module(module, segment.ident(), ns)?
412 } else {
413 self.resolve_ident_with_ribs(segment.ident(), ns)?
414 };
415
416 S::record_segment_res(self, segment, base_res);
417
418 if is_last {
419 return Some(fhir::PartialRes::new(base_res));
420 }
421
422 match base_res {
423 fhir::Res::Def(DefKind::Mod, module_id) => {
424 module = Some(Module::new(ModuleKind::Mod, module_id));
425 }
426 fhir::Res::Def(DefKind::Trait, module_id) => {
427 module = Some(Module::new(ModuleKind::Trait, module_id));
428 }
429 _ => {
430 return Some(fhir::PartialRes::with_unresolved_segments(
431 base_res,
432 segments.len() - segment_idx - 1,
433 ));
434 }
435 }
436 }
437 None
438 }
439
440 fn resolve_ident_with_ribs(&self, ident: Ident, ns: Namespace) -> Option<fhir::Res> {
441 for rib in self.ribs[ns].iter().rev() {
442 if let Some(res) = rib.bindings.get(&ident.name) {
443 return Some(*res);
444 }
445 if matches!(rib.kind, RibKind::Module) {
446 break;
447 }
448 }
449 if ns == TypeNS
450 && let Some(crate_id) = self.crates.get(&ident.name)
451 {
452 return Some(fhir::Res::Def(DefKind::Mod, *crate_id));
453 }
454
455 if let Some(res) = self.prelude[ns].bindings.get(&ident.name) {
456 return Some(*res);
457 }
458 None
459 }
460
461 fn glob_imports(
462 &self,
463 path: &hir::UsePath,
464 ) -> impl Iterator<Item = &'tcx ModChild> + use<'tcx> {
465 let res = path.segments.last().unwrap().res;
466
467 let tcx = self.genv.tcx();
468 let curr_mod = self.current_module.to_def_id();
469 if let hir::def::Res::Def(DefKind::Mod, module_id) = res { Some(module_id) } else { None }
470 .into_iter()
471 .flat_map(move |module_id| visible_module_children(tcx, module_id, curr_mod))
472 }
473
474 fn resolve_ident_in_module(
475 &self,
476 module: &Module,
477 ident: Ident,
478 ns: Namespace,
479 ) -> Option<fhir::Res> {
480 match module.kind {
481 ModuleKind::Mod => {
482 let module_id = module.def_id;
483 visible_module_children(self.genv.tcx(), module_id, self.current_module.to_def_id())
484 .find(|child| child.ident == ident)
485 .and_then(|child| fhir::Res::try_from(child.res).ok())
486 }
487 ModuleKind::Trait => {
488 let tcx = self.genv.tcx();
489 let trait_id = module.def_id;
490 tcx.associated_items(trait_id)
491 .find_by_ident_and_namespace(tcx, ident, ns, trait_id)
492 .map(|assoc| fhir::Res::Def(assoc.kind.as_def_kind(), assoc.def_id))
493 }
494 }
495 }
496
497 pub fn into_output(self) -> Result<ResolverOutput> {
498 self.err.into_result()?;
499 Ok(self.output)
500 }
501}
502
503impl<'tcx> hir::intravisit::Visitor<'tcx> for CrateResolver<'_, 'tcx> {
504 type NestedFilter = rustc_middle::hir::nested_filter::All;
505
506 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
507 self.genv.tcx()
508 }
509
510 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _s: Span, hir_id: hir::HirId) {
511 let old_mod = self.current_module;
512 self.current_module = hir_id.expect_owner();
513 self.push_rib(TypeNS, RibKind::Module);
514 self.push_rib(ValueNS, RibKind::Module);
515
516 self.define_items(module.item_ids);
517
518 if hir_id == CRATE_HIR_ID {
520 self.define_flux_global_items();
521 }
522
523 self.resolve_flux_items(hir_id.expect_owner());
525
526 hir::intravisit::walk_mod(self, module);
527
528 self.pop_rib(ValueNS);
529 self.pop_rib(TypeNS);
530 self.current_module = old_mod;
531 }
532
533 fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
534 self.push_rib(TypeNS, RibKind::Normal);
535 self.push_rib(ValueNS, RibKind::Normal);
536
537 let item_ids = block.stmts.iter().filter_map(|stmt| {
538 if let hir::StmtKind::Item(item_id) = &stmt.kind { Some(item_id) } else { None }
539 });
540 self.define_items(item_ids);
541 self.resolve_flux_items(self.genv.tcx().hir_get_parent_item(block.hir_id));
542
543 hir::intravisit::walk_block(self, block);
544
545 self.pop_rib(ValueNS);
546 self.pop_rib(TypeNS);
547 }
548
549 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
550 if self.genv.is_dummy(item.owner_id.def_id) {
551 return;
552 }
553 let def_id = self
554 .genv
555 .maybe_extern_id(item.owner_id.def_id)
556 .map(|def_id| OwnerId { def_id });
557
558 self.push_rib(TypeNS, RibKind::Normal);
559 self.push_rib(ValueNS, RibKind::Normal);
560
561 match item.kind {
562 ItemKind::Trait(..) => {
563 self.define_generics(def_id);
564 self.define_res_in(
565 kw::SelfUpper,
566 fhir::Res::SelfTyParam { trait_: def_id.resolved_id() },
567 TypeNS,
568 );
569 self.resolve_trait(def_id).collect_err(&mut self.err);
570 }
571 ItemKind::Impl(impl_) => {
572 self.define_generics(def_id);
573 self.define_res_in(
574 kw::SelfUpper,
575 fhir::Res::SelfTyAlias {
576 alias_to: def_id.resolved_id(),
577 is_trait_impl: impl_.of_trait.is_some(),
578 },
579 TypeNS,
580 );
581 self.resolve_impl(def_id).collect_err(&mut self.err);
582 }
583 ItemKind::TyAlias(..) => {
584 self.define_generics(def_id);
585 self.resolve_type_alias(def_id).collect_err(&mut self.err);
586 }
587 ItemKind::Enum(_enum_def, ..) => {
588 self.define_generics(def_id);
589 self.define_res_in(
590 kw::SelfUpper,
591 fhir::Res::SelfTyAlias { alias_to: def_id.resolved_id(), is_trait_impl: false },
592 TypeNS,
593 );
594 self.resolve_enum_def(def_id).collect_err(&mut self.err);
595 }
596 ItemKind::Struct(..) => {
597 self.define_generics(def_id);
598 self.define_res_in(
599 kw::SelfUpper,
600 fhir::Res::SelfTyAlias { alias_to: def_id.resolved_id(), is_trait_impl: false },
601 TypeNS,
602 );
603 self.resolve_struct_def(def_id).collect_err(&mut self.err);
604 }
605 ItemKind::Fn { .. } => {
606 self.define_generics(def_id);
607 self.resolve_fn_sig(def_id).collect_err(&mut self.err);
608 }
609 ItemKind::Const(..) => {
610 self.resolve_constant(def_id).collect_err(&mut self.err);
611 }
612 _ => {}
613 }
614
615 hir::intravisit::walk_item(self, item);
616
617 self.pop_rib(ValueNS);
618 self.pop_rib(TypeNS);
619 }
620
621 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
622 let def_id = self
623 .genv
624 .maybe_extern_id(impl_item.owner_id.def_id)
625 .map(|def_id| OwnerId { def_id });
626
627 self.push_rib(TypeNS, RibKind::Normal);
628 self.define_generics(def_id);
629 if let hir::ImplItemKind::Fn(..) = impl_item.kind {
630 self.resolve_fn_sig(def_id).collect_err(&mut self.err);
631 }
632 hir::intravisit::walk_impl_item(self, impl_item);
633 self.pop_rib(TypeNS);
634 }
635
636 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
637 let def_id = self
638 .genv
639 .maybe_extern_id(trait_item.owner_id.def_id)
640 .map(|def_id| OwnerId { def_id });
641
642 self.push_rib(TypeNS, RibKind::Normal);
643 self.define_generics(def_id);
644 if let hir::TraitItemKind::Fn(..) = trait_item.kind {
645 self.resolve_fn_sig(def_id).collect_err(&mut self.err);
646 }
647 hir::intravisit::walk_trait_item(self, trait_item);
648 self.pop_rib(TypeNS);
649 }
650}
651
652struct Module {
654 kind: ModuleKind,
655 def_id: DefId,
656}
657
658impl Module {
659 fn new(kind: ModuleKind, def_id: DefId) -> Self {
660 Self { kind, def_id }
661 }
662}
663
664enum ModuleKind {
666 Mod,
667 Trait,
668}
669
670#[derive(Debug)]
671enum RibKind {
672 Normal,
674 Module,
676}
677
678#[derive(Debug)]
679struct Rib {
680 kind: RibKind,
681 bindings: FxHashMap<Symbol, fhir::Res>,
682}
683
684impl Rib {
685 fn new(kind: RibKind) -> Self {
686 Self { kind, bindings: Default::default() }
687 }
688}
689
690fn module_children(tcx: TyCtxt<'_>, def_id: DefId) -> &[ModChild] {
691 #[expect(clippy::disallowed_methods, reason = "modules cannot have extern specs")]
692 if let Some(local_id) = def_id.as_local() {
693 tcx.module_children_local(local_id)
694 } else {
695 tcx.module_children(def_id)
696 }
697}
698
699fn visible_module_children(
701 tcx: TyCtxt<'_>,
702 module_id: DefId,
703 curr_mod: DefId,
704) -> impl Iterator<Item = &ModChild> {
705 module_children(tcx, module_id)
706 .iter()
707 .filter(move |child| child.vis.is_accessible_from(curr_mod, tcx))
708}
709
710fn is_prelude_import(tcx: TyCtxt, item: &hir::Item) -> bool {
712 tcx.hir_attrs(item.hir_id())
713 .iter()
714 .any(|attr| attr.path_matches(&[sym::prelude_import]))
715}
716
717trait Segment: std::fmt::Debug {
719 fn record_segment_res(resolver: &mut CrateResolver, segment: &Self, res: fhir::Res);
720 fn ident(&self) -> Ident;
721}
722
723impl Segment for surface::PathSegment {
724 fn record_segment_res(resolver: &mut CrateResolver, segment: &Self, res: fhir::Res) {
725 resolver
726 .output
727 .path_res_map
728 .insert(segment.node_id, fhir::PartialRes::new(res));
729 }
730
731 fn ident(&self) -> Ident {
732 self.ident
733 }
734}
735
736impl Segment for surface::ExprPathSegment {
737 fn record_segment_res(_resolver: &mut CrateResolver, _segment: &Self, _res: fhir::Res) {}
738
739 fn ident(&self) -> Ident {
740 self.ident
741 }
742}
743
744impl Segment for Ident {
745 fn record_segment_res(_resolver: &mut CrateResolver, _segment: &Self, _res: fhir::Res) {}
746
747 fn ident(&self) -> Ident {
748 *self
749 }
750}
751
752struct ItemResolver<'a, 'genv, 'tcx> {
753 resolver: &'a mut CrateResolver<'genv, 'tcx>,
754 opaque: Option<LocalDefId>, errors: Errors<'genv>,
756}
757
758impl<'a, 'genv, 'tcx> ItemResolver<'a, 'genv, 'tcx> {
759 fn run(
760 resolver: &'a mut CrateResolver<'genv, 'tcx>,
761 owner_id: MaybeExternId<OwnerId>,
762 f: impl FnOnce(&mut ItemResolver),
763 ) -> Result {
764 let mut item_resolver = ItemResolver::new(resolver, owner_id)?;
765 f(&mut item_resolver);
766 item_resolver.errors.into_result()
767 }
768
769 fn new(
770 resolver: &'a mut CrateResolver<'genv, 'tcx>,
771 owner_id: MaybeExternId<OwnerId>,
772 ) -> Result<Self> {
773 let tcx = resolver.genv.tcx();
774 let sess = resolver.genv.sess();
775 let opaque = match tcx.hir_owner_node(owner_id.local_id()) {
776 hir::OwnerNode::Item(item) => OpaqueTypeCollector::collect_item(sess, item)?,
777 hir::OwnerNode::ImplItem(impl_item) => {
778 OpaqueTypeCollector::collect_impl_item(sess, impl_item)?
779 }
780 hir::OwnerNode::TraitItem(trait_item) => {
781 OpaqueTypeCollector::collect_trait_item(sess, trait_item)?
782 }
783 node @ (hir::OwnerNode::ForeignItem(_)
784 | hir::OwnerNode::Crate(_)
785 | hir::OwnerNode::Synthetic) => {
786 bug!("unsupported node {node:?}")
787 }
788 };
789
790 let errors = Errors::new(resolver.genv.sess());
791 Ok(Self { resolver, opaque, errors })
792 }
793
794 fn resolve_opaque_impl(&mut self, node_id: surface::NodeId, span: Span) {
795 if let Some(def_id) = self.opaque {
796 self.resolver
797 .output
798 .impl_trait_res_map
799 .insert(node_id, def_id);
800 } else {
801 self.errors
802 .emit(errors::UnresolvedPath { span, path: "opaque type".into() });
803 }
804 }
805
806 fn resolve_type_path(&mut self, path: &surface::Path) {
807 if let Some(partial_res) = self.resolver.resolve_path_with_ribs(&path.segments, TypeNS) {
808 self.resolver
809 .output
810 .path_res_map
811 .insert(path.node_id, partial_res);
812 } else {
813 self.errors.emit(errors::UnresolvedPath::new(path));
814 }
815 }
816}
817
818impl surface::visit::Visitor for ItemResolver<'_, '_, '_> {
819 fn visit_async(&mut self, asyncness: &surface::Async) {
820 if let surface::Async::Yes { node_id, span } = asyncness {
821 self.resolve_opaque_impl(*node_id, *span);
822 }
823 }
824
825 fn visit_ty(&mut self, ty: &surface::Ty) {
826 if let surface::TyKind::ImplTrait(node_id, _) = &ty.kind {
827 self.resolve_opaque_impl(*node_id, ty.span);
828 }
829 surface::visit::walk_ty(self, ty);
830 }
831
832 fn visit_path(&mut self, path: &surface::Path) {
833 self.resolve_type_path(path);
834 surface::visit::walk_path(self, path);
835 }
836}
837
838struct OpaqueTypeCollector<'sess> {
839 opaque: Option<LocalDefId>, errors: Errors<'sess>,
841}
842
843impl<'sess> OpaqueTypeCollector<'sess> {
844 fn new(sess: &'sess FluxSession) -> Self {
845 Self { opaque: None, errors: Errors::new(sess) }
846 }
847
848 fn collect_item(sess: &'sess FluxSession, item: &hir::Item) -> Result<Option<LocalDefId>> {
849 let mut collector = Self::new(sess);
850 hir::intravisit::walk_item(&mut collector, item);
851 collector.into_result()
852 }
853
854 fn collect_impl_item(
855 sess: &'sess FluxSession,
856 impl_item: &hir::ImplItem,
857 ) -> Result<Option<LocalDefId>> {
858 let mut collector = Self::new(sess);
859 hir::intravisit::walk_impl_item(&mut collector, impl_item);
860 collector.into_result()
861 }
862
863 fn collect_trait_item(
864 sess: &'sess FluxSession,
865 trait_item: &hir::TraitItem,
866 ) -> Result<Option<LocalDefId>> {
867 let mut collector = Self::new(sess);
868 hir::intravisit::walk_trait_item(&mut collector, trait_item);
869 collector.into_result()
870 }
871
872 fn into_result(self) -> Result<Option<LocalDefId>> {
873 self.errors.into_result()?;
874 Ok(self.opaque)
875 }
876}
877
878impl<'tcx> hir::intravisit::Visitor<'tcx> for OpaqueTypeCollector<'_> {
879 fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
880 if let hir::TyKind::OpaqueDef(opaque_ty, ..) = ty.kind {
881 if self.opaque.is_some() {
882 self.errors.emit(errors::UnsupportedSignature::new(
883 ty.span,
884 "duplicate opaque types in signature",
885 ));
886 } else {
887 self.opaque = Some(opaque_ty.def_id);
888 }
889 }
890 hir::intravisit::walk_ty(self, ty);
891 }
892}
893
894fn builtin_types_rib() -> Rib {
895 Rib {
896 kind: RibKind::Normal,
897 bindings: PrimTy::ALL
898 .into_iter()
899 .map(|pty| (pty.name(), fhir::Res::PrimTy(pty)))
900 .collect(),
901 }
902}
903
904fn mk_crate_mapping(tcx: TyCtxt) -> UnordMap<Symbol, DefId> {
905 let mut map = UnordMap::default();
906 map.insert(kw::Crate, CRATE_DEF_ID.to_def_id());
907 for cnum in tcx.crates(()) {
908 let name = tcx.crate_name(*cnum);
909 if let Some(extern_crate) = tcx.extern_crate(*cnum)
910 && extern_crate.is_direct()
911 {
912 map.insert(name, cnum.as_def_id());
913 }
914 }
915 map
916}
917
918mod errors {
919 use flux_errors::E0999;
920 use flux_macros::Diagnostic;
921 use flux_syntax::surface;
922 use itertools::Itertools;
923 use rustc_span::Span;
924
925 #[derive(Diagnostic)]
926 #[diag(desugar_unsupported_signature, code = E0999)]
927 #[note]
928 pub(super) struct UnsupportedSignature<'a> {
929 #[primary_span]
930 span: Span,
931 note: &'a str,
932 }
933
934 impl<'a> UnsupportedSignature<'a> {
935 pub(super) fn new(span: Span, note: &'a str) -> Self {
936 Self { span, note }
937 }
938 }
939
940 #[derive(Diagnostic)]
941 #[diag(desugar_unresolved_path, code = E0999)]
942 pub struct UnresolvedPath {
943 #[primary_span]
944 pub span: Span,
945 pub path: String,
946 }
947
948 impl UnresolvedPath {
949 pub fn new(path: &surface::Path) -> Self {
950 Self {
951 span: path.span,
952 path: path.segments.iter().map(|segment| segment.ident).join("::"),
953 }
954 }
955 }
956
957 #[derive(Diagnostic)]
958 #[diag(desugar_unknown_qualifier, code = E0999)]
959 pub(super) struct UnknownQualifier {
960 #[primary_span]
961 span: Span,
962 }
963
964 impl UnknownQualifier {
965 pub(super) fn new(span: Span) -> Self {
966 Self { span }
967 }
968 }
969
970 #[derive(Diagnostic)]
971 #[diag(desugar_unknown_reveal_definition, code = E0999)]
972 pub(super) struct UnknownRevealDefinition {
973 #[primary_span]
974 span: Span,
975 }
976
977 impl UnknownRevealDefinition {
978 pub(super) fn new(span: Span) -> Self {
979 Self { span }
980 }
981 }
982}