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