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