Skip to main content

flux_middle/
queries.rs

1use std::{
2    cell::{OnceCell, RefCell},
3    rc::Rc,
4};
5
6use flux_arc_interner::List;
7use flux_common::{bug, tracked_span_bug};
8use flux_config as config;
9use flux_errors::{E0999, ErrorGuaranteed};
10use flux_macros::msg;
11use flux_rustc_bridge::{
12    self, def_id_to_string,
13    lowering::{self, Lower, UnsupportedErr},
14    mir::{self},
15    ty,
16};
17use flux_syntax::{surface, symbols::sym};
18use itertools::Itertools;
19use rustc_attr_ir::LangItem;
20use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
21use rustc_errors::{DiagMessage, Diagnostic};
22use rustc_hir::{
23    def::DefKind,
24    def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId},
25};
26use rustc_index::IndexVec;
27use rustc_macros::{Decodable, Encodable};
28use rustc_span::{DUMMY_SP, Span, Symbol};
29
30use crate::{
31    PanicSpec,
32    call_graph::{CallGraph, NodeKey},
33    def_id::{FluxDefId, FluxId, MaybeExternId, ResolvedDefId},
34    fhir,
35    global_env::GlobalEnv,
36    rty::{
37        self, AliasReft, Expr, GenericArg,
38        fold::TypeFoldable,
39        refining::{self, Refine, Refiner, refine_generic_param_def},
40    },
41};
42
43type Cache<K, V> = RefCell<UnordMap<K, V>>;
44
45pub type QueryResult<T = ()> = Result<T, QueryErr>;
46
47/// An error produced by a query.
48///
49/// We make a distinction between errors reported at def-site and errors reported at use-site.
50///
51/// For most errors reported at the def-site of an item, it makes little sense to check the definition
52/// of dependent items. For example, if a function signature is ill-formed, checking the body of another
53/// function that calls it, can produce confusing errors. In some cases, we can even fail to produce
54/// a signature for a function in which case we can't even check its call sites. For these cases, we
55/// emit an error at the definition site and return a [`QueryErr::Emitted`]. When checking a dependent,
56/// we detect this and early return without reporting any errors at the use-site.
57///
58/// Other errors are better reported at the use-site. For example, if some code calls a function from
59/// an external crate that has unsupported features, we ought to report the error at the call-site,
60/// because it would be confusing to only mention the definition of the external function without
61/// showing which part of the code is calling it. To attach a span to an error one can use [`QueryErr::at`]
62/// to get a [`QueryErrAt`].
63///
64/// Both [`QueryErr`] and [`QueryErrAt`] implement [`Diagnostic`]. The implementation for [`QueryErr`]
65/// reports the error at the definition site, while the implementation for [`QueryErrAt`] reports it at
66/// the (attached) use-site span. This allows us to play a bit lose because we can emit an error without
67/// attaching a span, but this means we may forget to attach spans at some places. We should consider
68/// not implementing [`Diagnostic`] for [`QueryErr`] such that we always make the distinction between
69/// use-site and def-site explicit, e.g., we could have methods `QueryErr::at_use_site` and
70/// `QueryErr::at_def_site` returning types with different implementations of [`Diagnostic`].
71#[derive(Debug, Clone, Encodable, Decodable)]
72pub enum QueryErr {
73    Unsupported {
74        def_id: DefId,
75        err: UnsupportedErr,
76    },
77    Ignored {
78        def_id: DefId,
79    },
80    InvalidGenericArg {
81        def_id: DefId,
82    },
83    MissingAssocReft {
84        impl_id: DefId,
85        trait_id: DefId,
86        name: Symbol,
87    },
88    /// An operation tried to access the internals of an opaque struct.
89    OpaqueStruct {
90        struct_id: DefId,
91    },
92    /// Used to report bugs, typically this means executing an arm in a match we thought it was
93    /// unreachable. Use this instead of panicking if it is easy to return a [`QueryErr`]. Use
94    /// [`QueryErr::bug`] or [`crate::query_bug!`] to construct this variant to track source location.
95    Bug {
96        def_id: Option<DefId>,
97        location: String,
98        msg: String,
99    },
100    Emitted(ErrorGuaranteed),
101    /// A definition from another crate was used but not explicitly included
102    NotIncluded {
103        def_id: DefId,
104    },
105}
106
107#[macro_export]
108macro_rules! query_bug {
109    ($fmt:literal $(,$args:expr)* $(,)?) => {
110        $crate::queries::QueryErr::bug(None, format_args!($fmt, $($args),*))
111    };
112    ($def_id:expr, $fmt:literal $(,$args:expr)* $(,)? ) => {{
113        $crate::queries::QueryErr::bug(Some($def_id.into()), format_args!($fmt, $($args),*))
114    }};
115}
116
117impl QueryErr {
118    pub fn unsupported(def_id: DefId, err: UnsupportedErr) -> Self {
119        QueryErr::Unsupported { def_id, err }
120    }
121
122    #[track_caller]
123    pub fn bug(def_id: Option<DefId>, msg: impl ToString) -> Self {
124        QueryErr::Bug {
125            def_id,
126            location: format!("{}", std::panic::Location::caller()),
127            msg: msg.to_string(),
128        }
129    }
130
131    pub fn at(self, cx: impl Into<ErrCtxt>) -> QueryErrAt {
132        QueryErrAt { cx: cx.into(), err: self }
133    }
134}
135
136/// A [`QueryErr`] with extra context information
137pub struct QueryErrAt {
138    cx: ErrCtxt,
139    err: QueryErr,
140}
141
142/// The "use site" context in which an error is reported
143#[derive(Clone, Copy)]
144pub enum ErrCtxt {
145    /// The error was triggered when checking a function body. The `Span` is the span in
146    /// the mir associated with the error. The `LocalDefId` is the id of the function.
147    FnCheck(Span, LocalDefId),
148    /// A miscellaneous context for which we only have a span
149    Misc(Span),
150}
151
152impl From<Span> for ErrCtxt {
153    fn from(v: Span) -> Self {
154        Self::Misc(v)
155    }
156}
157
158impl ErrCtxt {
159    fn span(self) -> Span {
160        match self {
161            ErrCtxt::Misc(span) => span,
162            ErrCtxt::FnCheck(span, _) => span,
163        }
164    }
165}
166
167pub struct Providers {
168    pub collect_specs: fn(GlobalEnv) -> crate::Specs,
169    pub resolve_crate: fn(GlobalEnv) -> crate::ResolverOutput,
170    pub desugar: for<'genv> fn(
171        GlobalEnv<'genv, '_>,
172        LocalDefId,
173    ) -> QueryResult<UnordMap<LocalDefId, fhir::Node<'genv>>>,
174    pub fhir_attr_map: for<'genv> fn(GlobalEnv<'genv, '_>, LocalDefId) -> fhir::AttrMap<'genv>,
175    pub fhir_crate: for<'genv> fn(GlobalEnv<'genv, '_>) -> fhir::FluxItems<'genv>,
176    pub qualifiers: fn(GlobalEnv) -> QueryResult<Vec<rty::Qualifier>>,
177    pub axioms: fn(GlobalEnv) -> QueryResult<Vec<rty::Axiom>>,
178    pub prim_rel: fn(GlobalEnv) -> QueryResult<UnordMap<rty::BinOp, rty::PrimRel>>,
179    pub spec_funcs: fn(GlobalEnv) -> rty::SpecFuncs,
180    pub func_sort: fn(GlobalEnv, FluxId<MaybeExternId>) -> rty::PolyFuncSort,
181    pub func_span: fn(GlobalEnv, FluxId<MaybeExternId>) -> Span,
182    pub adt_sort_def_of: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::AdtSortDef>,
183    pub check_wf: fn(GlobalEnv, LocalDefId) -> QueryResult<Rc<rty::WfckResults>>,
184    pub late_bound_refinement_params:
185        for<'genv> fn(GlobalEnv<'genv, '_>, LocalDefId) -> QueryResult<&'genv [fhir::ParamId]>,
186    pub adt_def: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::AdtDef>,
187    pub invariants_of: fn(GlobalEnv, MaybeExternId) -> rty::EarlyBinder<List<rty::Invariant>>,
188    pub constant_info: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::ConstantInfo>,
189    pub static_info: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::Ty>,
190    pub type_of: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>>,
191    pub variants_of: fn(
192        GlobalEnv,
193        MaybeExternId,
194    ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>,
195    pub fn_sig: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>>,
196    pub generics_of: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::Generics>,
197    pub refinement_generics_of:
198        fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>,
199    pub predicates_of:
200        fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>>,
201    pub assoc_refinements_of: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::AssocRefinements>,
202    pub sort_of_assoc_reft:
203        fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<rty::EarlyBinder<rty::FuncSort>>,
204    pub assoc_refinement_body:
205        fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<rty::EarlyBinder<rty::Lambda>>,
206    #[allow(clippy::type_complexity)]
207    pub default_assoc_refinement_body:
208        fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>,
209    pub item_bounds:
210        fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>>,
211    pub sort_decl_param_count: fn(GlobalEnv, FluxId<MaybeExternId>) -> usize,
212    pub call_graph: for<'genv, 'tcx> fn(GlobalEnv<'genv, 'tcx>) -> CallGraph<'tcx>,
213    pub inferred_no_panic:
214        for<'genv, 'tcx> fn(GlobalEnv<'genv, 'tcx>) -> UnordMap<NodeKey<'tcx>, PanicSpec>,
215}
216
217macro_rules! empty_query {
218    () => {
219        flux_common::bug!("query not provided")
220    };
221}
222
223impl Default for Providers {
224    fn default() -> Self {
225        Self {
226            collect_specs: |_| empty_query!(),
227            resolve_crate: |_| empty_query!(),
228            desugar: |_, _| empty_query!(),
229            fhir_attr_map: |_, _| empty_query!(),
230            fhir_crate: |_| empty_query!(),
231            spec_funcs: |_| empty_query!(),
232            func_sort: |_, _| empty_query!(),
233            func_span: |_, _| empty_query!(),
234            qualifiers: |_| empty_query!(),
235            axioms: |_| empty_query!(),
236            prim_rel: |_| empty_query!(),
237            adt_sort_def_of: |_, _| empty_query!(),
238            check_wf: |_, _| empty_query!(),
239            late_bound_refinement_params: |_, _| empty_query!(),
240            adt_def: |_, _| empty_query!(),
241            invariants_of: |_, _| empty_query!(),
242            type_of: |_, _| empty_query!(),
243            variants_of: |_, _| empty_query!(),
244            fn_sig: |_, _| empty_query!(),
245            generics_of: |_, _| empty_query!(),
246            refinement_generics_of: |_, _| empty_query!(),
247            predicates_of: |_, _| empty_query!(),
248            assoc_refinements_of: |_, _| empty_query!(),
249            assoc_refinement_body: |_, _| empty_query!(),
250            default_assoc_refinement_body: |_, _| empty_query!(),
251            sort_of_assoc_reft: |_, _| empty_query!(),
252            item_bounds: |_, _| empty_query!(),
253            constant_info: |_, _| empty_query!(),
254            static_info: |_, _| empty_query!(),
255            sort_decl_param_count: |_, _| empty_query!(),
256            call_graph: |_| empty_query!(),
257            inferred_no_panic: |_| empty_query!(),
258        }
259    }
260}
261
262pub struct Queries<'genv, 'tcx> {
263    pub(crate) providers: Providers,
264    /// The set of def ids that have been queried.
265    ///
266    /// After checking the crate, this set contains all items transitively reached from the set
267    /// of explicitly included items. We use this set to avoid triggering queries for items not
268    /// included when encoding metadata.
269    queried_def_ids: RefCell<UnordSet<DefId>>,
270    mir: Cache<LocalDefId, QueryResult<Rc<mir::BodyRoot<'tcx>>>>,
271    collect_specs: OnceCell<crate::Specs>,
272    resolve_crate: OnceCell<crate::ResolverOutput>,
273    flux_module_children: Cache<DefId, &'genv [fhir::FluxModChild]>,
274    desugar: Cache<LocalDefId, QueryResult<fhir::Node<'genv>>>,
275    fhir_attr_map: Cache<LocalDefId, fhir::AttrMap<'genv>>,
276    fhir_crate: OnceCell<fhir::FluxItems<'genv>>,
277    lower_generics_of: Cache<DefId, ty::Generics<'tcx>>,
278    lower_predicates_of: Cache<DefId, QueryResult<ty::GenericPredicates>>,
279    lower_type_of: Cache<DefId, QueryResult<ty::EarlyBinder<ty::Ty>>>,
280    lower_fn_sig: Cache<DefId, QueryResult<ty::EarlyBinder<ty::PolyFnSig>>>,
281    spec_funcs: Cache<CrateNum, Rc<rty::SpecFuncs>>,
282    inlined_body: Cache<FluxDefId, rty::Binder<rty::Expr>>,
283    func_sort: Cache<FluxDefId, rty::PolyFuncSort>,
284    func_span: Cache<FluxDefId, Span>,
285    qualifiers: OnceCell<QueryResult<Vec<rty::Qualifier>>>,
286    axioms: OnceCell<QueryResult<Vec<rty::Axiom>>>,
287    prim_rel: OnceCell<QueryResult<UnordMap<rty::BinOp, rty::PrimRel>>>,
288    adt_sort_def_of: Cache<DefId, QueryResult<rty::AdtSortDef>>,
289    check_wf: Cache<LocalDefId, QueryResult<Rc<rty::WfckResults>>>,
290    late_bound_refinement_params: Cache<LocalDefId, QueryResult<&'genv [fhir::ParamId]>>,
291    adt_def: Cache<DefId, QueryResult<rty::AdtDef>>,
292    invariants_of: Cache<DefId, rty::EarlyBinder<List<rty::Invariant>>>,
293    constant_info: Cache<DefId, QueryResult<rty::ConstantInfo>>,
294    static_info: Cache<DefId, QueryResult<rty::Ty>>,
295    generics_of: Cache<DefId, QueryResult<rty::Generics>>,
296    refinement_generics_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>>,
297    predicates_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::GenericPredicates>>>,
298    assoc_refinements_of: Cache<DefId, QueryResult<rty::AssocRefinements>>,
299    assoc_refinement_body: Cache<FluxDefId, QueryResult<rty::EarlyBinder<rty::Lambda>>>,
300    default_assoc_refinement_body:
301        Cache<FluxDefId, QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>>,
302    sort_of_assoc_reft: Cache<FluxDefId, QueryResult<rty::EarlyBinder<rty::FuncSort>>>,
303    item_bounds: Cache<DefId, QueryResult<rty::EarlyBinder<List<rty::Clause>>>>,
304    type_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::TyOrCtor>>>,
305    variants_of: Cache<DefId, QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>>,
306    fn_sig: Cache<DefId, QueryResult<rty::EarlyBinder<rty::PolyFnSig>>>,
307    sort_decl_param_count: Cache<FluxDefId, usize>,
308    no_panic: Cache<DefId, bool>,
309    assume_parametric_params: Cache<DefId, UnordSet<u32>>,
310    call_graph: OnceCell<CallGraph<'tcx>>,
311    /// The no-panic inference result for the local crate, keyed by `NodeKey`.
312    inferred_no_panic: OnceCell<Rc<UnordMap<NodeKey<'tcx>, PanicSpec>>>,
313}
314
315impl<'genv, 'tcx> Queries<'genv, 'tcx> {
316    pub(crate) fn new(providers: Providers) -> Self {
317        Self {
318            providers,
319            queried_def_ids: RefCell::new(UnordSet::new()),
320            mir: Default::default(),
321            collect_specs: Default::default(),
322            resolve_crate: Default::default(),
323            flux_module_children: Default::default(),
324            desugar: Default::default(),
325            fhir_attr_map: Default::default(),
326            fhir_crate: Default::default(),
327            lower_generics_of: Default::default(),
328            lower_predicates_of: Default::default(),
329            lower_type_of: Default::default(),
330            lower_fn_sig: Default::default(),
331            spec_funcs: Default::default(),
332            inlined_body: Default::default(),
333            func_sort: Default::default(),
334            func_span: Default::default(),
335            qualifiers: Default::default(),
336            axioms: Default::default(),
337            prim_rel: Default::default(),
338            adt_sort_def_of: Default::default(),
339            check_wf: Default::default(),
340            late_bound_refinement_params: Default::default(),
341            adt_def: Default::default(),
342            invariants_of: Default::default(),
343            constant_info: Default::default(),
344            static_info: Default::default(),
345            generics_of: Default::default(),
346            refinement_generics_of: Default::default(),
347            predicates_of: Default::default(),
348            assoc_refinements_of: Default::default(),
349            assoc_refinement_body: Default::default(),
350            default_assoc_refinement_body: Default::default(),
351            sort_of_assoc_reft: Default::default(),
352            item_bounds: Default::default(),
353            type_of: Default::default(),
354            variants_of: Default::default(),
355            fn_sig: Default::default(),
356            sort_decl_param_count: Default::default(),
357            no_panic: Default::default(),
358            assume_parametric_params: Default::default(),
359            call_graph: Default::default(),
360            inferred_no_panic: Default::default(),
361        }
362    }
363
364    pub(crate) fn queried(&self, def_id: DefId) -> bool {
365        self.queried_def_ids.borrow().contains(&def_id)
366    }
367
368    pub(crate) fn mir(
369        &self,
370        genv: GlobalEnv<'genv, 'tcx>,
371        def_id: LocalDefId,
372    ) -> QueryResult<Rc<mir::BodyRoot<'tcx>>> {
373        run_with_cache(&self.mir, def_id, || {
374            let mir = unsafe { flux_common::mir_storage::retrieve_mir_body(genv.tcx(), def_id) };
375            let mir =
376                lowering::MirLoweringCtxt::lower_mir_body(genv.tcx(), genv.sess(), def_id, mir)?;
377            Ok(Rc::new(mir))
378        })
379    }
380
381    pub(crate) fn collect_specs(&'genv self, genv: GlobalEnv<'genv, 'tcx>) -> &'genv crate::Specs {
382        self.collect_specs
383            .get_or_init(|| (self.providers.collect_specs)(genv))
384    }
385
386    pub(crate) fn resolve_crate(
387        &'genv self,
388        genv: GlobalEnv<'genv, 'tcx>,
389    ) -> &'genv crate::ResolverOutput {
390        self.resolve_crate
391            .get_or_init(|| (self.providers.resolve_crate)(genv))
392    }
393
394    /// Akin to `rustc_middle::ty::TyCtxt::module_children` but for flux items (`defs!` and
395    /// sort declarations) defined directly in a module.
396    #[allow(clippy::disallowed_methods, reason = "`flux_items_by_scope` is the source of truth")]
397    pub(crate) fn flux_module_children(
398        &'genv self,
399        genv: GlobalEnv<'genv, 'tcx>,
400        def_id: DefId,
401    ) -> &'genv [fhir::FluxModChild] {
402        run_with_cache(&self.flux_module_children, def_id, || {
403            def_id.dispatch_query(
404                genv,
405                self,
406                |def_id| -> &'genv [fhir::FluxModChild] {
407                    // Local modules: build children from surface specs (safe to call from the
408                    // resolver; `fhir_crate` would create a query cycle). Modules cannot
409                    // have extern specs, so `local_id()` is sound.
410                    let specs = genv.collect_specs();
411                    let module = rustc_hir::HirId::make_owner(def_id.local_id());
412                    let items = specs
413                        .flux_items_by_scope
414                        .get(&module)
415                        .map_or(&[][..], Vec::as_ref);
416                    genv.alloc_slice(
417                        &items
418                            .iter()
419                            .filter_map(|crate::FluxItemDecl { declarer, item }| {
420                                let declarer = declarer.to_def_id();
421                                let ident;
422                                let res = match item {
423                                    surface::FluxItem::FuncDef(func) => {
424                                        ident = func.name;
425                                        fhir::Res::GlobalFunc(fhir::SpecFuncKind::Def(
426                                            FluxDefId::new(declarer, ident.name),
427                                        ))
428                                    }
429                                    surface::FluxItem::SortDecl(sort) => {
430                                        ident = sort.name;
431                                        fhir::Res::UserSort(FluxDefId::new(declarer, ident.name))
432                                    }
433                                    surface::FluxItem::Qualifier(_)
434                                    | surface::FluxItem::PrimOpProp(_)
435                                    | surface::FluxItem::Axiom(_)
436                                    | surface::FluxItem::Use(_) => return None,
437                                };
438                                Some(fhir::FluxModChild { ident, res })
439                            })
440                            .collect::<Vec<_>>(),
441                    )
442                },
443                |def_id| genv.cstore().flux_module_children(def_id),
444                |_| &[], // crates without flux metadata have no flux children
445            )
446        })
447    }
448
449    pub(crate) fn desugar(
450        &'genv self,
451        genv: GlobalEnv<'genv, 'tcx>,
452        def_id: LocalDefId,
453    ) -> QueryResult<fhir::Node<'genv>> {
454        if let Some(v) = self.desugar.borrow().get(&def_id) {
455            return v.clone();
456        }
457        match (self.providers.desugar)(genv, def_id) {
458            Ok(nodes) => {
459                let mut cache = self.desugar.borrow_mut();
460                cache.extend_unord(nodes.into_items().map(|(def_id, node)| (def_id, Ok(node))));
461                let Some(res) = cache.get(&def_id) else {
462                    tracked_span_bug!("cannot desugar {def_id:?}")
463                };
464                res.clone()
465            }
466            Err(err) => {
467                self.desugar.borrow_mut().insert(def_id, Err(err.clone()));
468                Err(err)
469            }
470        }
471    }
472
473    pub(crate) fn fhir_attr_map(
474        &'genv self,
475        genv: GlobalEnv<'genv, 'tcx>,
476        def_id: LocalDefId,
477    ) -> fhir::AttrMap<'genv> {
478        run_with_cache(&self.fhir_attr_map, def_id, || (self.providers.fhir_attr_map)(genv, def_id))
479    }
480
481    pub(crate) fn fhir_crate(
482        &'genv self,
483        genv: GlobalEnv<'genv, 'tcx>,
484    ) -> &'genv fhir::FluxItems<'genv> {
485        self.fhir_crate
486            .get_or_init(|| (self.providers.fhir_crate)(genv))
487    }
488
489    pub(crate) fn lower_generics_of(
490        &self,
491        genv: GlobalEnv<'genv, 'tcx>,
492        def_id: DefId,
493    ) -> ty::Generics<'tcx> {
494        run_with_cache(&self.lower_generics_of, def_id, || {
495            genv.tcx().generics_of(def_id).lower(genv.tcx())
496        })
497    }
498
499    pub(crate) fn lower_predicates_of(
500        &self,
501        genv: GlobalEnv,
502        def_id: DefId,
503    ) -> QueryResult<ty::GenericPredicates> {
504        run_with_cache(&self.lower_predicates_of, def_id, || {
505            genv.tcx()
506                .clauses_of(def_id)
507                .lower(genv.tcx())
508                .map_err(|err| QueryErr::unsupported(def_id, err))
509        })
510    }
511
512    pub(crate) fn lower_type_of(
513        &self,
514        genv: GlobalEnv,
515        def_id: DefId,
516    ) -> QueryResult<ty::EarlyBinder<ty::Ty>> {
517        run_with_cache(&self.lower_type_of, def_id, || {
518            let ty = genv
519                .tcx()
520                .type_of(def_id)
521                .instantiate_identity()
522                .skip_norm_wip();
523            Ok(ty::EarlyBinder(
524                ty.lower(genv.tcx())
525                    .map_err(|err| QueryErr::unsupported(def_id, err.into_err()))?,
526            ))
527        })
528    }
529
530    pub(crate) fn lower_fn_sig(
531        &self,
532        genv: GlobalEnv,
533        def_id: DefId,
534    ) -> QueryResult<ty::EarlyBinder<ty::PolyFnSig>> {
535        run_with_cache(&self.lower_fn_sig, def_id, || {
536            let fn_sig = genv
537                .tcx()
538                .fn_sig(def_id)
539                .instantiate_identity()
540                .skip_norm_wip();
541            Ok(ty::EarlyBinder(
542                fn_sig
543                    .lower(genv.tcx())
544                    .map_err(|err| QueryErr::unsupported(def_id, err.into_err()))?,
545            ))
546        })
547    }
548
549    pub(crate) fn spec_funcs(&self, genv: GlobalEnv, krate: CrateNum) -> Rc<rty::SpecFuncs> {
550        run_with_cache(&self.spec_funcs, krate, || {
551            if krate == LOCAL_CRATE {
552                Rc::new((self.providers.spec_funcs)(genv))
553            } else {
554                genv.cstore().spec_funcs(krate)
555            }
556        })
557    }
558
559    pub(crate) fn inlined_body(&self, genv: GlobalEnv, did: FluxDefId) -> rty::Binder<rty::Expr> {
560        // We inline spec functions lazily (including those of external crates) in the current
561        // session, so they are inlined according to the flags of the current crate. Inlining a
562        // body recursively inlines (and caches) the bodies of the functions it calls. This
563        // terminates because `spec_funcs` rejects cycles.
564        run_with_cache(&self.inlined_body, did, || {
565            let rty::SpecFunc::Defined { body, .. } = genv.spec_func(did) else {
566                bug!("inlined body of uninterpreted function `{did:?}`")
567            };
568            body.reduce(genv)
569        })
570    }
571
572    pub(crate) fn func_sort(&self, genv: GlobalEnv, def_id: FluxDefId) -> rty::PolyFuncSort {
573        run_with_cache(&self.func_sort, def_id, || {
574            def_id.dispatch_query(
575                genv,
576                self,
577                |def_id| {
578                    // refinement functions cannot be extern specs so we simply grab the local id
579                    (self.providers.func_sort)(genv, def_id)
580                },
581                |def_id| genv.cstore().func_sort(def_id),
582                |_| {
583                    bug!(
584                        "cannot generate default function sort, the refinement must be defined somewhere"
585                    )
586                },
587            )
588        })
589    }
590
591    pub(crate) fn func_span(&self, genv: GlobalEnv, def_id: FluxDefId) -> Span {
592        run_with_cache(&self.func_span, def_id, || {
593            def_id.dispatch_query(
594                genv,
595                self,
596                |def_id| {
597                    // refinement functions cannot be extern specs so we simply grab the local id
598                    (self.providers.func_span)(genv, def_id)
599                },
600                |def_id| genv.cstore().func_span(def_id),
601                |_|
602                bug!(
603                        "cannot generate default function sort, the refinement must be defined somewhere"
604                    )
605                ,
606            )
607        })
608    }
609
610    pub(crate) fn qualifiers(&self, genv: GlobalEnv) -> QueryResult<&[rty::Qualifier]> {
611        self.qualifiers
612            .get_or_init(|| (self.providers.qualifiers)(genv))
613            .as_deref()
614            .map_err(Clone::clone)
615    }
616
617    pub(crate) fn axioms(&self, genv: GlobalEnv) -> QueryResult<&[rty::Axiom]> {
618        self.axioms
619            .get_or_init(|| (self.providers.axioms)(genv))
620            .as_deref()
621            .map_err(Clone::clone)
622    }
623
624    pub(crate) fn prim_rel(
625        &self,
626        genv: GlobalEnv,
627    ) -> QueryResult<&UnordMap<rty::BinOp, rty::PrimRel>> {
628        self.prim_rel
629            .get_or_init(|| (self.providers.prim_rel)(genv))
630            .as_ref()
631            .map_err(|err| err.clone())
632    }
633
634    pub(crate) fn adt_sort_def_of(
635        &self,
636        genv: GlobalEnv,
637        def_id: DefId,
638    ) -> QueryResult<rty::AdtSortDef> {
639        run_with_cache(&self.adt_sort_def_of, def_id, || {
640            def_id.dispatch_query(
641                genv,
642                self,
643                |def_id| (self.providers.adt_sort_def_of)(genv, def_id),
644                |def_id| genv.cstore().adt_sort_def(def_id),
645                |def_id| {
646                    let variants = IndexVec::from([rty::AdtSortVariant::new(vec![])]);
647                    Ok(rty::AdtSortDef::new(def_id, vec![], variants, false, true))
648                },
649            )
650        })
651    }
652
653    pub(crate) fn sort_decl_param_count(&self, genv: GlobalEnv, def_id: FluxDefId) -> usize {
654        run_with_cache(&self.sort_decl_param_count, def_id, || {
655            def_id.dispatch_query(
656                genv,
657                self,
658                |def_id| {
659                    (self.providers.sort_decl_param_count)(genv, def_id)
660                },
661                |def_id| genv.cstore().sort_decl_param_count(def_id),
662                |_| {
663                    bug!(
664                        "cannot generate default param count for sort declaration, it must be defined somewhere"
665                    )
666                }
667            )
668        })
669    }
670
671    pub(crate) fn check_wf(
672        &self,
673        genv: GlobalEnv<'genv, '_>,
674        def_id: LocalDefId,
675    ) -> QueryResult<Rc<rty::WfckResults>> {
676        run_with_cache(&self.check_wf, def_id, || (self.providers.check_wf)(genv, def_id))
677    }
678
679    pub(crate) fn late_bound_refinement_params(
680        &self,
681        genv: GlobalEnv<'genv, '_>,
682        def_id: LocalDefId,
683    ) -> QueryResult<&'genv [fhir::ParamId]> {
684        run_with_cache(&self.late_bound_refinement_params, def_id, || {
685            (self.providers.late_bound_refinement_params)(genv, def_id)
686        })
687    }
688
689    pub(crate) fn constant_info(
690        &self,
691        genv: GlobalEnv,
692        def_id: DefId,
693    ) -> QueryResult<rty::ConstantInfo> {
694        run_with_cache(&self.constant_info, def_id, || {
695            def_id.dispatch_query(
696                genv,
697                self,
698                |def_id| (self.providers.constant_info)(genv, def_id),
699                |def_id| genv.cstore().constant_info(def_id),
700                |def_id| {
701                    // TODO(RJ): fix duplication with [`conv_constant`]` in `flux-fhir-analysis`
702                    let ty = genv.tcx().type_of(def_id).no_bound_vars().unwrap();
703                    if ty.is_integral() {
704                        let val = genv.tcx().const_eval_poly(def_id).ok().and_then(|val| {
705                            let val = val.try_to_scalar_int()?;
706                            rty::Constant::from_scalar_int(genv.tcx(), val, &ty)
707                        });
708                        if let Some(constant_) = val {
709                            return Ok(rty::ConstantInfo::Interpreted(
710                                rty::Expr::constant(constant_),
711                                rty::Sort::Int,
712                            ));
713                        }
714                    }
715                    Ok(rty::ConstantInfo::Uninterpreted)
716                },
717            )
718        })
719    }
720
721    pub fn call_graph(&'genv self, genv: GlobalEnv<'genv, 'tcx>) -> &'genv CallGraph<'tcx> {
722        self.call_graph
723            .get_or_init(|| (self.providers.call_graph)(genv))
724    }
725
726    /// The no-panic inference result for the local crate, keyed by `NodeKey`.
727    pub fn inferred_no_panic(
728        &'genv self,
729        genv: GlobalEnv<'genv, 'tcx>,
730    ) -> Rc<UnordMap<NodeKey<'tcx>, PanicSpec>> {
731        self.inferred_no_panic
732            .get_or_init(|| Rc::new((self.providers.inferred_no_panic)(genv)))
733            .clone()
734    }
735
736    pub(crate) fn static_info(&self, genv: GlobalEnv, def_id: DefId) -> QueryResult<rty::Ty> {
737        run_with_cache(&self.static_info, def_id, || {
738            def_id.dispatch_query(
739                genv,
740                self,
741                |def_id| (self.providers.static_info)(genv, def_id),
742                |def_id| genv.cstore().static_info(def_id),
743                |def_id| rty::refining::default_static_ty(genv, def_id),
744            )
745        })
746    }
747
748    pub(crate) fn no_panic(&self, genv: GlobalEnv, def_id: DefId) -> bool {
749        run_with_cache(&self.no_panic, def_id, || {
750            def_id.dispatch_query(
751                genv,
752                self,
753                |def_id| {
754                    let mut current_id = def_id.local_id();
755
756                    // Walk up the entire parent chain within this closure
757                    loop {
758                        // Skip dummy items
759                        if genv.is_dummy(current_id) {
760                            if let Some(parent) = genv.tcx().opt_local_parent(current_id) {
761                                current_id = parent;
762                                continue;
763                            } else {
764                                return false; // Reached top without finding non-dummy
765                            }
766                        }
767
768                        // Check if current non-dummy item has the `no_panic` attribute
769                        if genv.fhir_attr_map(current_id).no_panic() {
770                            return true;
771                        }
772
773                        // Move to the next parent
774                        if let Some(parent) = genv.tcx().opt_local_parent(current_id) {
775                            current_id = parent;
776                        } else {
777                            break; // Reached the top
778                        }
779                    }
780
781                    config::no_panic()
782                },
783                |def_id| genv.cstore().no_panic(def_id),
784                |_| false,
785            )
786        })
787    }
788
789    pub(crate) fn assume_parametric_params(&self, genv: GlobalEnv, def_id: DefId) -> UnordSet<u32> {
790        run_with_cache(&self.assume_parametric_params, def_id, || {
791            def_id.dispatch_query(
792                genv,
793                self,
794                |def_id| {
795                    let tcx = genv.tcx();
796                    let generics = tcx.generics_of(def_id);
797                    genv.fhir_attr_map(def_id.local_id())
798                        .parametric_params()
799                        .iter()
800                        .map(|param_id| generics.param_def_id_to_index(tcx, *param_id).unwrap())
801                        .collect()
802                },
803                |def_id| genv.cstore().assume_parametric_params(def_id),
804                |_| UnordSet::default(),
805            )
806        })
807    }
808
809    pub(crate) fn adt_def(&self, genv: GlobalEnv, def_id: DefId) -> QueryResult<rty::AdtDef> {
810        run_with_cache(&self.adt_def, def_id, || {
811            def_id.dispatch_query(
812                genv,
813                self,
814                |def_id| (self.providers.adt_def)(genv, def_id),
815                |def_id| genv.cstore().adt_def(def_id),
816                |def_id| {
817                    let adt_def = genv.tcx().adt_def(def_id).lower(genv.tcx());
818                    Ok(rty::AdtDef::new(adt_def, genv.adt_sort_def_of(def_id)?, false))
819                },
820            )
821        })
822    }
823
824    pub(crate) fn invariants_of(
825        &self,
826        genv: GlobalEnv,
827        def_id: DefId,
828    ) -> rty::EarlyBinder<List<rty::Invariant>> {
829        run_with_cache(&self.invariants_of, def_id, || {
830            def_id.dispatch_query(
831                genv,
832                self,
833                |def_id| (self.providers.invariants_of)(genv, def_id),
834                |def_id| genv.cstore().invariants_of(def_id),
835                |_| rty::EarlyBinder(List::empty()),
836            )
837        })
838    }
839
840    pub(crate) fn generics_of(&self, genv: GlobalEnv, def_id: DefId) -> QueryResult<rty::Generics> {
841        // Box is special: its first type parameter (the pointee `T`) is refined as a `Type` rather
842        // than a `Base`. This allows refinements to "see through" the Box, similar to how references
843        // work.
844        if genv.tcx().is_lang_item(def_id, LangItem::OwnedBox) {
845            let generics = genv.lower_generics_of(def_id);
846            debug_assert_eq!(generics.params.len(), 2);
847            let deref_ty = &generics.params[0];
848            let alloc = &generics.params[1];
849            return Ok(rty::Generics {
850                own_params: List::from_arr([
851                    refine_generic_param_def(true, deref_ty),
852                    refine_generic_param_def(false, alloc),
853                ]),
854                parent: generics.parent(),
855                parent_count: generics.parent_count(),
856                has_self: generics.orig.has_self,
857            });
858        }
859        // `MetaSized` is a marker trait with a single `Self` type parameter. We refine it as `Type`
860        // (rather than `Base`) so that a type parameter `T` of kind `Type` can flow through bounds
861        // like `T: MetaSized`. This is required because `Box` is defined as `Box<T: ?Sized, ...>`
862        // which desugars to the bound `T: MetaSized`. This should be mostly fine because parameters
863        // of both kinds should be able to satisfy `MetaSized` bounds, but it will cause problems
864        // if we ever try to add associated refinements to `MetaSized` like we did for `Sized`.
865        if genv.tcx().is_lang_item(def_id, LangItem::MetaSized) {
866            let generics = genv.lower_generics_of(def_id);
867            debug_assert_eq!(generics.params.len(), 1);
868            let self_ty = &generics.params[0];
869            return Ok(rty::Generics {
870                own_params: List::from_arr([refine_generic_param_def(true, self_ty)]),
871                parent: generics.parent(),
872                parent_count: generics.parent_count(),
873                has_self: generics.orig.has_self,
874            });
875        }
876
877        run_with_cache(&self.generics_of, def_id, || {
878            def_id.dispatch_query(
879                genv,
880                self,
881                |def_id| (self.providers.generics_of)(genv, def_id),
882                |def_id| genv.cstore().generics_of(def_id),
883                |def_id| Ok(refining::refine_generics(&genv.lower_generics_of(def_id))),
884            )
885        })
886    }
887
888    pub(crate) fn refinement_generics_of(
889        &self,
890        genv: GlobalEnv,
891        def_id: DefId,
892    ) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
893        run_with_cache(&self.refinement_generics_of, def_id, || {
894            def_id.dispatch_query(
895                genv,
896                self,
897                |def_id| (self.providers.refinement_generics_of)(genv, def_id),
898                |def_id| genv.cstore().refinement_generics_of(def_id),
899                |def_id| {
900                    let parent = genv.tcx().generics_of(def_id).parent;
901                    Ok(rty::EarlyBinder(rty::RefinementGenerics {
902                        parent,
903                        parent_count: 0,
904                        own_params: List::empty(),
905                    }))
906                },
907            )
908        })
909    }
910
911    pub(crate) fn item_bounds(
912        &self,
913        genv: GlobalEnv<'genv, 'tcx>,
914        def_id: DefId,
915    ) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>> {
916        run_with_cache(&self.item_bounds, def_id, || {
917            def_id.dispatch_query(
918                genv,
919                self,
920                |def_id| (self.providers.item_bounds)(genv, def_id),
921                |def_id| genv.cstore().item_bounds(def_id),
922                |def_id| {
923                    let clauses = genv
924                        .tcx()
925                        .item_bounds(def_id)
926                        .skip_binder()
927                        .lower(genv.tcx())
928                        .map_err(|err| QueryErr::unsupported(def_id, err))?
929                        .refine(&Refiner::default_for_item(genv, def_id)?)?;
930
931                    Ok(rty::EarlyBinder(clauses))
932                },
933            )
934        })
935    }
936
937    pub(crate) fn predicates_of(
938        &self,
939        genv: GlobalEnv,
940        def_id: DefId,
941    ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
942        run_with_cache(&self.predicates_of, def_id, || {
943            def_id.dispatch_query(
944                genv,
945                self,
946                |def_id| (self.providers.predicates_of)(genv, def_id),
947                |def_id| genv.cstore().predicates_of(def_id),
948                |def_id| {
949                    let predicates = genv
950                        .lower_predicates_of(def_id)?
951                        .refine(&Refiner::default_for_item(genv, def_id)?)?;
952                    Ok(rty::EarlyBinder(predicates))
953                },
954            )
955        })
956    }
957
958    pub(crate) fn assoc_refinements_of(
959        &self,
960        genv: GlobalEnv,
961        def_id: DefId,
962    ) -> QueryResult<rty::AssocRefinements> {
963        run_with_cache(&self.assoc_refinements_of, def_id, || {
964            def_id.dispatch_query(
965                genv,
966                self,
967                |def_id| (self.providers.assoc_refinements_of)(genv, def_id),
968                |def_id| genv.cstore().assoc_refinements_of(def_id),
969                |def_id| Ok(genv.builtin_assoc_refts(def_id).unwrap_or_default()),
970            )
971        })
972    }
973
974    pub(crate) fn assoc_refinement_body(
975        &self,
976        genv: GlobalEnv,
977        impl_assoc_id: FluxDefId,
978    ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
979        run_with_cache(&self.assoc_refinement_body, impl_assoc_id, || {
980            impl_assoc_id.dispatch_query(
981                genv,
982                self,
983                |impl_assoc_id| (self.providers.assoc_refinement_body)(genv, impl_assoc_id),
984                |impl_assoc_id| genv.cstore().assoc_refinements_def(impl_assoc_id),
985                |impl_assoc_id| {
986                    Err(query_bug!(
987                        impl_assoc_id.parent(),
988                        "cannot generate default associate refinement for extern impl"
989                    ))
990                },
991            )
992        })
993    }
994
995    pub(crate) fn default_assoc_refinement_body(
996        &self,
997        genv: GlobalEnv,
998        trait_assoc_id: FluxDefId,
999    ) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
1000        run_with_cache(&self.default_assoc_refinement_body, trait_assoc_id, || {
1001            trait_assoc_id.dispatch_query(
1002                genv,
1003                self,
1004                |trait_assoc_id| {
1005                    (self.providers.default_assoc_refinement_body)(genv, trait_assoc_id)
1006                },
1007                |trait_assoc_id| genv.cstore().default_assoc_refinements_def(trait_assoc_id),
1008                |trait_assoc_id| {
1009                    Err(query_bug!(
1010                        trait_assoc_id.parent(),
1011                        "cannot generate default assoc refinement for extern trait"
1012                    ))
1013                },
1014            )
1015        })
1016    }
1017
1018    pub(crate) fn sort_of_assoc_reft(
1019        &self,
1020        genv: GlobalEnv,
1021        assoc_id: FluxDefId,
1022    ) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
1023        run_with_cache(&self.sort_of_assoc_reft, assoc_id, || {
1024            assoc_id.dispatch_query(
1025                genv,
1026                self,
1027                |assoc_id| (self.providers.sort_of_assoc_reft)(genv, assoc_id),
1028                |assoc_id| genv.cstore().sort_of_assoc_reft(assoc_id),
1029                |assoc_id| {
1030                    genv.builtin_assoc_reft_sort(assoc_id).ok_or_else(|| {
1031                        query_bug!(
1032                            assoc_id.parent(),
1033                            "assoc refinement on extern crate is not builtin"
1034                        )
1035                    })
1036                },
1037            )
1038        })
1039    }
1040
1041    pub(crate) fn type_of(
1042        &self,
1043        genv: GlobalEnv,
1044        def_id: DefId,
1045    ) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
1046        run_with_cache(&self.type_of, def_id, || {
1047            def_id.dispatch_query(
1048                genv,
1049                self,
1050                |def_id| (self.providers.type_of)(genv, def_id),
1051                |def_id| genv.cstore().type_of(def_id),
1052                |def_id| {
1053                    // If we're given a type parameter, provide the generics of the parent container.
1054                    let generics_def_id = match genv.def_kind(def_id) {
1055                        DefKind::TyParam => genv.tcx().parent(def_id),
1056                        _ => def_id,
1057                    };
1058                    let ty = genv.lower_type_of(def_id)?.skip_binder();
1059                    Ok(rty::EarlyBinder(
1060                        Refiner::default_for_item(genv, generics_def_id)?
1061                            .refine_ty_or_base(&ty)?
1062                            .into(),
1063                    ))
1064                },
1065            )
1066        })
1067    }
1068
1069    pub(crate) fn variants_of(
1070        &self,
1071        genv: GlobalEnv,
1072        def_id: DefId,
1073    ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
1074        run_with_cache(&self.variants_of, def_id, || {
1075            def_id.dispatch_query(
1076                genv,
1077                self,
1078                |def_id| (self.providers.variants_of)(genv, def_id),
1079                |def_id| genv.cstore().variants_of(def_id),
1080                |def_id| {
1081                    let variants = genv
1082                        .tcx()
1083                        .adt_def(def_id)
1084                        .variants()
1085                        .indices()
1086                        .map(|variant_idx| {
1087                            Refiner::default_for_item(genv, def_id)?
1088                                .refine_variant_def(def_id, variant_idx)
1089                        })
1090                        .try_collect()?;
1091                    Ok(rty::Opaqueness::Transparent(rty::EarlyBinder(variants)))
1092                },
1093            )
1094        })
1095    }
1096
1097    pub(crate) fn fn_sig(
1098        &self,
1099        genv: GlobalEnv,
1100        def_id: DefId,
1101    ) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
1102        run_with_cache(&self.fn_sig, def_id, || {
1103            def_id.dispatch_query(
1104                genv,
1105                self,
1106                |def_id| (self.providers.fn_sig)(genv, def_id),
1107                |def_id| genv.cstore().fn_sig(def_id),
1108                |def_id| {
1109                    let tcx = genv.tcx();
1110
1111                    let mut poly_sig = genv
1112                        .lower_fn_sig(def_id)?
1113                        .skip_binder()
1114                        .refine(&Refiner::default_for_item(genv, def_id)?)?
1115                        .hoist_input_binders();
1116                    if genv.is_fn_call(def_id) {
1117                        let fn_once_id = tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP);
1118
1119                        let fn_once_no_panic = genv
1120                            .builtin_assoc_refts(fn_once_id)
1121                            .unwrap()
1122                            .find(sym::no_panic)
1123                            .unwrap();
1124
1125                        let args = GenericArg::identity_for_item(genv, fn_once_id)?;
1126
1127                        let alias_reft = AliasReft { assoc_id: fn_once_no_panic.def_id, args };
1128
1129                        poly_sig = poly_sig.map(|mut fn_sig| {
1130                            fn_sig.no_panic = Expr::alias(alias_reft, List::empty());
1131                            fn_sig
1132                        });
1133                    }
1134
1135                    // We only will add weak kvars if
1136                    //   0. If suggestions are enabled.
1137                    //   1. There are no weak kvars already
1138                    //   2. The function does NOT have a `#[no_suggestions]` annotation
1139                    //      in its parent. (checked below)
1140                    #[cfg(feature = "suggestions")]
1141                    if genv.weak_kvars_for(def_id).is_none() {
1142                        // We only will add weak kvars to specs that are
1143                        // available locally (also enforced in fixpoint_encoding
1144                        // --- this check is perhaps redundant).
1145                        match genv.resolve_id(def_id).as_maybe_extern() {
1146                            Some(maybe_extern) if !genv.no_suggestions(maybe_extern.local_id()) => {
1147                                poly_sig = poly_sig
1148                                    .add_weak_kvars(genv, maybe_extern.local_id().into())?;
1149                            }
1150                            _ => {}
1151                        }
1152                    }
1153                    Ok(rty::EarlyBinder(poly_sig))
1154                },
1155            )
1156        })
1157    }
1158}
1159
1160/// Logic to *dispatch* a `def_id` to a provider (`local`, `external`, or `default`).
1161/// This is a trait so it can be implemented for [`DefId`] and for [`FluxDefId`].
1162pub trait DispatchKey: Sized + Copy {
1163    type LocalId;
1164
1165    fn dispatch_query<R>(
1166        self,
1167        genv: GlobalEnv,
1168        queries: &Queries,
1169        local: impl FnOnce(Self::LocalId) -> R,
1170        external: impl FnOnce(Self) -> Option<R>,
1171        default: impl FnOnce(Self) -> R,
1172    ) -> R;
1173
1174    fn def_id(self) -> DefId;
1175}
1176
1177impl DispatchKey for DefId {
1178    type LocalId = MaybeExternId;
1179
1180    fn dispatch_query<R>(
1181        self,
1182        genv: GlobalEnv,
1183        queries: &Queries,
1184        local: impl FnOnce(MaybeExternId) -> R,
1185        external: impl FnOnce(Self) -> Option<R>,
1186        default: impl FnOnce(Self) -> R,
1187    ) -> R {
1188        queries.queried_def_ids.borrow_mut().insert(self);
1189        match genv.resolve_id(self) {
1190            ResolvedDefId::Local(local_id) => {
1191                // Case 1: `def_id` is a `LocalDefId` so forward it to the *local provider*
1192                local(MaybeExternId::Local(local_id))
1193            }
1194            ResolvedDefId::ExternSpec(local_id, def_id) => {
1195                // Case 2: `def_id` is a `LocalDefId` wrapping an extern spec, so we also
1196                // forward it to the local provider
1197                local(MaybeExternId::Extern(local_id, def_id))
1198            }
1199            ResolvedDefId::Extern(def_id) if let Some(v) = external(def_id) => {
1200                // Case 3: `def_id` is an external `def_id` for which we have an annotation in the
1201                // *external provider*
1202                v
1203            }
1204            ResolvedDefId::Extern(def_id) => {
1205                // Case 4: If none of the above, we generate a default annotation
1206                default(def_id)
1207            }
1208        }
1209    }
1210
1211    fn def_id(self) -> DefId {
1212        self
1213    }
1214}
1215
1216impl DispatchKey for FluxDefId {
1217    type LocalId = FluxId<MaybeExternId>;
1218
1219    fn dispatch_query<R>(
1220        self,
1221        genv: GlobalEnv,
1222        queries: &Queries,
1223        local: impl FnOnce(FluxId<MaybeExternId>) -> R,
1224        external: impl FnOnce(FluxId<DefId>) -> Option<R>,
1225        default: impl FnOnce(FluxId<DefId>) -> R,
1226    ) -> R {
1227        #[allow(
1228            clippy::disallowed_methods,
1229            reason = "we are mapping the parent id to a different representation which still guarantees the existence of the item"
1230        )]
1231        self.parent().dispatch_query(
1232            genv,
1233            queries,
1234            |container_id| local(FluxId::new(container_id, self.name())),
1235            |container_id| external(FluxId::new(container_id, self.name())),
1236            |container_id| default(FluxId::new(container_id, self.name())),
1237        )
1238    }
1239
1240    fn def_id(self) -> DefId {
1241        self.parent()
1242    }
1243}
1244
1245fn run_with_cache<K, V>(cache: &Cache<K, V>, key: K, f: impl FnOnce() -> V) -> V
1246where
1247    K: std::hash::Hash + Eq,
1248    V: Clone,
1249{
1250    if let Some(v) = cache.borrow().get(&key) {
1251        return v.clone();
1252    }
1253    let v = f();
1254    cache.borrow_mut().insert(key, v.clone());
1255    v
1256}
1257
1258const OPAQUE_STRUCT: DiagMessage = msg!("invalid use of opaque struct");
1259const MISSING_ASSOC_REFT: DiagMessage =
1260    msg!("associated refinement `{$name}` is missing from implementation");
1261
1262impl<'a> Diagnostic<'a> for QueryErr {
1263    #[track_caller]
1264    fn into_diag(
1265        self,
1266        dcx: rustc_errors::DiagCtxtHandle<'a>,
1267        _level: rustc_errors::Level,
1268    ) -> rustc_errors::Diag<'a> {
1269        rustc_middle::ty::tls::with_opt(
1270            #[track_caller]
1271            |tcx| {
1272                let tcx = tcx.expect("no TyCtxt stored in tls");
1273                match self {
1274                    QueryErr::Unsupported { def_id, err } => {
1275                        let span = err.span.unwrap_or_else(|| tcx.def_span(def_id));
1276                        let mut diag = dcx.struct_span_err(span, msg!("unsupported signature"));
1277                        diag.code(E0999);
1278                        diag.note(err.descr);
1279                        diag
1280                    }
1281                    QueryErr::Ignored { def_id } => {
1282                        let def_span = tcx.def_span(def_id);
1283                        let mut diag = dcx.struct_span_err(def_span, msg!("use of ignored item"));
1284                        diag.code(E0999);
1285                        diag
1286                    }
1287                    QueryErr::NotIncluded { def_id } => {
1288                        let def_span = tcx.def_span(def_id);
1289                        let mut diag = dcx.struct_span_err(
1290                            def_span,
1291                            msg!("use of item defined in external crate, but was not included when checking that crate"),
1292                        );
1293                        diag.code(E0999);
1294                        diag
1295                    }
1296                    QueryErr::InvalidGenericArg { def_id } => {
1297                        let def_span = tcx.def_span(def_id);
1298                        let mut diag = dcx.struct_span_err(
1299                            def_span,
1300                            msg!("cannot instantiate base generic with opaque type or a type parameter of kind type"),
1301                        );
1302                        diag.code(E0999);
1303                        diag
1304                    }
1305                    QueryErr::MissingAssocReft { impl_id, name, .. } => {
1306                        let def_span = tcx.def_span(impl_id);
1307                        let mut diag = dcx.struct_span_err(def_span, MISSING_ASSOC_REFT);
1308                        diag.arg("name", name);
1309                        diag.code(E0999);
1310                        diag
1311                    }
1312                    QueryErr::Bug { def_id, location, msg } => {
1313                        let mut diag = dcx.struct_err(msg!("internal flux error: {$location}"));
1314                        if let Some(def_id) = def_id {
1315                            diag.span(tcx.def_span(def_id));
1316                        }
1317                        diag.arg("location", location);
1318                        diag.note(msg);
1319                        diag
1320                    }
1321                    QueryErr::Emitted(_) => {
1322                        let mut diag = dcx.struct_err("QueryErr::Emitted should be emitted");
1323                        diag.downgrade_to_delayed_bug();
1324                        diag
1325                    }
1326                    QueryErr::OpaqueStruct { struct_id } => {
1327                        let struct_span = tcx.def_span(struct_id);
1328                        let mut diag = dcx.struct_span_err(struct_span, OPAQUE_STRUCT);
1329                        diag.arg("struct", tcx.def_path_str(struct_id));
1330                        diag
1331                    }
1332                }
1333            },
1334        )
1335    }
1336}
1337
1338impl<'a> Diagnostic<'a> for QueryErrAt {
1339    #[track_caller]
1340    fn into_diag(
1341        self,
1342        dcx: rustc_errors::DiagCtxtHandle<'a>,
1343        level: rustc_errors::Level,
1344    ) -> rustc_errors::Diag<'a> {
1345        rustc_middle::ty::tls::with_opt(
1346            #[track_caller]
1347            |tcx| {
1348                let tcx = tcx.expect("no TyCtxt stored in tls");
1349                let cx_span = self.cx.span();
1350                let mut diag = match self.err {
1351                    QueryErr::Unsupported { def_id, err, .. } => {
1352                        let mut diag =
1353                            dcx.struct_span_err(cx_span, msg!("use of unsupported {$kind}"));
1354                        diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
1355                        if let Some(def_ident_span) = tcx.def_ident_span(def_id) {
1356                            diag.span_note(
1357                                def_ident_span,
1358                                msg!("this {$kind} has unsupported features"),
1359                            );
1360                        }
1361                        diag.note(err.descr);
1362                        diag
1363                    }
1364                    QueryErr::Ignored { def_id } => {
1365                        let mut diag =
1366                            dcx.struct_span_err(cx_span, msg!("use of ignored {$kind} `{$name}`"));
1367                        diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
1368                        diag.arg("name", def_id_to_string(def_id));
1369                        diag.span_label(cx_span, msg!("help: try ignoring or trusting this code"));
1370                        diag
1371                    }
1372                    QueryErr::NotIncluded { def_id } => {
1373                        let mut diag = dcx.struct_span_err(
1374                            cx_span,
1375                            msg!("use of {$kind} `{$name}` that was not included when checking external crate"),
1376                        );
1377                        diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
1378                        diag.arg("name", def_id_to_string(def_id));
1379                        let span = tcx
1380                            .def_ident_span(def_id)
1381                            .unwrap_or_else(|| tcx.def_span(def_id));
1382                        diag.span_help(
1383                            span,
1384                            msg!("when checking external crate, include the file or module where the excluded item is defined"),
1385                        );
1386                        diag
1387                    }
1388                    QueryErr::MissingAssocReft { name, .. } => {
1389                        let mut diag = dcx.struct_span_err(cx_span, MISSING_ASSOC_REFT);
1390                        diag.arg("name", name);
1391                        diag.code(E0999);
1392                        diag
1393                    }
1394                    QueryErr::OpaqueStruct { struct_id } => {
1395                        let mut diag = dcx.struct_span_err(cx_span, OPAQUE_STRUCT);
1396                        diag.arg("struct", tcx.def_path_str(struct_id));
1397                        diag.span_label(
1398                            cx_span,
1399                            msg!("operation accesses the internal representation of `{$struct}`"),
1400                        );
1401                        if let ErrCtxt::FnCheck(_, fn_def_id) = self.cx {
1402                            let fn_span = tcx.def_span(fn_def_id);
1403                            if fn_span.in_derive_expansion() {
1404                                // reset message span to use the type definition
1405                                diag.span_label(
1406                                    tcx.def_span(struct_id),
1407                                    msg!("help: this code was generated by a `#[derive(..)]` and cannot be annotated directly; try annotating this type with `#[flux::trusted_derive]`"),
1408                                );
1409                            } else {
1410                                diag.arg("def_kind", tcx.def_descr(fn_def_id.to_def_id()));
1411                                diag.span_label(
1412                                    fn_span,
1413                                    msg!("help: try annotating this {$def_kind} with `#[trusted]`"),
1414                                );
1415                            }
1416                            diag.note(
1417                                msg!("opaque structs can only be accessed in trusted code (see <https://flux-rs.github.io/flux/guide/specifications.html#opaque-structs>)"),
1418                            );
1419                        }
1420                        diag
1421                    }
1422                    QueryErr::InvalidGenericArg { .. }
1423                    | QueryErr::Emitted(_)
1424                    | QueryErr::Bug { .. } => {
1425                        let mut diag = self.err.into_diag(dcx, level);
1426                        diag.span(cx_span);
1427                        diag
1428                    }
1429                };
1430                diag.code(E0999);
1431                diag
1432            },
1433        )
1434    }
1435}
1436
1437impl From<ErrorGuaranteed> for QueryErr {
1438    fn from(err: ErrorGuaranteed) -> Self {
1439        Self::Emitted(err)
1440    }
1441}
1442
1443pub fn try_query<T>(f: impl FnOnce() -> QueryResult<T>) -> QueryResult<T> {
1444    f()
1445}