Skip to main content

flux_desugar/
resolver.rs

1pub(crate) mod refinement_resolver;
2
3use std::collections::hash_map;
4
5use flux_common::{
6    bug,
7    result::{ErrorCollector, ErrorEmitter, ResultExt},
8};
9use flux_errors::Errors;
10use flux_middle::{
11    FluxItemDecl, ResolverOutput, Specs,
12    def_id::{FluxDefId, FluxLocalDefId, MaybeExternId},
13    fhir,
14    fhir::{
15        Namespace::{self, *},
16        PerNS,
17    },
18    global_env::GlobalEnv,
19};
20use flux_syntax::{
21    surface::{self, Ident, visit::Visitor as _},
22    symbols::sym,
23};
24use hir::{ItemId, ItemKind, OwnerId, def::DefKind};
25use itertools::Itertools;
26use rustc_data_structures::unord::{ExtendUnord, UnordMap};
27use rustc_errors::ErrorGuaranteed;
28use rustc_hir::{
29    self as hir, CRATE_OWNER_ID, ParamName, PrimTy, def::CtorOf, def_id::CRATE_DEF_ID,
30};
31use rustc_middle::{middle::resolve::ModChild, ty::TyCtxt};
32use rustc_span::{Span, Symbol, def_id::DefId, symbol::kw};
33
34use self::refinement_resolver::{ImplicitParamCollector, RefinementResolver};
35
36type Result<T = ()> = std::result::Result<T, ErrorGuaranteed>;
37
38/// The reason a name lookup (`resolve_ident_with_ribs`, `resolve_ident_in_module`,
39/// `resolve_path_with_ribs`) failed.
40enum ResolveError {
41    NotFound,
42    /// The name resolved to two or more distinct, competing bindings (e.g. two different glob
43    /// imports bringing in different items under the same name) with nothing more specific to
44    /// disambiguate. Carries everything needed to emit [`errors::AmbiguousName`], so that callers
45    /// deep in the path walk don't have to reconstruct which segment went wrong.
46    Ambiguous(Ambiguity),
47    /// The name resolved to a generic parameter (or `Self`) of an outer item.
48    OuterGeneric(Span),
49}
50
51impl ResolveError {
52    /// Emits the error. A [`ResolveError::NotFound`] is reported with the diagnostic built by
53    /// `not_found`, since only the caller knows what was being looked for.
54    #[track_caller]
55    fn emit<'a, D: rustc_errors::Diagnostic<'a>>(
56        self,
57        emitter: &'a impl ErrorEmitter,
58        not_found: impl FnOnce() -> D,
59    ) -> ErrorGuaranteed {
60        match self {
61            Self::NotFound => emitter.emit(not_found()),
62            Self::Ambiguous(ambiguity) => emitter.emit(errors::AmbiguousName::new(ambiguity)),
63            Self::OuterGeneric(span) => emitter.emit(errors::OuterGeneric { span }),
64        }
65    }
66}
67
68/// A name that two competing glob imports bind to different items:
69///
70/// ```ignore
71/// mod a { pub struct S; }
72/// mod b { pub struct S; }
73///
74/// use a::*;
75/// use b::*;
76///
77/// #[flux::spec(fn(x: S))]
78/// fn f(x: a::S) {}
79/// ```
80#[derive(Clone, Copy, Debug)]
81struct Ambiguity {
82    /// The use site that hit the ambiguity: the `S` inside the signature.
83    span: Span,
84    /// The contested name: `S`.
85    name: Symbol,
86    /// Where the first candidate was brought into scope: the `use a::*;` statement.
87    first: Span,
88    /// Same for the second candidate: `use b::*;`. It can coincide with `first` when a single
89    /// glob imports a module that is itself ambiguously re-exporting the name.
90    second: Span,
91}
92
93pub(crate) fn resolve_crate(genv: GlobalEnv) -> ResolverOutput {
94    match try_resolve_crate(genv) {
95        Ok(output) => output,
96        Err(err) => genv.sess().abort(err),
97    }
98}
99
100fn try_resolve_crate(genv: GlobalEnv) -> Result<ResolverOutput> {
101    let specs = genv.collect_specs();
102    let mut resolver = CrateResolver::new(genv, specs);
103
104    genv.tcx().hir_walk_toplevel_module(&mut resolver);
105
106    resolver.into_output()
107}
108
109pub(crate) struct CrateResolver<'genv, 'tcx> {
110    genv: GlobalEnv<'genv, 'tcx>,
111    specs: &'genv Specs,
112    output: ResolverOutput,
113    ribs: PerNS<Vec<Rib>>,
114    /// A mapping from the names of all imported crates to their [`DefId`]
115    crates: UnordMap<Symbol, DefId>,
116    /// Names available everywhere: Rust builtin types plus flux's global funcs (theory funcs, `cast`)
117    /// and primitive sorts.
118    prelude: PerNS<Rib>,
119    qualifiers: UnordMap<Symbol, FluxLocalDefId>,
120    primop_props: UnordMap<Symbol, FluxDefId>,
121    err: Option<ErrorGuaranteed>,
122    /// The most recent module we have visited. Used to check for visibility of other items from
123    /// this module.
124    current_module: OwnerId,
125}
126
127/// Map to keep track of names defined in a scope
128#[derive(Default)]
129struct DefinitionMap {
130    defined: UnordMap<Ident, ()>,
131}
132
133impl DefinitionMap {
134    fn define(&mut self, name: Ident) -> std::result::Result<(), errors::DuplicateDefinition> {
135        match self.defined.entry(name) {
136            hash_map::Entry::Occupied(entry) => {
137                Err(errors::DuplicateDefinition {
138                    span: name.span,
139                    previous_definition: entry.key().span,
140                    name: name.name,
141                })
142            }
143            hash_map::Entry::Vacant(entry) => {
144                entry.insert(());
145                Ok(())
146            }
147        }
148    }
149}
150
151impl<'genv, 'tcx> CrateResolver<'genv, 'tcx> {
152    pub fn new(genv: GlobalEnv<'genv, 'tcx>, specs: &'genv Specs) -> Self {
153        Self {
154            genv,
155            output: ResolverOutput::default(),
156            specs,
157            ribs: PerNS { type_ns: vec![], value_ns: vec![], macro_ns: vec![], flux_fn_ns: vec![] },
158            crates: mk_crate_mapping(genv.tcx()),
159            prelude: PerNS {
160                type_ns: builtin_types_rib(),
161                value_ns: Rib::new(RibKind::Misc),
162                macro_ns: Rib::new(RibKind::Misc),
163                flux_fn_ns: theory_funcs_rib(),
164            },
165            err: None,
166            qualifiers: Default::default(),
167            primop_props: Default::default(),
168            current_module: CRATE_OWNER_ID,
169        }
170    }
171
172    /// Qualifiers and primop-props are global, so their names are checked for duplicates across
173    /// the whole crate (unlike other flux items, which are scoped to the module or block declaring
174    /// them via [`Self::define_res_in`]).
175    #[allow(
176        clippy::disallowed_methods,
177        reason = "`flux_items_by_scope` is the source of truth for `FluxDefId`"
178    )]
179    fn define_flux_global_items(&mut self) {
180        let mut definitions = DefinitionMap::default();
181        for decls in self.specs.flux_items_by_scope.values() {
182            for FluxItemDecl { declarer, item } in decls {
183                // We are putting qualifiers, primops and axioms in the same namespace.
184                match item {
185                    surface::FluxItem::Qualifier(qual) => {
186                        let ident = qual.name;
187                        if definitions
188                            .define(ident)
189                            .emit(&self.genv)
190                            .collect_err(&mut self.err)
191                            .is_some()
192                        {
193                            let def_id = FluxLocalDefId::new(declarer.def_id, ident.name);
194                            self.qualifiers.insert(ident.name, def_id);
195                        }
196                    }
197                    surface::FluxItem::PrimOpProp(primop) => {
198                        let ident = primop.name;
199                        if definitions
200                            .define(ident)
201                            .emit(&self.genv)
202                            .collect_err(&mut self.err)
203                            .is_some()
204                        {
205                            let def_id = FluxDefId::new(declarer.to_def_id(), ident.name);
206                            self.primop_props.insert(ident.name, def_id);
207                        }
208                    }
209                    surface::FluxItem::Axiom(axiom) => {
210                        let _ = definitions
211                            .define(axiom.name)
212                            .emit(&self.genv)
213                            .collect_err(&mut self.err);
214                    }
215                    surface::FluxItem::Use(_)
216                    | surface::FluxItem::FuncDef(_)
217                    | surface::FluxItem::SortDecl(_) => {}
218                };
219            }
220        }
221    }
222
223    /// Defines the flux items declared in `scope` (a module or a block) in the innermost rib.
224    #[allow(
225        clippy::disallowed_methods,
226        reason = "`flux_items_by_scope` is the source of truth for `FluxDefId`"
227    )]
228    fn define_flux_items(&mut self, scope: hir::HirId) {
229        let Some(decls) = self.specs.flux_items_by_scope.get(&scope) else { return };
230        for FluxItemDecl { declarer, item } in decls {
231            match item {
232                surface::FluxItem::Qualifier(_)
233                | surface::FluxItem::PrimOpProp(_)
234                | surface::FluxItem::Axiom(_) => {
235                    // Already registered in `define_global_qualifiers_and_primop_props`.
236                }
237                surface::FluxItem::FuncDef(defn) => {
238                    let def_id = FluxDefId::new(declarer.to_def_id(), defn.name.name);
239                    let kind = fhir::SpecFuncKind::Def(def_id);
240                    self.define_res_in(
241                        fhir::Res::GlobalFunc(kind),
242                        ReftNS,
243                        BindingSource::Explicit(defn.name),
244                    );
245                }
246                surface::FluxItem::SortDecl(sort_decl) => {
247                    let def_id = FluxDefId::new(declarer.to_def_id(), sort_decl.name.name);
248                    self.define_res_in(
249                        fhir::Res::UserSort(def_id),
250                        TypeNS,
251                        BindingSource::Explicit(sort_decl.name),
252                    );
253                }
254                surface::FluxItem::Use(use_tree) => {
255                    // Flux's `use` has no glob form, so every name it brings in is explicit.
256                    for (ident, res, ns) in self.resolve_flux_use_tree(use_tree) {
257                        self.define_res_in(res, ns, BindingSource::Explicit(ident));
258                    }
259                }
260            }
261        }
262    }
263
264    fn define_items(&mut self, item_ids: impl IntoIterator<Item = &'tcx ItemId>) {
265        for item_id in item_ids {
266            let item = self.genv.tcx().hir_item(*item_id);
267            let def_kind = match item.kind {
268                ItemKind::Use(use_tree) => {
269                    let is_prelude = is_prelude_import(self.genv.tcx(), item);
270                    self.define_use_tree(&use_tree, &mut vec![], is_prelude, item.span);
271                    continue;
272                }
273                ItemKind::ForeignMod { items, .. } => {
274                    self.define_foreign_items(items);
275                    continue;
276                }
277                ItemKind::TyAlias(..)
278                | ItemKind::Enum(..)
279                | ItemKind::Struct(..)
280                | ItemKind::Union(..)
281                | ItemKind::Trait { .. }
282                | ItemKind::Mod(..)
283                | ItemKind::Const(..) => self.genv.def_kind(item.owner_id),
284                _ => continue,
285            };
286            if let Some(ns) = def_kind.ns().map(Namespace::from)
287                && let Some(ident) = item.kind.ident()
288            {
289                self.define_res_in(
290                    fhir::Res::Def(def_kind, item.owner_id.to_def_id()),
291                    ns,
292                    BindingSource::Explicit(ident),
293                );
294            }
295        }
296    }
297
298    fn define_foreign_items(&mut self, items: &[rustc_hir::ForeignItemId]) {
299        for item_id in items {
300            let item = self.genv.tcx().hir_foreign_item(*item_id);
301            match item.kind {
302                rustc_hir::ForeignItemKind::Type => {
303                    self.define_res_in(
304                        fhir::Res::Def(DefKind::ForeignTy, item.owner_id.to_def_id()),
305                        TypeNS,
306                        BindingSource::Explicit(item.ident),
307                    );
308                }
309                rustc_hir::ForeignItemKind::Fn(..) | rustc_hir::ForeignItemKind::Static(..) => {}
310            }
311        }
312    }
313
314    /// Define the name in `source` in the innermost rib of `ns`.
315    fn define_res_in(
316        &mut self,
317        res: fhir::Res<surface::NodeId>,
318        ns: Namespace,
319        source: BindingSource,
320    ) {
321        let ident = source.ident();
322        if ident.name == kw::Underscore {
323            return;
324        }
325        let entry = self.ribs[ns]
326            .last_mut()
327            .unwrap()
328            .bindings
329            .entry(ident.name)
330            .or_default();
331
332        if let Some(prev) = entry.define(source, res) {
333            if let fhir::Res::Param(..) = prev.res {
334                self.emit(errors::DuplicateParam {
335                    span: ident.span,
336                    name: ident.name,
337                    first_use: prev.span,
338                });
339            } else {
340                self.emit(errors::DuplicateDefinition {
341                    span: ident.span,
342                    previous_definition: prev.span,
343                    name: ident.name,
344                });
345            }
346        }
347    }
348
349    /// Define `ident` in the prelude of `ns`. The prelude is only ever populated from the single
350    /// `#[prelude_import]` glob, so unlike [`Self::define_res_in`] it keeps plain last-one-wins
351    /// semantics: there is no second glob to be ambiguous with.
352    fn define_in_prelude(&mut self, ident: Ident, res: fhir::Res<surface::NodeId>, ns: Namespace) {
353        self.prelude[ns]
354            .bindings
355            .insert(ident.name, NameResolution::from_explicit(Binding { span: ident.span, res }));
356    }
357
358    fn push_rib(&mut self, ns: Namespace, kind: RibKind) {
359        self.ribs[ns].push(Rib::new(kind));
360    }
361
362    fn pop_rib(&mut self, ns: Namespace) {
363        self.ribs[ns].pop();
364    }
365
366    fn define_generics(&mut self, def_id: MaybeExternId<OwnerId>) {
367        let generics = self
368            .genv
369            .tcx()
370            .hir_get_generics(def_id.local_id().def_id)
371            .unwrap();
372        for param in generics.params {
373            let def_kind = self.genv.tcx().def_kind(param.def_id);
374            if let ParamName::Plain(name) = param.name
375                && let Some(ns) = def_kind.ns().map(Namespace::from)
376            {
377                debug_assert!(matches!(def_kind, DefKind::TyParam | DefKind::ConstParam));
378                let param_id = self.genv.maybe_extern_id(param.def_id).resolved_id();
379                self.define_res_in(
380                    fhir::Res::Def(def_kind, param_id),
381                    ns,
382                    BindingSource::Explicit(name),
383                );
384            }
385        }
386    }
387
388    fn resolve_flux_items(&mut self, scope: hir::HirId) {
389        let Some(decls) = self.specs.flux_items_by_scope.get(&scope) else { return };
390        for ns in [TypeNS, ValueNS, ReftNS] {
391            self.push_rib(ns, RibKind::Item);
392        }
393        for FluxItemDecl { item, .. } in decls {
394            self.resolve_flux_item(item, MaybeExternId::Local(scope.owner))
395                .collect_err(&mut self.err);
396        }
397        for ns in [TypeNS, ValueNS, ReftNS] {
398            self.pop_rib(ns);
399        }
400    }
401
402    fn resolve_flux_item(
403        &mut self,
404        item: &surface::FluxItem,
405        parent: MaybeExternId<OwnerId>,
406    ) -> Result {
407        if let surface::FluxItem::Use(_) = item {
408            // Use paths are resolved `CrateResolver::resolve_flux_use_tree`
409            return Ok(());
410        }
411        ItemResolver::run(self, parent, |vis| vis.visit_flux_item(item))?;
412        // Sort variables share the type namespace with sorts/types (see [`fhir::Namespace`]).
413        self.push_rib(TypeNS, RibKind::Misc);
414        for (idx, ident) in item.sort_vars().iter().enumerate() {
415            self.define_res_in(fhir::Res::SortParam(idx), TypeNS, BindingSource::Explicit(*ident));
416        }
417        let result =
418            RefinementResolver::run(self, Default::default(), |vis| vis.visit_flux_item(item));
419        self.pop_rib(TypeNS);
420        result
421    }
422
423    fn resolve_item(&mut self, item: &surface::Item, item_id: MaybeExternId<OwnerId>) -> Result {
424        ItemResolver::run(self, item_id, |vis| vis.visit_item(item))?;
425        let params = ImplicitParamCollector::run(self, |vis| vis.visit_item(item))?;
426        RefinementResolver::run(self, params, |vis| vis.visit_item(item))
427    }
428
429    fn resolve_trait_item(
430        &mut self,
431        item: &surface::TraitItemFn,
432        item_id: MaybeExternId<OwnerId>,
433    ) -> Result {
434        ItemResolver::run(self, item_id, |vis| vis.visit_trait_item(item))?;
435        let params = ImplicitParamCollector::run(self, |vis| vis.visit_trait_item(item))?;
436        RefinementResolver::run(self, params, |vis| vis.visit_trait_item(item))
437    }
438
439    fn resolve_impl_item(
440        &mut self,
441        item: &surface::ImplItemFn,
442        item_id: MaybeExternId<OwnerId>,
443    ) -> Result {
444        ItemResolver::run(self, item_id, |vis| vis.visit_impl_item(item))?;
445        let params = ImplicitParamCollector::run(self, |vis| vis.visit_impl_item(item))?;
446        RefinementResolver::run(self, params, |vis| vis.visit_impl_item(item))
447    }
448
449    fn resolve_path_with_ribs<S: Segment>(
450        &mut self,
451        segments: &[S],
452        ns: Namespace,
453    ) -> std::result::Result<fhir::PartialRes<surface::NodeId>, ResolveError> {
454        let result = self.resolve_path_with_ribs_inner(segments, ns);
455        let fallback = match &result {
456            Ok(res) => matches!(res.full_res(), Some(fhir::Res::Def(DefKind::Mod, _))),
457            Err(ResolveError::NotFound) => true,
458            Err(ResolveError::Ambiguous(_) | ResolveError::OuterGeneric(_)) => false,
459        };
460        // Retry a primitive when ordinary lookup finds a module or fails.
461        // See: https://github.com/rust-lang/rust/blob/12c4d3f34dcb4715784d2fa0e8443853e0592194/compiler/rustc_resolve/src/late.rs#L5069-L5071
462        if fallback
463            && (ns == TypeNS || (ns == ValueNS && segments.len() > 1))
464            && let Some(first) = segments.first()
465        {
466            let name = first.ident().name;
467            let prim = PrimTy::from_name(name).map(fhir::Res::PrimTy).or_else(|| {
468                fhir::PrimSort::ALL
469                    .into_iter()
470                    .find(|sort| sort.name() == name)
471                    .map(fhir::Res::PrimSort)
472            });
473            if let Some(res) = prim {
474                S::record_segment_res(self, first, res);
475                return Ok(fhir::PartialRes::with_unresolved_segments(res, segments.len() - 1));
476            }
477        }
478        result
479    }
480
481    /// Ordinary path lookup, also used for imports where modules must not become primitives.
482    fn resolve_path_with_ribs_inner<S: Segment>(
483        &mut self,
484        segments: &[S],
485        ns: Namespace,
486    ) -> std::result::Result<fhir::PartialRes<surface::NodeId>, ResolveError> {
487        let mut module: Option<Module> = None;
488        for (segment_idx, segment) in segments.iter().enumerate() {
489            let is_last = segment_idx + 1 == segments.len();
490            let ns = if is_last { ns } else { TypeNS };
491
492            let base_res = if let Some(module) = module {
493                self.resolve_ident_in_module(module, segment.ident(), ns)?
494            } else {
495                self.resolve_ident_with_ribs(segment.ident(), ns)?
496            };
497
498            S::record_segment_res(self, segment, base_res);
499
500            if is_last {
501                return Ok(fhir::PartialRes::new(base_res));
502            }
503
504            match base_res {
505                fhir::Res::Def(DefKind::Mod, module_id) => {
506                    module = Some(Module::new(ModuleKind::Mod, module_id));
507                }
508                fhir::Res::Def(DefKind::Trait, module_id) => {
509                    module = Some(Module::new(ModuleKind::Trait, module_id));
510                }
511                fhir::Res::Def(DefKind::Enum, module_id) => {
512                    module = Some(Module::new(ModuleKind::Enum, module_id));
513                }
514                _ => {
515                    return Ok(fhir::PartialRes::with_unresolved_segments(
516                        base_res,
517                        segments.len() - segment_idx - 1,
518                    ));
519                }
520            }
521        }
522        Err(ResolveError::NotFound)
523    }
524
525    fn resolve_flux_use_tree(
526        &mut self,
527        use_tree: &surface::UseTree,
528    ) -> Vec<(Ident, fhir::Res<surface::NodeId>, Namespace)> {
529        self.resolve_flux_use_tree_rec(use_tree, None, &mut vec![])
530    }
531
532    fn resolve_flux_use_tree_rec(
533        &mut self,
534        use_tree: &surface::UseTree,
535        mut resolved_module_id: Option<DefId>,
536        resolved_prefix: &mut Vec<Ident>,
537    ) -> Vec<(Ident, fhir::Res<surface::NodeId>, Namespace)> {
538        let Some((last, all_but_last)) = use_tree.prefix.segments.split_last() else {
539            bug!("path must have at least one segment")
540        };
541        let module_segments = match &use_tree.kind {
542            surface::UseTreeKind::Simple => all_but_last,
543            surface::UseTreeKind::Nested(_) => &use_tree.prefix.segments[..],
544        };
545
546        for segment in module_segments {
547            let ident = segment.ident();
548            let res = if let Some(module_id) = resolved_module_id {
549                let module = Module::new(ModuleKind::Mod, module_id);
550                self.resolve_ident_in_module(module, ident, TypeNS)
551            } else {
552                self.resolve_ident_with_ribs(ident, TypeNS)
553            };
554            let res = match res {
555                Ok(res) => res,
556                Err(err) => {
557                    self.emit_resolve_err(err, || {
558                        errors::UnresolvedImport::new(ident, resolved_module_id, resolved_prefix)
559                    });
560                    return vec![];
561                }
562            };
563            if let fhir::Res::Def(DefKind::Mod, def_id) = res {
564                resolved_module_id = Some(def_id);
565            } else {
566                self.emit_not_a_module(ident, resolved_prefix);
567                return vec![];
568            }
569            resolved_prefix.push(ident);
570        }
571
572        match &use_tree.kind {
573            surface::UseTreeKind::Simple => {
574                let mut resolutions = vec![];
575                // An import names an item in every namespace at once, so an ambiguity in any one
576                // of them is an error even if the others resolve. Keeping only the first means one
577                // import is one error.
578                let mut error = None;
579                for ns in [TypeNS, ValueNS, ReftNS] {
580                    let res = if let Some(module_id) = resolved_module_id {
581                        let module = Module::new(ModuleKind::Mod, module_id);
582                        self.resolve_ident_in_module(module, last.ident(), ns)
583                    } else {
584                        self.resolve_ident_with_ribs(last.ident(), ns)
585                    };
586                    match res {
587                        Ok(res) => resolutions.push((last.ident(), res, ns)),
588                        Err(ResolveError::NotFound) => {}
589                        Err(err) => error = error.or(Some(err)),
590                    }
591                }
592                if resolutions.is_empty() {
593                    error = error.or(Some(ResolveError::NotFound));
594                }
595                if let Some(err) = error {
596                    self.emit_resolve_err(err, || {
597                        errors::UnresolvedImport::new(
598                            last.ident,
599                            resolved_module_id,
600                            resolved_prefix,
601                        )
602                    });
603                }
604                resolutions
605            }
606            surface::UseTreeKind::Nested(items) => {
607                let mut resolutions = vec![];
608                for item in items {
609                    let len = resolved_prefix.len();
610                    resolutions.extend(self.resolve_flux_use_tree_rec(
611                        item,
612                        resolved_module_id,
613                        resolved_prefix,
614                    ));
615                    resolved_prefix.truncate(len);
616                }
617                resolutions
618            }
619        }
620    }
621
622    fn resolve_ident_with_ribs(
623        &self,
624        ident: Ident,
625        ns: Namespace,
626    ) -> std::result::Result<fhir::Res<surface::NodeId>, ResolveError> {
627        let mut ribs = self.ribs[ns].iter().rev();
628        let mut crossed_item = false;
629        while let Some(rib) = ribs.next() {
630            // An ambiguous name is still a name: it stops the climb here rather than falling
631            // through to outer scopes or the prelude.
632            if let Some(name_res) = rib.bindings.get(&ident.name)
633                && let Some(res) = name_res.resolve(ident)
634            {
635                // Like in rust, nested items cannot mention generics of outer items
636                let res = res.map_err(ResolveError::Ambiguous)?;
637                if crossed_item
638                    && matches!(
639                        res,
640                        fhir::Res::Def(DefKind::TyParam | DefKind::ConstParam, _)
641                            | fhir::Res::SelfTyParam { .. }
642                            | fhir::Res::SelfTyAlias { .. }
643                    )
644                {
645                    return Err(ResolveError::OuterGeneric(ident.span));
646                }
647                return Ok(res);
648            }
649            match rib.kind {
650                // A module boundary stops item resolution.
651                RibKind::Module => break,
652                RibKind::Item => crossed_item = true,
653                // A variant is a barrier that hides refinement params bound in the `refined_by` *enclosing*
654                // scope, but not other refinement bindings in other scopes (e.g. flux funcs in the parent module).
655                // FIXME: this is skipping potential names defined inside a `const _ = { ... }` or other similar
656                // "transparent modules".
657                RibKind::Variant => {
658                    ribs.take_while_ref(|rib| !matches!(rib.kind, RibKind::Module))
659                        .for_each(drop);
660                }
661                _ => {}
662            }
663        }
664        if ns == TypeNS {
665            if let Some(crate_id) = self.crates.get(&ident.name) {
666                return Ok(fhir::Res::Def(DefKind::Mod, *crate_id));
667            }
668            // FIXME: `crate`, `self` and `super` should only be allowed as the first segment
669            if ident.name == kw::Crate {
670                return Ok(fhir::Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()));
671            }
672            if ident.name == kw::SelfLower {
673                return Ok(fhir::Res::Def(DefKind::Mod, self.current_module.to_def_id()));
674            }
675            if ident.name == kw::Super
676                && let Some(parent) = self.genv.tcx().opt_local_parent(self.current_module.def_id)
677            {
678                return Ok(fhir::Res::Def(DefKind::Mod, parent.to_def_id()));
679            }
680        }
681
682        if let Some(name_res) = self.prelude[ns].bindings.get(&ident.name)
683            && let Some(res) = name_res.resolve(ident)
684        {
685            return res.map_err(ResolveError::Ambiguous);
686        }
687        Err(ResolveError::NotFound)
688    }
689
690    /// Defines the names brought into scope by a `use` tree. `prefix` accumulates the segments of
691    /// the enclosing nested trees, because the path of a nested tree is relative to its parent.
692    fn define_use_tree(
693        &mut self,
694        use_tree: &hir::UseTree<'tcx>,
695        prefix: &mut Vec<hir::PathSegment<'tcx>>,
696        is_prelude: bool,
697        glob_span: Span,
698    ) {
699        let path = use_tree.prefix;
700        match use_tree.kind {
701            hir::UseKind::Single(mut ident) => {
702                // For a nested `self` import, e.g., `use foo::{self}`, rustc doesn't strip the
703                // `self` because the path of the nested tree is relative. The name it defines is
704                // the last segment of the enclosing prefix (`foo`).
705                if ident.name == kw::SelfLower
706                    && let Some(last) = prefix.last()
707                {
708                    ident = Ident::new(last.ident.name, ident.span);
709                }
710                if let Some(res) = path.res.value_ns
711                    && let Ok(res) = fhir::Res::try_from(res)
712                {
713                    self.define_res_in(res, ValueNS, BindingSource::Explicit(ident));
714                }
715                if let Some(res) = path.res.type_ns
716                    && let Ok(res) = fhir::Res::try_from(res)
717                {
718                    self.define_res_in(res, TypeNS, BindingSource::Explicit(ident));
719                }
720            }
721            hir::UseKind::Glob => {
722                let len = prefix.len();
723                prefix.extend_from_slice(path.segments);
724                for mod_child in self.glob_imports(prefix) {
725                    if let Ok(res) = fhir::Res::try_from(mod_child.res)
726                        && let Some(ns @ (TypeNS | ValueNS)) = res.ns()
727                    {
728                        if is_prelude {
729                            self.define_in_prelude(mod_child.ident, res, ns);
730                        } else {
731                            let source = BindingSource::Glob { ident: mod_child.ident, glob_span };
732                            self.define_res_in(res, ns, source);
733                        }
734                    }
735                }
736                prefix.truncate(len);
737            }
738            hir::UseKind::Nested { items } => {
739                let len = prefix.len();
740                prefix.extend_from_slice(path.segments);
741                for (nested, _, _) in items {
742                    self.define_use_tree(nested, prefix, is_prelude, glob_span);
743                }
744                prefix.truncate(len);
745            }
746        }
747    }
748
749    fn glob_imports(
750        &mut self,
751        segments: &[hir::PathSegment<'tcx>],
752    ) -> impl Iterator<Item = &'tcx ModChild> + use<'tcx> {
753        // The path for the prelude import is not resolved anymore after <https://github.com/rust-lang/rust/pull/145322>,
754        // so we resolve all paths here. If this ever causes problems, we could use the resolution in the `UsePath` for
755        // non-prelude glob imports.
756        let tcx = self.genv.tcx();
757        let curr_mod = self.current_module.to_def_id();
758        self.resolve_path_with_ribs_inner(segments, TypeNS)
759            .ok()
760            .and_then(|partial_res| partial_res.full_res())
761            .and_then(|res| {
762                if let fhir::Res::Def(DefKind::Mod, module_id) = res {
763                    Some(module_id)
764                } else {
765                    None
766                }
767            })
768            .into_iter()
769            .flat_map(move |module_id| visible_module_children(tcx, module_id, curr_mod))
770    }
771
772    fn resolve_ident_in_module(
773        &self,
774        module: Module,
775        ident: Ident,
776        ns: Namespace,
777    ) -> std::result::Result<fhir::Res<surface::NodeId>, ResolveError> {
778        let tcx = self.genv.tcx();
779        let res = match module.kind {
780            ModuleKind::Mod => {
781                let module_id = module.def_id;
782                let current_mod = self.current_module.to_def_id();
783
784                // Three sources, tried in order, first one with the name wins: the module's Rust
785                // children, then the ambiguous ones rustc leaves out of `module_children`, then
786                // its flux items. Only the first two have a Rust namespace to look in.
787                //
788                // Keeping them apart matters because the folds below read every candidate as a
789                // glob, so one pool would make `mod m { struct Bag; defs! { opaque sort Bag; } }`
790                // ambiguous at each `m::Bag`. It isn't: two explicit definitions clash as a
791                // duplicate definition, already reported when `m`'s rib was built.
792                let mut resolution: NameResolution = ns
793                    .to_rustc()
794                    .into_iter()
795                    .flat_map(|rustc_ns| {
796                        visible_module_children(tcx, module_id, current_mod).filter(move |child| {
797                            child.res.matches_ns(rustc_ns)
798                                && tcx.hygienic_eq(ident, child.ident, current_mod)
799                        })
800                    })
801                    .filter_map(|child| {
802                        Some(Binding {
803                            span: child.ident.span,
804                            res: fhir::Res::try_from(child.res).ok()?,
805                        })
806                    })
807                    .collect();
808                if resolution.is_empty() {
809                    // Still a Rust name, so it comes before any flux item.
810                    if let Some(ambiguity) = self.ambiguous_module_child(module_id, ident, ns) {
811                        return Err(ResolveError::Ambiguous(ambiguity));
812                    }
813                    resolution = self
814                        .genv
815                        .flux_module_children(module_id)
816                        .iter()
817                        .filter(|child| {
818                            child.res.ns() == Some(ns) && child.ident.name == ident.name
819                        })
820                        .map(|child| {
821                            Binding {
822                                span: child.ident.span,
823                                res: child.res.map_param_id(|id| match id {}),
824                            }
825                        })
826                        .collect();
827                }
828                resolution.resolve(ident)
829            }
830            ModuleKind::Trait => {
831                // Associated items are Rust items, so we only ever resolve them in a Rust namespace.
832                ns.to_rustc()
833                    .and_then(|rustc_ns| {
834                        let trait_id = module.def_id;
835                        tcx.associated_items(trait_id)
836                            .find_by_ident_and_namespace(tcx, ident, rustc_ns, trait_id)
837                            .map(|assoc| fhir::Res::Def(assoc.kind.as_def_kind(), assoc.def_id))
838                    })
839                    .map(Ok)
840            }
841            ModuleKind::Enum => {
842                tcx.adt_def(module.def_id)
843                    .variants()
844                    .iter()
845                    .find(|data| data.name == ident.name)
846                    .and_then(|data| {
847                        let (kind, def_id) = match (ns, data.ctor) {
848                            (TypeNS, _) => (DefKind::Variant, data.def_id),
849                            (ValueNS, Some((ctor_kind, ctor_id))) => {
850                                (DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_id)
851                            }
852                            _ => return None,
853                        };
854                        Some(fhir::Res::Def(kind, def_id))
855                    })
856                    .map(Ok)
857            }
858        };
859        match res {
860            Some(res) => res.map_err(ResolveError::Ambiguous),
861            None => Err(ResolveError::NotFound),
862        }
863    }
864
865    /// The ambiguity for `ident` in `module_id`, if the module's *own* glob re-exports bind the
866    /// name to two different items (`mod m { pub use a::*; pub use b::*; }`). rustc keeps such
867    /// bindings out of `module_children` — they go into a separate `ambig_module_children` map —
868    /// so they need their own lookup.
869    ///
870    /// Only *local* modules are covered. The data for a foreign module is reachable only through an
871    /// untracked `CStore` accessor, and rustc doesn't report `E0659` across a crate boundary
872    /// anyway: it resolves to the first candidate and fires the `ambiguous_glob_imports`
873    /// future-incompatibility lint instead (see rust-lang/rust#114095). We report those as
874    /// unresolved.
875    #[expect(clippy::disallowed_methods, reason = "modules cannot have extern specs")]
876    fn ambiguous_module_child(
877        &self,
878        module_id: DefId,
879        ident: Ident,
880        ns: Namespace,
881    ) -> Option<Ambiguity> {
882        let tcx = self.genv.tcx();
883        let module_id = module_id.as_local()?;
884        let rustc_ns = ns.to_rustc()?;
885        let current_mod = self.current_module.to_def_id();
886        let child = tcx
887            .resolutions(())
888            .ambig_module_children
889            .get(&module_id)?
890            .iter()
891            .find(|child| {
892                child.main.res.matches_ns(rustc_ns)
893                    && tcx.hygienic_eq(ident, child.main.ident, current_mod)
894                    && child.main.vis.is_accessible_from(current_mod, tcx)
895            })?;
896        Some(Ambiguity {
897            span: ident.span,
898            name: ident.name,
899            first: self.glob_span(&child.main),
900            second: self.glob_span(&child.second),
901        })
902    }
903
904    /// Where a module child was brought into its module: the `use ...::*;` statement it was
905    /// re-exported by, or the item's own definition. Mirrors rustc's `child_span`.
906    fn glob_span(&self, child: &ModChild) -> Span {
907        let def_id = child
908            .reexport_chain
909            .first()
910            .and_then(|reexport| reexport.id())
911            .unwrap_or_else(|| child.res.def_id());
912        self.genv.tcx().def_span(def_id)
913    }
914
915    pub fn into_output(self) -> Result<ResolverOutput> {
916        self.err.into_result()?;
917        Ok(self.output)
918    }
919
920    #[track_caller]
921    fn emit_resolve_err<D: rustc_errors::Diagnostic<'genv>>(
922        &mut self,
923        err: ResolveError,
924        not_found: impl FnOnce() -> D,
925    ) {
926        self.err.collect(err.emit(self.genv.sess(), not_found));
927    }
928
929    fn emit_not_a_module(&mut self, ident: Ident, resolved_prefix: &[Ident]) {
930        let name = Segment::format_iter(resolved_prefix.iter().chain(&[ident]));
931        self.emit(errors::UnresolvedImport {
932            span: ident.span,
933            name,
934            reason: format!("`{ident}` is not a module"),
935        });
936    }
937
938    #[track_caller]
939    fn emit(&mut self, err: impl rustc_errors::Diagnostic<'genv>) {
940        self.err.collect(self.genv.sess().emit_err(err));
941    }
942}
943
944impl<'tcx> hir::intravisit::Visitor<'tcx> for CrateResolver<'_, 'tcx> {
945    type NestedFilter = rustc_middle::hir::nested_filter::All;
946
947    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
948        self.genv.tcx()
949    }
950
951    fn visit_mod(
952        &mut self,
953        module: &'tcx hir::Mod<'tcx>,
954        _s: Span,
955        mod_id: hir::def_id::LocalModId,
956    ) {
957        let owner_id = OwnerId { def_id: mod_id.to_local_def_id() };
958        let old_mod = self.current_module;
959        self.current_module = owner_id;
960        self.push_rib(TypeNS, RibKind::Module);
961        self.push_rib(ValueNS, RibKind::Module);
962        self.push_rib(ReftNS, RibKind::Module);
963
964        self.define_items(module.item_ids);
965
966        // Flux primops and wualifiers are made globally available as if they were defined at the top of the crate
967        if mod_id.is_top_level_module() {
968            self.define_flux_global_items();
969        }
970        // Other items are defined in the module they are declared in.
971        let scope = hir::HirId::make_owner(owner_id.def_id);
972        self.define_flux_items(scope);
973
974        self.resolve_flux_items(scope);
975        hir::intravisit::walk_mod(self, module);
976
977        self.pop_rib(ReftNS);
978        self.pop_rib(ValueNS);
979        self.pop_rib(TypeNS);
980        self.current_module = old_mod;
981    }
982
983    fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
984        self.push_rib(TypeNS, RibKind::Misc);
985        self.push_rib(ValueNS, RibKind::Misc);
986        self.push_rib(ReftNS, RibKind::Misc);
987
988        let item_ids = block.stmts.iter().filter_map(|stmt| {
989            if let hir::StmtKind::Item(item_id) = &stmt.kind { Some(item_id) } else { None }
990        });
991        self.define_items(item_ids);
992        self.define_flux_items(block.hir_id);
993
994        self.resolve_flux_items(block.hir_id);
995        hir::intravisit::walk_block(self, block);
996
997        self.pop_rib(ReftNS);
998        self.pop_rib(ValueNS);
999        self.pop_rib(TypeNS);
1000    }
1001
1002    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
1003        if self.genv.is_dummy(item.owner_id.def_id) {
1004            return;
1005        }
1006        let def_id = self
1007            .genv
1008            .maybe_extern_id(item.owner_id.def_id)
1009            .map(|def_id| OwnerId { def_id });
1010
1011        self.push_rib(TypeNS, RibKind::Item);
1012        self.push_rib(ValueNS, RibKind::Item);
1013
1014        match item.kind {
1015            ItemKind::Trait { .. } => {
1016                self.define_generics(def_id);
1017                self.define_res_in(
1018                    fhir::Res::SelfTyParam { trait_: def_id.resolved_id() },
1019                    TypeNS,
1020                    BindingSource::Explicit(Ident::with_dummy_span(kw::SelfUpper)),
1021                );
1022            }
1023            ItemKind::Impl(hir::Impl { of_trait, .. }) => {
1024                self.define_generics(def_id);
1025                self.define_res_in(
1026                    fhir::Res::SelfTyAlias {
1027                        alias_to: def_id.resolved_id(),
1028                        is_trait_impl: of_trait.is_some(),
1029                    },
1030                    TypeNS,
1031                    BindingSource::Explicit(Ident::with_dummy_span(kw::SelfUpper)),
1032                );
1033            }
1034            ItemKind::TyAlias(..) => {
1035                self.define_generics(def_id);
1036            }
1037            ItemKind::Enum(..) => {
1038                self.define_generics(def_id);
1039                self.define_res_in(
1040                    fhir::Res::SelfTyAlias { alias_to: def_id.resolved_id(), is_trait_impl: false },
1041                    TypeNS,
1042                    BindingSource::Explicit(Ident::with_dummy_span(kw::SelfUpper)),
1043                );
1044            }
1045            ItemKind::Struct(..) => {
1046                self.define_generics(def_id);
1047                self.define_res_in(
1048                    fhir::Res::SelfTyAlias { alias_to: def_id.resolved_id(), is_trait_impl: false },
1049                    TypeNS,
1050                    BindingSource::Explicit(Ident::with_dummy_span(kw::SelfUpper)),
1051                );
1052            }
1053            ItemKind::Fn { .. } => {
1054                self.define_generics(def_id);
1055            }
1056            _ => {}
1057        }
1058        if let Some(item) = self.specs.get_item(def_id.local_id()) {
1059            self.resolve_item(item, def_id).collect_err(&mut self.err);
1060        }
1061
1062        hir::intravisit::walk_item(self, item);
1063
1064        self.pop_rib(ValueNS);
1065        self.pop_rib(TypeNS);
1066    }
1067
1068    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
1069        let def_id = self
1070            .genv
1071            .maybe_extern_id(impl_item.owner_id.def_id)
1072            .map(|def_id| OwnerId { def_id });
1073
1074        // Generics are defined in both namespaces (const params live in the value namespace), so
1075        // we need a rib in each to avoid leaking them into sibling items.
1076        self.push_rib(TypeNS, RibKind::Misc);
1077        self.push_rib(ValueNS, RibKind::Misc);
1078        if let Some(item) = self.specs.get_impl_item(def_id.local_id()) {
1079            self.define_generics(def_id);
1080            self.resolve_impl_item(item, def_id)
1081                .collect_err(&mut self.err);
1082        }
1083        hir::intravisit::walk_impl_item(self, impl_item);
1084        self.pop_rib(ValueNS);
1085        self.pop_rib(TypeNS);
1086    }
1087
1088    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
1089        let def_id = self
1090            .genv
1091            .maybe_extern_id(trait_item.owner_id.def_id)
1092            .map(|def_id| OwnerId { def_id });
1093
1094        // Generics are defined in both namespaces (const params live in the value namespace), so
1095        // we need a rib in each to avoid leaking them into sibling items.
1096        self.push_rib(TypeNS, RibKind::Misc);
1097        self.push_rib(ValueNS, RibKind::Misc);
1098        if let Some(item) = self.specs.get_trait_item(def_id.local_id()) {
1099            self.define_generics(def_id);
1100            self.resolve_trait_item(item, def_id)
1101                .collect_err(&mut self.err);
1102        }
1103        hir::intravisit::walk_trait_item(self, trait_item);
1104        self.pop_rib(ValueNS);
1105        self.pop_rib(TypeNS);
1106    }
1107}
1108
1109/// Akin to `rustc_resolve::Module` but specialized to what we support
1110#[derive(Clone, Copy, Debug)]
1111struct Module {
1112    kind: ModuleKind,
1113    def_id: DefId,
1114}
1115
1116impl Module {
1117    fn new(kind: ModuleKind, def_id: DefId) -> Self {
1118        Self { kind, def_id }
1119    }
1120}
1121
1122/// Akin to `rustc_resolve::ModuleKind` but specialized to what we support
1123#[derive(Clone, Copy, Debug)]
1124enum ModuleKind {
1125    Mod,
1126    Trait,
1127    Enum,
1128}
1129
1130#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1131pub(crate) enum RibKind {
1132    /// An rib with no special rules.
1133    Misc,
1134    /// A module boundary. This is a barrier for item resolution.
1135    Module,
1136    /// An item boundary. Generic parameters (and `Self`) of outer items are not visible past it.
1137    Item,
1138    /// An enum variant. This is a barrier scope because variants are nested within `refined_by`
1139    /// params.
1140    Variant,
1141}
1142
1143/// The value stored for each binding in a [`Rib`]. Lookups and clash detection are keyed by the
1144/// name in the [`Rib`]'s map, so all a binding carries is where it came from, for diagnostics that
1145/// point at the previous location of a name.
1146#[derive(Clone, Copy, Debug)]
1147struct Binding {
1148    /// Where the name was brought into scope: the item, generic or param itself, or, for a
1149    /// glob-imported binding, the `use ...::*;` statement rather than the imported item's
1150    /// declaration, matching where rustc points its `E0659` notes.
1151    span: Span,
1152    res: fhir::Res<surface::NodeId>,
1153}
1154
1155/// How a name was brought into a rib. Explicit definitions (items, generics, params, single
1156/// `use`s, flux `use`s) shadow glob imports of the same name in the same namespace, regardless of
1157/// declaration order; only globs can be ambiguous with each other.
1158#[derive(Clone, Copy, Debug)]
1159enum BindingSource {
1160    /// A name written where it is defined: an item, generic, param or single `use`.
1161    Explicit(Ident),
1162    /// A glob-imported name: the imported item's ident, plus the span of the `use ...::*;`
1163    /// statement that brought it in, which is the one diagnostics cite.
1164    Glob { ident: Ident, glob_span: Span },
1165}
1166
1167impl BindingSource {
1168    fn ident(self) -> Ident {
1169        match self {
1170            BindingSource::Explicit(ident) | BindingSource::Glob { ident, .. } => ident,
1171        }
1172    }
1173
1174    /// Where the name was brought into scope.
1175    fn span(self) -> Span {
1176        match self {
1177            BindingSource::Explicit(ident) => ident.span,
1178            BindingSource::Glob { glob_span, .. } => glob_span,
1179        }
1180    }
1181}
1182
1183/// The glob-imported candidate(s) for a name, mirroring rustc's `glob_decl` slot.
1184#[derive(Clone, Copy, Debug)]
1185enum GlobBinding {
1186    Single(Binding),
1187    /// Two competing globs bound this name to different items. Frozen once set: further
1188    /// candidates never change it. We deliberately diverge from rustc here, which keeps updating
1189    /// the second span as new distinct competitors show up; with three or more globs we therefore
1190    /// report the first two rather than the first and the last.
1191    Ambiguous(Span, Span),
1192}
1193
1194/// All candidates for a single name in a single namespace, split into the two slots
1195/// (`non_glob_decl`/`glob_decl`). The non-glob slot always wins.
1196#[derive(Clone, Copy, Debug, Default)]
1197struct NameResolution {
1198    non_glob: Option<Binding>,
1199    glob: Option<GlobBinding>,
1200}
1201
1202impl NameResolution {
1203    fn from_explicit(binding: Binding) -> Self {
1204        Self { non_glob: Some(binding), glob: None }
1205    }
1206
1207    fn is_empty(&self) -> bool {
1208        self.non_glob.is_none() && self.glob.is_none()
1209    }
1210
1211    /// Define the binding. Return previously defined binding if there's a clash
1212    fn define(
1213        &mut self,
1214        source: BindingSource,
1215        res: fhir::Res<surface::NodeId>,
1216    ) -> Option<Binding> {
1217        let binding = Binding { span: source.span(), res };
1218        match source {
1219            BindingSource::Explicit(_) => {
1220                if let Some(prev) = self.non_glob {
1221                    Some(prev)
1222                } else {
1223                    self.non_glob = Some(binding);
1224                    None
1225                }
1226            }
1227            BindingSource::Glob { .. } => {
1228                self.add_glob(binding);
1229                None
1230            }
1231        }
1232    }
1233
1234    /// Fold one more glob candidate into the glob slot. A candidate resolving to the same item as
1235    /// the one already recorded (the same item reached through two different globs) is not an
1236    /// ambiguity.
1237    fn add_glob(&mut self, binding: Binding) {
1238        self.glob = Some(match self.glob {
1239            None => GlobBinding::Single(binding),
1240            Some(GlobBinding::Single(prev)) => {
1241                if prev.res == binding.res {
1242                    GlobBinding::Single(prev)
1243                } else {
1244                    GlobBinding::Ambiguous(prev.span, binding.span)
1245                }
1246            }
1247            Some(ambiguous @ GlobBinding::Ambiguous(..)) => ambiguous,
1248        });
1249    }
1250
1251    /// The resolution for `ident`, or `None` if this holds no candidate at all (in which case the
1252    /// caller should keep looking in outer scopes).
1253    fn resolve(
1254        &self,
1255        ident: Ident,
1256    ) -> Option<std::result::Result<fhir::Res<surface::NodeId>, Ambiguity>> {
1257        if let Some(binding) = self.non_glob {
1258            return Some(Ok(binding.res));
1259        }
1260        match self.glob? {
1261            GlobBinding::Single(binding) => Some(Ok(binding.res)),
1262            GlobBinding::Ambiguous(first, second) => {
1263                Some(Err(Ambiguity { span: ident.span, name: ident.name, first, second }))
1264            }
1265        }
1266    }
1267}
1268
1269impl FromIterator<Binding> for NameResolution {
1270    /// Fold a stream of *glob* candidates. Used to merge a module's children, where two entries
1271    /// for the same name can only come from an ambiguous glob re-export.
1272    fn from_iter<T: IntoIterator<Item = Binding>>(iter: T) -> Self {
1273        let mut resolution = Self::default();
1274        for binding in iter {
1275            resolution.add_glob(binding);
1276        }
1277        resolution
1278    }
1279}
1280
1281#[derive(Debug)]
1282struct Rib {
1283    kind: RibKind,
1284    bindings: UnordMap<Symbol, NameResolution>,
1285}
1286
1287impl Rib {
1288    fn new(kind: RibKind) -> Self {
1289        Self { kind, bindings: Default::default() }
1290    }
1291}
1292
1293fn module_children(tcx: TyCtxt<'_>, def_id: DefId) -> &[ModChild] {
1294    #[expect(clippy::disallowed_methods, reason = "modules cannot have extern specs")]
1295    if let Some(local_id) = def_id.as_local() {
1296        tcx.module_children_local(local_id)
1297    } else {
1298        tcx.module_children(def_id)
1299    }
1300}
1301
1302/// Iterator over module children visible form `curr_mod`
1303fn visible_module_children(
1304    tcx: TyCtxt<'_>,
1305    module_id: DefId,
1306    curr_mod: DefId,
1307) -> impl Iterator<Item = &ModChild> {
1308    module_children(tcx, module_id)
1309        .iter()
1310        .filter(move |child| child.vis.is_accessible_from(curr_mod, tcx))
1311}
1312
1313/// Return true if the item has a `#[prelude_import]` annotation
1314fn is_prelude_import(tcx: TyCtxt, item: &hir::Item) -> bool {
1315    tcx.hir_attrs(item.hir_id()).iter().any(|attr| {
1316        matches!(
1317            attr,
1318            rustc_attr_ir::Attribute::Parsed(rustc_attr_ir::AttributeKind::PreludeImport)
1319        )
1320    })
1321}
1322
1323/// Abstraction over a "segment" so we can use [`CrateResolver::resolve_path_with_ribs`] with paths
1324/// from different sources  (e.g., [`surface::PathSegment`], [`surface::ExprPathSegment`])
1325pub(crate) trait Segment: std::fmt::Debug {
1326    fn record_segment_res(
1327        resolver: &mut CrateResolver,
1328        segment: &Self,
1329        res: fhir::Res<surface::NodeId>,
1330    );
1331    fn ident(&self) -> Ident;
1332
1333    fn format_iter<'a>(segments: impl IntoIterator<Item = &'a Self>) -> String
1334    where
1335        Self: Sized + 'a,
1336    {
1337        segments.into_iter().map(|s| s.ident()).join("::")
1338    }
1339}
1340
1341impl Segment for surface::PathSegment {
1342    fn record_segment_res(
1343        resolver: &mut CrateResolver,
1344        segment: &Self,
1345        res: fhir::Res<surface::NodeId>,
1346    ) {
1347        resolver
1348            .output
1349            .path_res_map
1350            .insert(segment.node_id, fhir::PartialRes::new(res));
1351    }
1352
1353    fn ident(&self) -> Ident {
1354        self.ident
1355    }
1356}
1357
1358impl Segment for surface::ExprPathSegment {
1359    fn record_segment_res(
1360        resolver: &mut CrateResolver,
1361        segment: &Self,
1362        res: fhir::Res<surface::NodeId>,
1363    ) {
1364        resolver
1365            .output
1366            .path_res_map
1367            .insert(segment.node_id, fhir::PartialRes::new(res));
1368    }
1369
1370    fn ident(&self) -> Ident {
1371        self.ident
1372    }
1373}
1374
1375impl Segment for Ident {
1376    fn record_segment_res(
1377        _resolver: &mut CrateResolver,
1378        _segment: &Self,
1379        _res: fhir::Res<surface::NodeId>,
1380    ) {
1381    }
1382
1383    fn ident(&self) -> Ident {
1384        *self
1385    }
1386}
1387
1388impl Segment for hir::PathSegment<'_> {
1389    fn record_segment_res(
1390        _resolver: &mut CrateResolver,
1391        _segment: &Self,
1392        _res: fhir::Res<surface::NodeId>,
1393    ) {
1394    }
1395
1396    fn ident(&self) -> Ident {
1397        self.ident
1398    }
1399}
1400
1401struct ItemResolver<'a, 'genv, 'tcx> {
1402    resolver: &'a mut CrateResolver<'genv, 'tcx>,
1403    errors: Errors<'genv>,
1404    item_id: MaybeExternId<OwnerId>,
1405}
1406
1407impl<'a, 'genv, 'tcx> ItemResolver<'a, 'genv, 'tcx> {
1408    fn run(
1409        resolver: &'a mut CrateResolver<'genv, 'tcx>,
1410        item_id: MaybeExternId<OwnerId>,
1411        f: impl FnOnce(&mut ItemResolver),
1412    ) -> Result {
1413        let mut item_resolver = ItemResolver::new(resolver, item_id);
1414        f(&mut item_resolver);
1415        item_resolver.errors.into_result()
1416    }
1417
1418    fn new(resolver: &'a mut CrateResolver<'genv, 'tcx>, item_id: MaybeExternId<OwnerId>) -> Self {
1419        let errors = Errors::new(resolver.genv.sess());
1420        Self { resolver, errors, item_id }
1421    }
1422
1423    fn resolve_path_in(&mut self, ns: Namespace, path: &surface::Path) {
1424        match self.resolver.resolve_path_with_ribs(&path.segments, ns) {
1425            Ok(partial_res) => {
1426                self.resolver
1427                    .output
1428                    .path_res_map
1429                    .insert(path.node_id, partial_res);
1430            }
1431            Err(err) => {
1432                err.emit(&self.errors, || {
1433                    errors::UnresolvedName::new(path.span, &path.segments, ns.descr())
1434                });
1435            }
1436        }
1437    }
1438
1439    fn resolve_attrs(&mut self, node_id: surface::NodeId, attrs: &[surface::Attr]) {
1440        for attr in attrs {
1441            match attr {
1442                surface::Attr::Qualifiers(names) => self.resolve_qualifiers(node_id, names),
1443                surface::Attr::Reveal(names) => {
1444                    let reveals = self.resolve_func_defs(names);
1445                    self.resolver.output.reveal_res_map.insert(node_id, reveals);
1446                }
1447                surface::Attr::Hide(names) => {
1448                    let hides = self.resolve_func_defs(names);
1449                    self.resolver.output.hide_res_map.insert(node_id, hides);
1450                }
1451                surface::Attr::AssumeParametric(names) => {
1452                    self.resolve_parametric_params(node_id, names);
1453                }
1454                _ => {}
1455            }
1456        }
1457    }
1458
1459    fn resolve_parametric_params(&mut self, node_id: surface::NodeId, names: &[Ident]) {
1460        let tcx = self.resolver.genv.tcx();
1461        let generics = tcx.generics_of(self.item_id.resolved_id());
1462        let param_map: UnordMap<Symbol, DefId> = (0..generics.count())
1463            .map(|i| generics.param_at(i, tcx))
1464            .map(|p| (p.name, p.def_id))
1465            .collect();
1466        let mut params = Vec::with_capacity(names.len());
1467        for name in names {
1468            if let Some(&def_id) = param_map.get(&name.name) {
1469                params.push(def_id);
1470            } else {
1471                self.errors
1472                    .emit(errors::UnknownParametricParam::new(name.span));
1473            }
1474        }
1475        self.resolver
1476            .output
1477            .parametric_param_res_map
1478            .insert(node_id, params);
1479    }
1480
1481    fn resolve_qualifiers(&mut self, node_id: surface::NodeId, qual_names: &[Ident]) {
1482        let mut qualifiers = Vec::with_capacity(qual_names.len());
1483        for qual in qual_names {
1484            if let Some(def_id) = self.resolver.qualifiers.get(&qual.name) {
1485                qualifiers.push(*def_id);
1486            } else {
1487                self.errors.emit(errors::UnknownQualifier::new(qual.span));
1488            }
1489        }
1490        self.resolver
1491            .output
1492            .qualifier_res_map
1493            .insert(node_id, qualifiers);
1494    }
1495
1496    /// Resolves the names of function definitions in a `#[reveal(...)]` or `#[hide(...)]` attribute
1497    fn resolve_func_defs(&mut self, names: &[Ident]) -> Vec<(FluxDefId, Span)> {
1498        let mut def_ids = Vec::with_capacity(names.len());
1499        for name in names {
1500            match self.resolver.resolve_ident_with_ribs(*name, ReftNS) {
1501                Ok(fhir::Res::GlobalFunc(kind)) => {
1502                    if let Some(def_id) = kind.def_id() {
1503                        def_ids.push((def_id, name.span));
1504                    } else {
1505                        self.errors
1506                            .emit(errors::UnknownFuncDefinition::new(name.span));
1507                    }
1508                }
1509                Ok(_) => {
1510                    self.errors
1511                        .emit(errors::UnknownFuncDefinition::new(name.span));
1512                }
1513                Err(err) => {
1514                    err.emit(&self.errors, || errors::UnknownFuncDefinition::new(name.span));
1515                }
1516            }
1517        }
1518        def_ids
1519    }
1520}
1521
1522impl surface::visit::Visitor<'_> for ItemResolver<'_, '_, '_> {
1523    fn visit_item(&mut self, item: &surface::Item) {
1524        self.resolve_attrs(item.node_id, &item.attrs);
1525        surface::visit::walk_item(self, item);
1526    }
1527
1528    fn visit_trait_item(&mut self, item: &surface::TraitItemFn) {
1529        self.resolve_attrs(item.node_id, &item.attrs);
1530        surface::visit::walk_trait_item(self, item);
1531    }
1532
1533    fn visit_impl_item(&mut self, item: &surface::ImplItemFn) {
1534        self.resolve_attrs(item.node_id, &item.attrs);
1535        surface::visit::walk_impl_item(self, item);
1536    }
1537
1538    fn visit_trait(&mut self, trait_: &surface::Trait) {
1539        let mut definitions = DefinitionMap::default();
1540        for assoc_reft in &trait_.assoc_refinements {
1541            let _ = definitions.define(assoc_reft.name).emit(&self.errors);
1542        }
1543        surface::visit::walk_trait(self, trait_);
1544    }
1545
1546    fn visit_impl(&mut self, impl_: &surface::Impl) {
1547        let mut definitions = DefinitionMap::default();
1548        for assoc_reft in &impl_.assoc_refinements {
1549            let _ = definitions.define(assoc_reft.name).emit(&self.errors);
1550        }
1551        surface::visit::walk_impl(self, impl_);
1552    }
1553
1554    fn visit_generic_arg(&mut self, arg: &surface::GenericArg) {
1555        if let surface::GenericArgKind::Type(ty) = &arg.kind
1556            && let Some(path) = ty.is_potential_const_arg()
1557        {
1558            // We parse const arguments as path types as we cannot distinguish them during
1559            // parsing. We try to resolve that ambiguity by attempting resolution in both the
1560            // type and value namespaces. If we resolved the path in the value namespace, we
1561            // transform it into a generic const argument.
1562            // A name that is *ambiguous* in a namespace, or that is a forbidden outer generic,
1563            // still counts as present there: rerouting to the other namespace would hide the error
1564            // instead of reporting it. The real diagnostic comes from `resolve_path_in` below.
1565            let check_ns = |ns| {
1566                !matches!(
1567                    self.resolver.resolve_ident_with_ribs(path.last().ident, ns),
1568                    Err(ResolveError::NotFound)
1569                )
1570            };
1571
1572            if !check_ns(TypeNS) && check_ns(ValueNS) {
1573                self.resolve_path_in(ValueNS, path);
1574                return;
1575            }
1576        }
1577        surface::visit::walk_generic_arg(self, arg);
1578    }
1579
1580    fn visit_const_arg(&mut self, const_arg: &surface::ConstArg) {
1581        if let surface::ConstArgKind::Path(path) = &const_arg.kind {
1582            self.resolve_path_in(ValueNS, path);
1583            surface::visit::walk_path(self, path);
1584        }
1585    }
1586
1587    fn visit_path(&mut self, path: &surface::Path) {
1588        self.resolve_path_in(TypeNS, path);
1589        surface::visit::walk_path(self, path);
1590    }
1591}
1592
1593/// The [`Namespace::TypeNS`] prelude: builtin Rust types (`bool`, `i32`, `str`, ...) together with
1594/// the sort-only primitive sorts (`int`, `real`, `Set`, `Map`, `ptr`). Sorts and types share the
1595/// type namespace; `bool`/`char`/`str` are resolved as [`fhir::Res::PrimTy`] and their sort is
1596/// derived in `conv_sort_path` (see [`fhir::PrimSort`]).
1597fn builtin_types_rib() -> Rib {
1598    use flux_middle::fhir::PrimSort;
1599    let sorts = PrimSort::ALL.into_iter().map(|prim| {
1600        let ident = Ident::with_dummy_span(prim.name());
1601        (
1602            ident.name,
1603            NameResolution::from_explicit(Binding {
1604                span: ident.span,
1605                res: fhir::Res::PrimSort(prim),
1606            }),
1607        )
1608    });
1609    let types = PrimTy::ALL.into_iter().map(|pty| {
1610        let ident = Ident::with_dummy_span(pty.name());
1611        (
1612            ident.name,
1613            NameResolution::from_explicit(Binding {
1614                span: ident.span,
1615                res: fhir::Res::PrimTy(pty),
1616            }),
1617        )
1618    });
1619
1620    // Types go after such that they override sorts with the same name. Note this collects into a
1621    // map, so it is a plain last-one-wins overwrite, not the shadowing/ambiguity fold used for
1622    // user-written definitions.
1623    let bindings = sorts.chain(types).collect();
1624    Rib { kind: RibKind::Misc, bindings }
1625}
1626
1627/// The [`Namespace::ReftNS`] prelude: theory functions and `cast`.
1628fn theory_funcs_rib() -> Rib {
1629    let mut rib = Rib::new(RibKind::Misc);
1630    rib.bindings
1631        .extend_unord(flux_middle::THEORY_FUNCS.items().map(|(_, itf)| {
1632            let ident = Ident::with_dummy_span(itf.name);
1633            let res = fhir::Res::GlobalFunc(fhir::SpecFuncKind::Thy(itf.itf));
1634            (ident.name, NameResolution::from_explicit(Binding { span: ident.span, res }))
1635        }));
1636    let cast_ident = Ident::with_dummy_span(sym::cast);
1637    rib.bindings.insert(
1638        cast_ident.name,
1639        NameResolution::from_explicit(Binding {
1640            span: cast_ident.span,
1641            res: fhir::Res::GlobalFunc(fhir::SpecFuncKind::Cast),
1642        }),
1643    );
1644    rib
1645}
1646
1647fn mk_crate_mapping(tcx: TyCtxt) -> UnordMap<Symbol, DefId> {
1648    let mut map = UnordMap::default();
1649    for cnum in tcx.crates(()) {
1650        let name = tcx.crate_name(*cnum);
1651        if let Some(extern_crate) = tcx.extern_crate(*cnum)
1652            && extern_crate.is_direct()
1653        {
1654            map.insert(name, cnum.as_def_id());
1655        }
1656    }
1657    map
1658}
1659
1660mod errors {
1661    use flux_errors::E0999;
1662    use flux_macros::Diagnostic;
1663    use flux_syntax::surface::Ident;
1664    use rustc_span::{Span, Symbol, def_id::DefId};
1665
1666    use super::Segment;
1667
1668    /// A name that could not be resolved. `kind` is the user-facing description of what was being
1669    /// looked for (`"type"`, `"value"`, `"sort"`, ...); it is passed explicitly by each call site
1670    /// because it no longer matches the resolution [`Namespace`](flux_middle::fhir::Namespace)
1671    /// (e.g. sorts are resolved in the type namespace).
1672    #[derive(Diagnostic)]
1673    #[diag("cannot find {$kind} `{$name}` in this scope", code = E0999)]
1674    pub(crate) struct UnresolvedName {
1675        #[primary_span]
1676        #[label("not found in this scope")]
1677        span: Span,
1678        kind: &'static str,
1679        name: String,
1680    }
1681
1682    impl UnresolvedName {
1683        pub(crate) fn new<S: Segment>(span: Span, segments: &[S], kind: &'static str) -> Self {
1684            Self { span, name: Segment::format_iter(segments), kind }
1685        }
1686    }
1687
1688    /// An import path (`flux::use foo::bar::baz`) that could not be resolved. Unlike
1689    /// [`UnresolvedName`], this always reports the full requested path in the message and
1690    /// explains, via `reason`, what specifically went wrong at the failing segment (not found,
1691    /// or found but not a module).
1692    #[derive(Diagnostic)]
1693    #[diag("unresolved import `{$name}`", code = E0999)]
1694    pub(crate) struct UnresolvedImport {
1695        #[primary_span]
1696        #[label("{$reason}")]
1697        pub span: Span,
1698        pub name: String,
1699        pub reason: String,
1700    }
1701
1702    impl UnresolvedImport {
1703        /// The import segment `ident` was not found, in `module_id` if the prefix before it
1704        /// resolved to one, or in scope otherwise.
1705        pub(super) fn new(
1706            ident: Ident,
1707            module_id: Option<DefId>,
1708            resolved_prefix: &[Ident],
1709        ) -> Self {
1710            let reason = match module_id {
1711                None => "not found in this scope".to_string(),
1712                Some(_) => format!("no `{ident}` in `{}`", Segment::format_iter(resolved_prefix)),
1713            };
1714            let name = Segment::format_iter(resolved_prefix.iter().chain(&[ident]));
1715            Self { span: ident.span, name, reason }
1716        }
1717    }
1718
1719    #[derive(Diagnostic)]
1720    #[diag("can't use generic parameters from outer item", code = E0999)]
1721    #[note("nested items cannot mention the generic parameters or `Self` of outer items")]
1722    pub(super) struct OuterGeneric {
1723        #[primary_span]
1724        #[label("use of generic parameter from outer item")]
1725        pub span: Span,
1726    }
1727
1728    #[derive(Diagnostic)]
1729    #[diag("unknown qualifier", code = E0999)]
1730    pub(super) struct UnknownQualifier {
1731        #[primary_span]
1732        span: Span,
1733    }
1734
1735    impl UnknownQualifier {
1736        pub(super) fn new(span: Span) -> Self {
1737            Self { span }
1738        }
1739    }
1740
1741    #[derive(Diagnostic)]
1742    #[diag("unknown function definition", code = E0999)]
1743    pub(super) struct UnknownFuncDefinition {
1744        #[primary_span]
1745        span: Span,
1746    }
1747
1748    impl UnknownFuncDefinition {
1749        pub(super) fn new(span: Span) -> Self {
1750            Self { span }
1751        }
1752    }
1753
1754    #[derive(Diagnostic)]
1755    #[diag("unknown type parameter", code = E0999)]
1756    pub(super) struct UnknownParametricParam {
1757        #[primary_span]
1758        span: Span,
1759    }
1760
1761    impl UnknownParametricParam {
1762        pub(super) fn new(span: Span) -> Self {
1763            Self { span }
1764        }
1765    }
1766
1767    #[derive(Diagnostic)]
1768    #[diag("the name `{$name}` is defined multiple times", code = E0999)]
1769    pub(super) struct DuplicateDefinition {
1770        #[primary_span]
1771        #[label("`{$name}` redefined here")]
1772        pub span: Span,
1773        #[label("previous definition of `{$name}`")]
1774        pub previous_definition: Span,
1775        pub name: Symbol,
1776    }
1777
1778    /// A name bound to two different items by two competing glob imports, reported at the first
1779    /// use of the name (imports themselves are never an error). Mirrors rustc's `E0659`.
1780    #[derive(Diagnostic)]
1781    #[diag("the name `{$name}` is ambiguous", code = E0999)]
1782    #[note("two different items named `{$name}` are in scope through glob imports")]
1783    pub(super) struct AmbiguousName {
1784        #[primary_span]
1785        #[label("ambiguous name")]
1786        span: Span,
1787        name: Symbol,
1788        #[label("`{$name}` could refer to the item imported here")]
1789        first: Span,
1790        #[label("`{$name}` could also refer to the item imported here")]
1791        second: Option<Span>,
1792    }
1793
1794    impl AmbiguousName {
1795        pub(super) fn new(ambiguity: super::Ambiguity) -> Self {
1796            let super::Ambiguity { span, name, first, second } = ambiguity;
1797            // Both candidates can come from the same glob statement, when it imports a module
1798            // that is itself ambiguously glob re-exporting the name. Pointing a second, identical
1799            // label at it reads as a bug, so drop it.
1800            Self { span, name, first, second: (first != second).then_some(second) }
1801        }
1802    }
1803
1804    #[derive(Diagnostic)]
1805    #[diag("identifier `{$name}` is bound more than once in this parameter list", code = E0999)]
1806    pub(super) struct DuplicateParam {
1807        #[primary_span]
1808        #[label("used as a parameter more than once")]
1809        pub span: Span,
1810        pub name: Symbol,
1811        #[label("first use of `{$name}`")]
1812        pub first_use: Span,
1813    }
1814}