flux_desugar/
resolver.rs

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