flux_desugar/
resolver.rs

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