flux_desugar/
resolver.rs

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