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    prim_props: UnordMap<Symbol, FluxDefId>,
67    enum_variants: FxHashMap<DefId, EnumVariants>,
68    err: Option<ErrorGuaranteed>,
69    /// The most recent module we have visited. Used to check for visibility of other items from
70    /// this module.
71    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        // Flux items are made globally available as if they were defined at the top of the crate
519        if hir_id == CRATE_HIR_ID {
520            self.define_flux_global_items();
521        }
522
523        // But we resolve names in them as if they were defined in their containing module
524        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
652/// Akin to `rustc_resolve::Module` but specialized to what we support
653struct 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
664/// Akin to `rustc_resolve::ModuleKind` but specialized to what we support
665enum ModuleKind {
666    Mod,
667    Trait,
668}
669
670#[derive(Debug)]
671enum RibKind {
672    /// Any other rib without extra rules.
673    Normal,
674    /// We pass through a module. Lookups of items should stop here.
675    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
699/// Iterator over module children visible form `curr_mod`
700fn 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
710/// Return true if the item has a `#[prelude_import]` annotation
711fn 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
717/// Abstraction over [`surface::PathSegment`] and [`surface::ExprPathSegment`]
718trait 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>, // TODO: HACK! need to generalize to multiple opaque types/impls in a signature.
755    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>, // TODO: HACK! need to generalize to multiple opaque types/impls in a signature.
840    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}