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_rustc_bridge::{
11    self, def_id_to_string,
12    lowering::{self, Lower, UnsupportedErr},
13    mir::{self},
14    ty,
15};
16use itertools::Itertools;
17use rustc_data_structures::unord::{ExtendUnord, UnordMap};
18use rustc_errors::Diagnostic;
19use rustc_hir::{
20    def::DefKind,
21    def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId},
22};
23use rustc_index::IndexVec;
24use rustc_macros::{Decodable, Encodable};
25use rustc_span::{Span, Symbol};
26
27use crate::{
28    def_id::{FluxDefId, FluxId, MaybeExternId, ResolvedDefId},
29    fhir,
30    global_env::GlobalEnv,
31    rty::{
32        self,
33        refining::{self, Refine, Refiner},
34    },
35};
36
37type Cache<K, V> = RefCell<UnordMap<K, V>>;
38
39pub type QueryResult<T = ()> = Result<T, QueryErr>;
40
41/// An error produced by a query.
42///
43/// We make a distinction between errors reported at def-site and errors reported at use-site.
44///
45/// For most errors reported at the def-site of an item, it makes little sense to check the definition
46/// of dependent items. For example, if a function signature is ill-formed, checking the body of another
47/// function that calls it, can produce confusing errors. In some cases, we can even fail to produce
48/// a signature for a function in which case we can't even check its call sites. For these cases, we
49/// emit an error at the definition site and return a [`QueryErr::Emitted`]. When checking a dependent,
50/// we detect this and early return without reporting any errors at the use-site.
51///
52/// Other errors are better reported at the use-site. For example, if some code calls a function from
53/// an external crate that has unsupported features, we ought to report the error at the call-site,
54/// because it would be confusing to only mention the definition of the external function without
55/// showing which part of the code is calling it. To attach a span to an error one can use [`QueryErr::at`]
56/// to get a [`QueryErrAt`].
57///
58/// Both [`QueryErr`] and [`QueryErrAt`] implement [`Diagnostic`]. The implementation for [`QueryErr`]
59/// reports the error at the definition site, while the implementation for [`QueryErrAt`] reports it at
60/// the (attached) use-site span. This allows us to play a bit lose because we can emit an error without
61/// attaching a span, but this means we may forget to attach spans at some places. We should consider
62/// not implementing [`Diagnostic`] for [`QueryErr`] such that we always make the distinction between
63/// use-site and def-site explicit, e.g., we could have methods `QueryErr::at_use_site` and
64/// `QueryErr::at_def_site` returning types with different implementations of [`Diagnostic`].
65#[derive(Debug, Clone, Encodable, Decodable)]
66pub enum QueryErr {
67    Unsupported {
68        def_id: DefId,
69        err: UnsupportedErr,
70    },
71    Ignored {
72        def_id: DefId,
73    },
74    InvalidGenericArg {
75        def_id: DefId,
76    },
77    MissingAssocReft {
78        impl_id: DefId,
79        trait_id: DefId,
80        name: Symbol,
81    },
82    /// An operation tried to access the internals of an opaque struct.
83    OpaqueStruct {
84        struct_id: DefId,
85    },
86    /// Used to report bugs, typically this means executing an arm in a match we thought it was
87    /// unreachable. Use this instead of panicking if it is easy to return a [`QueryErr`]. Use
88    /// [`QueryErr::bug`] or [`crate::query_bug!`] to construct this variant to track source location.
89    Bug {
90        def_id: Option<DefId>,
91        location: String,
92        msg: String,
93    },
94    Emitted(ErrorGuaranteed),
95}
96
97#[macro_export]
98macro_rules! query_bug {
99    ($fmt:literal $(,$args:expr)* $(,)?) => {
100        $crate::queries::QueryErr::bug(None, format_args!($fmt, $($args),*))
101    };
102    ($def_id:expr, $fmt:literal $(,$args:expr)* $(,)? ) => {{
103        $crate::queries::QueryErr::bug(Some($def_id.into()), format_args!($fmt, $($args),*))
104    }};
105}
106
107impl QueryErr {
108    pub fn unsupported(def_id: DefId, err: UnsupportedErr) -> Self {
109        QueryErr::Unsupported { def_id, err }
110    }
111
112    #[track_caller]
113    pub fn bug(def_id: Option<DefId>, msg: impl ToString) -> Self {
114        QueryErr::Bug {
115            def_id,
116            location: format!("{}", std::panic::Location::caller()),
117            msg: msg.to_string(),
118        }
119    }
120
121    pub fn at(self, cx: impl Into<ErrCtxt>) -> QueryErrAt {
122        QueryErrAt { cx: cx.into(), err: self }
123    }
124}
125
126/// A [`QueryErr`] with extra context information
127pub struct QueryErrAt {
128    cx: ErrCtxt,
129    err: QueryErr,
130}
131
132/// The "use site" context in which an error is reported
133#[derive(Clone, Copy)]
134pub enum ErrCtxt {
135    /// The error was triggered when checking a function body. The `Span` is the span in
136    /// the mir associated with the error. The `LocalDefId` is the id of the function.
137    FnCheck(Span, LocalDefId),
138    /// A miscellaneous context for which we only have a span
139    Misc(Span),
140}
141
142impl From<Span> for ErrCtxt {
143    fn from(v: Span) -> Self {
144        Self::Misc(v)
145    }
146}
147
148impl ErrCtxt {
149    fn span(self) -> Span {
150        match self {
151            ErrCtxt::Misc(span) => span,
152            ErrCtxt::FnCheck(span, _) => span,
153        }
154    }
155}
156
157pub struct Providers {
158    pub collect_specs: fn(GlobalEnv) -> crate::Specs,
159    pub resolve_crate: fn(GlobalEnv) -> crate::ResolverOutput,
160    pub desugar: for<'genv> fn(
161        GlobalEnv<'genv, '_>,
162        LocalDefId,
163    ) -> QueryResult<UnordMap<LocalDefId, fhir::Node<'genv>>>,
164    pub fhir_attr_map: for<'genv> fn(GlobalEnv<'genv, '_>, LocalDefId) -> fhir::AttrMap<'genv>,
165    pub fhir_crate: for<'genv> fn(GlobalEnv<'genv, '_>) -> fhir::FluxItems<'genv>,
166    pub qualifiers: fn(GlobalEnv) -> QueryResult<Vec<rty::Qualifier>>,
167    pub prim_rel: fn(GlobalEnv) -> QueryResult<UnordMap<rty::BinOp, rty::PrimRel>>,
168    pub normalized_defns: fn(GlobalEnv) -> rty::NormalizedDefns,
169    pub func_sort: fn(GlobalEnv, FluxId<MaybeExternId>) -> rty::PolyFuncSort,
170    pub func_span: fn(GlobalEnv, FluxId<MaybeExternId>) -> Span,
171    pub adt_sort_def_of: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::AdtSortDef>,
172    pub check_wf: fn(GlobalEnv, LocalDefId) -> QueryResult<Rc<rty::WfckResults>>,
173    pub adt_def: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::AdtDef>,
174    pub constant_info: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::ConstantInfo>,
175    pub type_of: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>>,
176    pub variants_of: fn(
177        GlobalEnv,
178        MaybeExternId,
179    ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>,
180    pub fn_sig: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>>,
181    pub generics_of: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::Generics>,
182    pub refinement_generics_of:
183        fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>,
184    pub predicates_of:
185        fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>>,
186    pub assoc_refinements_of: fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::AssocRefinements>,
187    pub sort_of_assoc_reft:
188        fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<rty::EarlyBinder<rty::FuncSort>>,
189    pub assoc_refinement_body:
190        fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<rty::EarlyBinder<rty::Lambda>>,
191    #[allow(clippy::type_complexity)]
192    pub default_assoc_refinement_body:
193        fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>,
194    pub item_bounds:
195        fn(GlobalEnv, MaybeExternId) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>>,
196    pub sort_decl_param_count: fn(GlobalEnv, FluxId<MaybeExternId>) -> usize,
197}
198
199macro_rules! empty_query {
200    () => {
201        flux_common::bug!("query not provided")
202    };
203}
204
205impl Default for Providers {
206    fn default() -> Self {
207        Self {
208            collect_specs: |_| empty_query!(),
209            resolve_crate: |_| empty_query!(),
210            desugar: |_, _| empty_query!(),
211            fhir_attr_map: |_, _| empty_query!(),
212            fhir_crate: |_| empty_query!(),
213            normalized_defns: |_| empty_query!(),
214            func_sort: |_, _| empty_query!(),
215            func_span: |_, _| empty_query!(),
216            qualifiers: |_| empty_query!(),
217            prim_rel: |_| empty_query!(),
218            adt_sort_def_of: |_, _| empty_query!(),
219            check_wf: |_, _| empty_query!(),
220            adt_def: |_, _| empty_query!(),
221            type_of: |_, _| empty_query!(),
222            variants_of: |_, _| empty_query!(),
223            fn_sig: |_, _| empty_query!(),
224            generics_of: |_, _| empty_query!(),
225            refinement_generics_of: |_, _| empty_query!(),
226            predicates_of: |_, _| empty_query!(),
227            assoc_refinements_of: |_, _| empty_query!(),
228            assoc_refinement_body: |_, _| empty_query!(),
229            default_assoc_refinement_body: |_, _| empty_query!(),
230            sort_of_assoc_reft: |_, _| empty_query!(),
231            item_bounds: |_, _| empty_query!(),
232            constant_info: |_, _| empty_query!(),
233            sort_decl_param_count: |_, _| empty_query!(),
234        }
235    }
236}
237
238pub struct Queries<'genv, 'tcx> {
239    pub(crate) providers: Providers,
240    mir: Cache<LocalDefId, QueryResult<Rc<mir::BodyRoot<'tcx>>>>,
241    collect_specs: OnceCell<crate::Specs>,
242    resolve_crate: OnceCell<crate::ResolverOutput>,
243    desugar: Cache<LocalDefId, QueryResult<fhir::Node<'genv>>>,
244    fhir_attr_map: Cache<LocalDefId, fhir::AttrMap<'genv>>,
245    fhir_crate: OnceCell<fhir::FluxItems<'genv>>,
246    lower_generics_of: Cache<DefId, ty::Generics<'tcx>>,
247    lower_predicates_of: Cache<DefId, QueryResult<ty::GenericPredicates>>,
248    lower_type_of: Cache<DefId, QueryResult<ty::EarlyBinder<ty::Ty>>>,
249    lower_fn_sig: Cache<DefId, QueryResult<ty::EarlyBinder<ty::PolyFnSig>>>,
250    normalized_defns: Cache<CrateNum, Rc<rty::NormalizedDefns>>,
251    func_sort: Cache<FluxDefId, rty::PolyFuncSort>,
252    func_span: Cache<FluxDefId, Span>,
253    qualifiers: OnceCell<QueryResult<Vec<rty::Qualifier>>>,
254    prim_rel: OnceCell<QueryResult<UnordMap<rty::BinOp, rty::PrimRel>>>,
255    adt_sort_def_of: Cache<DefId, QueryResult<rty::AdtSortDef>>,
256    check_wf: Cache<LocalDefId, QueryResult<Rc<rty::WfckResults>>>,
257    adt_def: Cache<DefId, QueryResult<rty::AdtDef>>,
258    constant_info: Cache<DefId, QueryResult<rty::ConstantInfo>>,
259    generics_of: Cache<DefId, QueryResult<rty::Generics>>,
260    refinement_generics_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>>,
261    predicates_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::GenericPredicates>>>,
262    assoc_refinements_of: Cache<DefId, QueryResult<rty::AssocRefinements>>,
263    assoc_refinement_body: Cache<FluxDefId, QueryResult<rty::EarlyBinder<rty::Lambda>>>,
264    default_assoc_refinement_body:
265        Cache<FluxDefId, QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>>,
266    sort_of_assoc_reft: Cache<FluxDefId, QueryResult<rty::EarlyBinder<rty::FuncSort>>>,
267    item_bounds: Cache<DefId, QueryResult<rty::EarlyBinder<List<rty::Clause>>>>,
268    type_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::TyOrCtor>>>,
269    variants_of: Cache<DefId, QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>>,
270    fn_sig: Cache<DefId, QueryResult<rty::EarlyBinder<rty::PolyFnSig>>>,
271    lower_late_bound_vars: Cache<LocalDefId, QueryResult<List<ty::BoundVariableKind>>>,
272    sort_decl_param_count: Cache<FluxDefId, usize>,
273    no_panic: Cache<DefId, bool>,
274}
275
276impl<'genv, 'tcx> Queries<'genv, 'tcx> {
277    pub(crate) fn new(providers: Providers) -> Self {
278        Self {
279            providers,
280            mir: Default::default(),
281            collect_specs: Default::default(),
282            resolve_crate: Default::default(),
283            desugar: Default::default(),
284            fhir_attr_map: Default::default(),
285            fhir_crate: Default::default(),
286            lower_generics_of: Default::default(),
287            lower_predicates_of: Default::default(),
288            lower_type_of: Default::default(),
289            lower_fn_sig: Default::default(),
290            normalized_defns: Default::default(),
291            func_sort: Default::default(),
292            func_span: Default::default(),
293            qualifiers: Default::default(),
294            prim_rel: Default::default(),
295            adt_sort_def_of: Default::default(),
296            check_wf: Default::default(),
297            adt_def: Default::default(),
298            constant_info: Default::default(),
299            generics_of: Default::default(),
300            refinement_generics_of: Default::default(),
301            predicates_of: Default::default(),
302            assoc_refinements_of: Default::default(),
303            assoc_refinement_body: Default::default(),
304            default_assoc_refinement_body: Default::default(),
305            sort_of_assoc_reft: Default::default(),
306            item_bounds: Default::default(),
307            type_of: Default::default(),
308            variants_of: Default::default(),
309            fn_sig: Default::default(),
310            lower_late_bound_vars: Default::default(),
311            sort_decl_param_count: Default::default(),
312            no_panic: Default::default(),
313        }
314    }
315
316    pub(crate) fn mir(
317        &self,
318        genv: GlobalEnv<'genv, 'tcx>,
319        def_id: LocalDefId,
320    ) -> QueryResult<Rc<mir::BodyRoot<'tcx>>> {
321        run_with_cache(&self.mir, def_id, || {
322            let mir = unsafe { flux_common::mir_storage::retrieve_mir_body(genv.tcx(), def_id) };
323            let mir =
324                lowering::MirLoweringCtxt::lower_mir_body(genv.tcx(), genv.sess(), def_id, mir)?;
325            Ok(Rc::new(mir))
326        })
327    }
328
329    pub(crate) fn collect_specs(&'genv self, genv: GlobalEnv<'genv, 'tcx>) -> &'genv crate::Specs {
330        self.collect_specs
331            .get_or_init(|| (self.providers.collect_specs)(genv))
332    }
333
334    pub(crate) fn resolve_crate(
335        &'genv self,
336        genv: GlobalEnv<'genv, 'tcx>,
337    ) -> &'genv crate::ResolverOutput {
338        self.resolve_crate
339            .get_or_init(|| (self.providers.resolve_crate)(genv))
340    }
341
342    pub(crate) fn desugar(
343        &'genv self,
344        genv: GlobalEnv<'genv, 'tcx>,
345        def_id: LocalDefId,
346    ) -> QueryResult<fhir::Node<'genv>> {
347        if let Some(v) = self.desugar.borrow().get(&def_id) {
348            return v.clone();
349        }
350        match (self.providers.desugar)(genv, def_id) {
351            Ok(nodes) => {
352                let mut cache = self.desugar.borrow_mut();
353                cache.extend_unord(nodes.into_items().map(|(def_id, node)| (def_id, Ok(node))));
354                let Some(res) = cache.get(&def_id) else {
355                    tracked_span_bug!("cannot desugar {def_id:?}")
356                };
357                res.clone()
358            }
359            Err(err) => {
360                self.desugar.borrow_mut().insert(def_id, Err(err.clone()));
361                Err(err)
362            }
363        }
364    }
365
366    pub(crate) fn fhir_attr_map(
367        &'genv self,
368        genv: GlobalEnv<'genv, 'tcx>,
369        def_id: LocalDefId,
370    ) -> fhir::AttrMap<'genv> {
371        run_with_cache(&self.fhir_attr_map, def_id, || (self.providers.fhir_attr_map)(genv, def_id))
372    }
373
374    pub(crate) fn fhir_crate(
375        &'genv self,
376        genv: GlobalEnv<'genv, 'tcx>,
377    ) -> &'genv fhir::FluxItems<'genv> {
378        self.fhir_crate
379            .get_or_init(|| (self.providers.fhir_crate)(genv))
380    }
381
382    pub(crate) fn lower_generics_of(
383        &self,
384        genv: GlobalEnv<'genv, 'tcx>,
385        def_id: DefId,
386    ) -> ty::Generics<'tcx> {
387        run_with_cache(&self.lower_generics_of, def_id, || {
388            genv.tcx().generics_of(def_id).lower(genv.tcx())
389        })
390    }
391
392    pub(crate) fn lower_predicates_of(
393        &self,
394        genv: GlobalEnv,
395        def_id: DefId,
396    ) -> QueryResult<ty::GenericPredicates> {
397        run_with_cache(&self.lower_predicates_of, def_id, || {
398            genv.tcx()
399                .predicates_of(def_id)
400                .lower(genv.tcx())
401                .map_err(|err| QueryErr::unsupported(def_id, err))
402        })
403    }
404
405    pub(crate) fn lower_type_of(
406        &self,
407        genv: GlobalEnv,
408        def_id: DefId,
409    ) -> QueryResult<ty::EarlyBinder<ty::Ty>> {
410        run_with_cache(&self.lower_type_of, def_id, || {
411            let ty = genv.tcx().type_of(def_id).instantiate_identity();
412            Ok(ty::EarlyBinder(
413                ty.lower(genv.tcx())
414                    .map_err(|err| QueryErr::unsupported(def_id, err.into_err()))?,
415            ))
416        })
417    }
418
419    pub(crate) fn lower_fn_sig(
420        &self,
421        genv: GlobalEnv,
422        def_id: DefId,
423    ) -> QueryResult<ty::EarlyBinder<ty::PolyFnSig>> {
424        run_with_cache(&self.lower_fn_sig, def_id, || {
425            let fn_sig = genv.tcx().fn_sig(def_id).instantiate_identity();
426            Ok(ty::EarlyBinder(
427                fn_sig
428                    .lower(genv.tcx())
429                    .map_err(|err| QueryErr::unsupported(def_id, err.into_err()))?,
430            ))
431        })
432    }
433
434    pub(crate) fn lower_late_bound_vars(
435        &self,
436        genv: GlobalEnv,
437        def_id: LocalDefId,
438    ) -> QueryResult<List<ty::BoundVariableKind>> {
439        run_with_cache(&self.lower_late_bound_vars, def_id, || {
440            let hir_id = genv.tcx().local_def_id_to_hir_id(def_id);
441            genv.tcx()
442                .late_bound_vars(hir_id)
443                .lower(genv.tcx())
444                .map_err(|err| QueryErr::unsupported(def_id.to_def_id(), err.into_err()))
445        })
446    }
447
448    pub(crate) fn normalized_defns(
449        &self,
450        genv: GlobalEnv,
451        krate: CrateNum,
452    ) -> Rc<rty::NormalizedDefns> {
453        run_with_cache(&self.normalized_defns, krate, || {
454            if krate == LOCAL_CRATE {
455                Rc::new((self.providers.normalized_defns)(genv))
456            } else {
457                genv.cstore().normalized_defns(krate)
458            }
459        })
460    }
461
462    pub(crate) fn func_sort(&self, genv: GlobalEnv, def_id: FluxDefId) -> rty::PolyFuncSort {
463        run_with_cache(&self.func_sort, def_id, || {
464            def_id.dispatch_query(
465                genv,
466                |def_id| {
467                    // refinement functions cannot be extern specs so we simply grab the local id
468                    (self.providers.func_sort)(genv, def_id)
469                },
470                |def_id| genv.cstore().func_sort(def_id),
471                |_| {
472                    bug!(
473                        "cannot generate default function sort, the refinement must be defined somewhere"
474                    )
475                },
476            )
477        })
478    }
479
480    pub(crate) fn func_span(&self, genv: GlobalEnv, def_id: FluxDefId) -> Span {
481        run_with_cache(&self.func_span, def_id, || {
482            def_id.dispatch_query(
483                genv,
484                |def_id| {
485                    // refinement functions cannot be extern specs so we simply grab the local id
486                    (self.providers.func_span)(genv, def_id)
487                },
488                |def_id| genv.cstore().func_span(def_id),
489                |_|
490                bug!(
491                        "cannot generate default function sort, the refinement must be defined somewhere"
492                    )
493                ,
494            )
495        })
496    }
497
498    pub(crate) fn qualifiers(&self, genv: GlobalEnv) -> QueryResult<&[rty::Qualifier]> {
499        self.qualifiers
500            .get_or_init(|| (self.providers.qualifiers)(genv))
501            .as_deref()
502            .map_err(Clone::clone)
503    }
504
505    pub(crate) fn prim_rel(
506        &self,
507        genv: GlobalEnv,
508    ) -> QueryResult<&UnordMap<rty::BinOp, rty::PrimRel>> {
509        self.prim_rel
510            .get_or_init(|| (self.providers.prim_rel)(genv))
511            .as_ref()
512            .map_err(|err| err.clone())
513    }
514
515    pub(crate) fn adt_sort_def_of(
516        &self,
517        genv: GlobalEnv,
518        def_id: DefId,
519    ) -> QueryResult<rty::AdtSortDef> {
520        run_with_cache(&self.adt_sort_def_of, def_id, || {
521            def_id.dispatch_query(
522                genv,
523                |def_id| (self.providers.adt_sort_def_of)(genv, def_id),
524                |def_id| genv.cstore().adt_sort_def(def_id),
525                |def_id| {
526                    let variants = IndexVec::from([rty::AdtSortVariant::new(vec![])]);
527                    Ok(rty::AdtSortDef::new(def_id, vec![], variants, false, true))
528                },
529            )
530        })
531    }
532
533    pub(crate) fn sort_decl_param_count(&self, genv: GlobalEnv, def_id: FluxDefId) -> usize {
534        run_with_cache(&self.sort_decl_param_count, def_id, || {
535            def_id.dispatch_query(
536                genv,
537                |def_id| {
538                    (self.providers.sort_decl_param_count)(genv, def_id)
539                },
540                |def_id| genv.cstore().sort_decl_param_count(def_id),
541                |_| {
542                    bug!(
543                        "cannot generate default param count for sort declaration, it must be defined somewhere"
544                    )
545                }
546            )
547        })
548    }
549
550    pub(crate) fn check_wf(
551        &self,
552        genv: GlobalEnv<'genv, '_>,
553        def_id: LocalDefId,
554    ) -> QueryResult<Rc<rty::WfckResults>> {
555        run_with_cache(&self.check_wf, def_id, || (self.providers.check_wf)(genv, def_id))
556    }
557
558    pub(crate) fn constant_info(
559        &self,
560        genv: GlobalEnv,
561        def_id: DefId,
562    ) -> QueryResult<rty::ConstantInfo> {
563        run_with_cache(&self.constant_info, def_id, || {
564            def_id.dispatch_query(
565                genv,
566                |def_id| (self.providers.constant_info)(genv, def_id),
567                |def_id| genv.cstore().constant_info(def_id),
568                |def_id| {
569                    // TODO(RJ): fix duplication with [`conv_constant`]` in `flux-fhir-analysis`
570                    let ty = genv.tcx().type_of(def_id).no_bound_vars().unwrap();
571                    if ty.is_integral() {
572                        let val = genv.tcx().const_eval_poly(def_id).ok().and_then(|val| {
573                            let val = val.try_to_scalar_int()?;
574                            rty::Constant::from_scalar_int(genv.tcx(), val, &ty)
575                        });
576                        if let Some(constant_) = val {
577                            return Ok(rty::ConstantInfo::Interpreted(
578                                rty::Expr::constant(constant_),
579                                rty::Sort::Int,
580                            ));
581                        }
582                    }
583                    Ok(rty::ConstantInfo::Uninterpreted)
584                },
585            )
586        })
587    }
588
589    pub(crate) fn no_panic(&self, genv: GlobalEnv, def_id: DefId) -> bool {
590        run_with_cache(&self.no_panic, def_id, || {
591            def_id.dispatch_query(
592                genv,
593                |def_id| {
594                    let mut current_id = def_id.local_id();
595
596                    // Walk up the entire parent chain within this closure
597                    loop {
598                        // Skip dummy items
599                        if genv.is_dummy(current_id) {
600                            if let Some(parent) = genv.tcx().opt_local_parent(current_id) {
601                                current_id = parent;
602                                continue;
603                            } else {
604                                return false; // Reached top without finding non-dummy
605                            }
606                        }
607
608                        // Check if current non-dummy item has the `no_panic` attribute
609                        if genv.fhir_attr_map(current_id).no_panic() {
610                            return true;
611                        }
612
613                        // Move to the next parent
614                        if let Some(parent) = genv.tcx().opt_local_parent(current_id) {
615                            current_id = parent;
616                        } else {
617                            break; // Reached the top
618                        }
619                    }
620
621                    config::no_panic()
622                },
623                |def_id| genv.cstore().no_panic(def_id),
624                |_| false,
625            )
626        })
627    }
628
629    pub(crate) fn adt_def(&self, genv: GlobalEnv, def_id: DefId) -> QueryResult<rty::AdtDef> {
630        run_with_cache(&self.adt_def, def_id, || {
631            def_id.dispatch_query(
632                genv,
633                |def_id| (self.providers.adt_def)(genv, def_id),
634                |def_id| genv.cstore().adt_def(def_id),
635                |def_id| {
636                    let adt_def = genv.tcx().adt_def(def_id).lower(genv.tcx());
637                    Ok(rty::AdtDef::new(adt_def, genv.adt_sort_def_of(def_id)?, vec![], false))
638                },
639            )
640        })
641    }
642
643    pub(crate) fn generics_of(&self, genv: GlobalEnv, def_id: DefId) -> QueryResult<rty::Generics> {
644        run_with_cache(&self.generics_of, def_id, || {
645            def_id.dispatch_query(
646                genv,
647                |def_id| (self.providers.generics_of)(genv, def_id),
648                |def_id| genv.cstore().generics_of(def_id),
649                |def_id| {
650                    Ok(refining::refine_generics(genv, def_id, &genv.lower_generics_of(def_id)))
651                },
652            )
653        })
654    }
655
656    pub(crate) fn refinement_generics_of(
657        &self,
658        genv: GlobalEnv,
659        def_id: DefId,
660    ) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
661        run_with_cache(&self.refinement_generics_of, def_id, || {
662            def_id.dispatch_query(
663                genv,
664                |def_id| (self.providers.refinement_generics_of)(genv, def_id),
665                |def_id| genv.cstore().refinement_generics_of(def_id),
666                |def_id| {
667                    let parent = genv.tcx().generics_of(def_id).parent;
668                    Ok(rty::EarlyBinder(rty::RefinementGenerics {
669                        parent,
670                        parent_count: 0,
671                        own_params: List::empty(),
672                    }))
673                },
674            )
675        })
676    }
677
678    pub(crate) fn item_bounds(
679        &self,
680        genv: GlobalEnv<'genv, 'tcx>,
681        def_id: DefId,
682    ) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>> {
683        run_with_cache(&self.item_bounds, def_id, || {
684            def_id.dispatch_query(
685                genv,
686                |def_id| (self.providers.item_bounds)(genv, def_id),
687                |def_id| genv.cstore().item_bounds(def_id),
688                |def_id| {
689                    let clauses = genv
690                        .tcx()
691                        .item_bounds(def_id)
692                        .skip_binder()
693                        .lower(genv.tcx())
694                        .map_err(|err| QueryErr::unsupported(def_id, err))?
695                        .refine(&Refiner::default_for_item(genv, def_id)?)?;
696
697                    Ok(rty::EarlyBinder(clauses))
698                },
699            )
700        })
701    }
702
703    pub(crate) fn predicates_of(
704        &self,
705        genv: GlobalEnv,
706        def_id: DefId,
707    ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
708        run_with_cache(&self.predicates_of, def_id, || {
709            def_id.dispatch_query(
710                genv,
711                |def_id| (self.providers.predicates_of)(genv, def_id),
712                |def_id| genv.cstore().predicates_of(def_id),
713                |def_id| {
714                    let predicates = genv
715                        .lower_predicates_of(def_id)?
716                        .refine(&Refiner::default_for_item(genv, def_id)?)?;
717                    Ok(rty::EarlyBinder(predicates))
718                },
719            )
720        })
721    }
722
723    pub(crate) fn assoc_refinements_of(
724        &self,
725        genv: GlobalEnv,
726        def_id: DefId,
727    ) -> QueryResult<rty::AssocRefinements> {
728        run_with_cache(&self.assoc_refinements_of, def_id, || {
729            def_id.dispatch_query(
730                genv,
731                |def_id| (self.providers.assoc_refinements_of)(genv, def_id),
732                |def_id| genv.cstore().assoc_refinements_of(def_id),
733                |def_id| Ok(genv.builtin_assoc_refts(def_id).unwrap_or_default()),
734            )
735        })
736    }
737
738    pub(crate) fn assoc_refinement_body(
739        &self,
740        genv: GlobalEnv,
741        impl_assoc_id: FluxDefId,
742    ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
743        run_with_cache(&self.assoc_refinement_body, impl_assoc_id, || {
744            impl_assoc_id.dispatch_query(
745                genv,
746                |impl_assoc_id| (self.providers.assoc_refinement_body)(genv, impl_assoc_id),
747                |impl_assoc_id| genv.cstore().assoc_refinements_def(impl_assoc_id),
748                |impl_assoc_id| {
749                    Err(query_bug!(
750                        impl_assoc_id.parent(),
751                        "cannot generate default associate refinement for extern impl"
752                    ))
753                },
754            )
755        })
756    }
757
758    pub(crate) fn default_assoc_refinement_body(
759        &self,
760        genv: GlobalEnv,
761        trait_assoc_id: FluxDefId,
762    ) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
763        run_with_cache(&self.default_assoc_refinement_body, trait_assoc_id, || {
764            trait_assoc_id.dispatch_query(
765                genv,
766                |trait_assoc_id| {
767                    (self.providers.default_assoc_refinement_body)(genv, trait_assoc_id)
768                },
769                |trait_assoc_id| genv.cstore().default_assoc_refinements_def(trait_assoc_id),
770                |trait_assoc_id| {
771                    Err(query_bug!(
772                        trait_assoc_id.parent(),
773                        "cannot generate default assoc refinement for extern trait"
774                    ))
775                },
776            )
777        })
778    }
779
780    pub(crate) fn sort_of_assoc_reft(
781        &self,
782        genv: GlobalEnv,
783        assoc_id: FluxDefId,
784    ) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
785        run_with_cache(&self.sort_of_assoc_reft, assoc_id, || {
786            assoc_id.dispatch_query(
787                genv,
788                |assoc_id| (self.providers.sort_of_assoc_reft)(genv, assoc_id),
789                |assoc_id| genv.cstore().sort_of_assoc_reft(assoc_id),
790                |assoc_id| {
791                    genv.builtin_assoc_reft_sort(assoc_id).ok_or_else(|| {
792                        query_bug!(
793                            assoc_id.parent(),
794                            "assoc refinement on extern crate is not builtin"
795                        )
796                    })
797                },
798            )
799        })
800    }
801
802    pub(crate) fn type_of(
803        &self,
804        genv: GlobalEnv,
805        def_id: DefId,
806    ) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
807        run_with_cache(&self.type_of, def_id, || {
808            def_id.dispatch_query(
809                genv,
810                |def_id| (self.providers.type_of)(genv, def_id),
811                |def_id| genv.cstore().type_of(def_id),
812                |def_id| {
813                    // If we're given a type parameter, provide the generics of the parent container.
814                    let generics_def_id = match genv.def_kind(def_id) {
815                        DefKind::TyParam => genv.tcx().parent(def_id),
816                        _ => def_id,
817                    };
818                    let ty = genv.lower_type_of(def_id)?.skip_binder();
819                    Ok(rty::EarlyBinder(
820                        Refiner::default_for_item(genv, generics_def_id)?
821                            .refine_ty_or_base(&ty)?
822                            .into(),
823                    ))
824                },
825            )
826        })
827    }
828
829    pub(crate) fn variants_of(
830        &self,
831        genv: GlobalEnv,
832        def_id: DefId,
833    ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
834        run_with_cache(&self.variants_of, def_id, || {
835            def_id.dispatch_query(
836                genv,
837                |def_id| (self.providers.variants_of)(genv, def_id),
838                |def_id| genv.cstore().variants_of(def_id),
839                |def_id| {
840                    let variants = genv
841                        .tcx()
842                        .adt_def(def_id)
843                        .variants()
844                        .indices()
845                        .map(|variant_idx| {
846                            Refiner::default_for_item(genv, def_id)?
847                                .refine_variant_def(def_id, variant_idx)
848                        })
849                        .try_collect()?;
850                    Ok(rty::Opaqueness::Transparent(rty::EarlyBinder(variants)))
851                },
852            )
853        })
854    }
855
856    pub(crate) fn fn_sig(
857        &self,
858        genv: GlobalEnv,
859        def_id: DefId,
860    ) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
861        run_with_cache(&self.fn_sig, def_id, || {
862            def_id.dispatch_query(
863                genv,
864                |def_id| (self.providers.fn_sig)(genv, def_id),
865                |def_id| genv.cstore().fn_sig(def_id),
866                |def_id| {
867                    let fn_sig = genv
868                        .lower_fn_sig(def_id)?
869                        .skip_binder()
870                        .refine(&Refiner::default_for_item(genv, def_id)?)?
871                        .hoist_input_binders();
872                    Ok(rty::EarlyBinder(fn_sig))
873                },
874            )
875        })
876    }
877}
878
879/// Logic to *dispatch* a `def_id` to a provider (`local`, `external`, or `default`).
880/// This is a trait so it can be implemented for [`DefId`] and for [`FluxDefId`].
881trait DispatchKey: Sized {
882    type LocalId;
883
884    fn dispatch_query<R>(
885        self,
886        genv: GlobalEnv,
887        local: impl FnOnce(Self::LocalId) -> R,
888        external: impl FnOnce(Self) -> Option<R>,
889        default: impl FnOnce(Self) -> R,
890    ) -> R;
891}
892
893impl DispatchKey for DefId {
894    type LocalId = MaybeExternId;
895
896    fn dispatch_query<R>(
897        self,
898        genv: GlobalEnv,
899        local: impl FnOnce(MaybeExternId) -> R,
900        external: impl FnOnce(Self) -> Option<R>,
901        default: impl FnOnce(Self) -> R,
902    ) -> R {
903        match genv.resolve_id(self) {
904            ResolvedDefId::Local(local_id) => {
905                // Case 1: `def_id` is a `LocalDefId` so forward it to the *local provider*
906                local(MaybeExternId::Local(local_id))
907            }
908            ResolvedDefId::ExternSpec(local_id, def_id) => {
909                // Case 2: `def_id` is a `LocalDefId` wrapping an extern spec, so we also
910                // forward it to the local provider
911                local(MaybeExternId::Extern(local_id, def_id))
912            }
913            ResolvedDefId::Extern(def_id) if let Some(v) = external(def_id) => {
914                // Case 3: `def_id` is an external `def_id` for which we have an annotation in the
915                // *external provider*
916                v
917            }
918            ResolvedDefId::Extern(def_id) => {
919                // Case 4: If none of the above, we generate a default annotation
920                default(def_id)
921            }
922        }
923    }
924}
925
926impl DispatchKey for FluxDefId {
927    type LocalId = FluxId<MaybeExternId>;
928
929    fn dispatch_query<R>(
930        self,
931        genv: GlobalEnv,
932        local: impl FnOnce(FluxId<MaybeExternId>) -> R,
933        external: impl FnOnce(FluxId<DefId>) -> Option<R>,
934        default: impl FnOnce(FluxId<DefId>) -> R,
935    ) -> R {
936        #[allow(
937            clippy::disallowed_methods,
938            reason = "we are mapping the parent id to a different representation which still guarantees the existence of the item"
939        )]
940        self.parent().dispatch_query(
941            genv,
942            |container_id| local(FluxId::new(container_id, self.name())),
943            |container_id| external(FluxId::new(container_id, self.name())),
944            |container_id| default(FluxId::new(container_id, self.name())),
945        )
946    }
947}
948
949fn run_with_cache<K, V>(cache: &Cache<K, V>, key: K, f: impl FnOnce() -> V) -> V
950where
951    K: std::hash::Hash + Eq,
952    V: Clone,
953{
954    if let Some(v) = cache.borrow().get(&key) {
955        return v.clone();
956    }
957    let v = f();
958    cache.borrow_mut().insert(key, v.clone());
959    v
960}
961
962impl<'a> Diagnostic<'a> for QueryErr {
963    #[track_caller]
964    fn into_diag(
965        self,
966        dcx: rustc_errors::DiagCtxtHandle<'a>,
967        _level: rustc_errors::Level,
968    ) -> rustc_errors::Diag<'a, ErrorGuaranteed> {
969        use crate::fluent_generated as fluent;
970
971        rustc_middle::ty::tls::with_opt(
972            #[track_caller]
973            |tcx| {
974                let tcx = tcx.expect("no TyCtxt stored in tls");
975                match self {
976                    QueryErr::Unsupported { def_id, err } => {
977                        let span = err.span.unwrap_or_else(|| tcx.def_span(def_id));
978                        let mut diag = dcx.struct_span_err(span, fluent::middle_query_unsupported);
979                        diag.code(E0999);
980                        diag.note(err.descr);
981                        diag
982                    }
983                    QueryErr::Ignored { def_id } => {
984                        let def_span = tcx.def_span(def_id);
985                        let mut diag =
986                            dcx.struct_span_err(def_span, fluent::middle_query_ignored_item);
987                        diag.code(E0999);
988                        diag
989                    }
990                    QueryErr::InvalidGenericArg { def_id } => {
991                        let def_span = tcx.def_span(def_id);
992                        let mut diag =
993                            dcx.struct_span_err(def_span, fluent::middle_query_invalid_generic_arg);
994                        diag.code(E0999);
995                        diag
996                    }
997                    QueryErr::MissingAssocReft { impl_id, name, .. } => {
998                        let def_span = tcx.def_span(impl_id);
999                        let mut diag =
1000                            dcx.struct_span_err(def_span, fluent::middle_query_missing_assoc_reft);
1001                        diag.arg("name", name);
1002                        diag.code(E0999);
1003                        diag
1004                    }
1005                    QueryErr::Bug { def_id, location, msg } => {
1006                        let mut diag = dcx.struct_err(fluent::middle_query_bug);
1007                        if let Some(def_id) = def_id {
1008                            diag.span(tcx.def_span(def_id));
1009                        }
1010                        diag.arg("location", location);
1011                        diag.note(msg);
1012                        diag
1013                    }
1014                    QueryErr::Emitted(_) => {
1015                        let mut diag = dcx.struct_err("QueryErr::Emitted should be emitted");
1016                        diag.downgrade_to_delayed_bug();
1017                        diag
1018                    }
1019                    QueryErr::OpaqueStruct { struct_id } => {
1020                        let struct_span = tcx.def_span(struct_id);
1021                        let mut diag =
1022                            dcx.struct_span_err(struct_span, fluent::middle_query_opaque_struct);
1023                        diag.arg("struct", tcx.def_path_str(struct_id));
1024                        diag
1025                    }
1026                }
1027            },
1028        )
1029    }
1030}
1031
1032impl<'a> Diagnostic<'a> for QueryErrAt {
1033    #[track_caller]
1034    fn into_diag(
1035        self,
1036        dcx: rustc_errors::DiagCtxtHandle<'a>,
1037        level: rustc_errors::Level,
1038    ) -> rustc_errors::Diag<'a, ErrorGuaranteed> {
1039        use crate::fluent_generated as fluent;
1040
1041        rustc_middle::ty::tls::with_opt(
1042            #[track_caller]
1043            |tcx| {
1044                let tcx = tcx.expect("no TyCtxt stored in tls");
1045                let cx_span = self.cx.span();
1046                let mut diag = match self.err {
1047                    QueryErr::Unsupported { def_id, err, .. } => {
1048                        let mut diag =
1049                            dcx.struct_span_err(cx_span, fluent::middle_query_unsupported_at);
1050                        diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
1051                        if let Some(def_ident_span) = tcx.def_ident_span(def_id) {
1052                            diag.span_note(def_ident_span, fluent::_subdiag::note);
1053                        }
1054                        diag.note(err.descr);
1055                        diag
1056                    }
1057                    QueryErr::Ignored { def_id } => {
1058                        let mut diag =
1059                            dcx.struct_span_err(cx_span, fluent::middle_query_ignored_at);
1060                        diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
1061                        diag.arg("name", def_id_to_string(def_id));
1062                        diag.span_label(cx_span, fluent::_subdiag::label);
1063                        diag
1064                    }
1065                    QueryErr::MissingAssocReft { name, .. } => {
1066                        let mut diag = dcx
1067                            .struct_span_err(cx_span, fluent::middle_query_missing_assoc_reft_at);
1068                        diag.arg("name", name);
1069                        diag.code(E0999);
1070                        diag
1071                    }
1072                    QueryErr::OpaqueStruct { struct_id } => {
1073                        let mut diag =
1074                            dcx.struct_span_err(cx_span, fluent::middle_query_opaque_struct);
1075                        diag.arg("struct", tcx.def_path_str(struct_id));
1076                        diag.span_label(cx_span, fluent::_subdiag::label);
1077                        if let ErrCtxt::FnCheck(_, fn_def_id) = self.cx {
1078                            let fn_span = tcx.def_span(fn_def_id);
1079                            diag.arg("def_kind", tcx.def_descr(fn_def_id.to_def_id()));
1080                            diag.span_label(fn_span, fluent::middle_query_opaque_struct_help);
1081                            diag.note(fluent::middle_query_opaque_struct_note);
1082                        }
1083                        diag
1084                    }
1085                    QueryErr::InvalidGenericArg { .. }
1086                    | QueryErr::Emitted(_)
1087                    | QueryErr::Bug { .. } => {
1088                        let mut diag = self.err.into_diag(dcx, level);
1089                        diag.span(cx_span);
1090                        diag
1091                    }
1092                };
1093                diag.code(E0999);
1094                diag
1095            },
1096        )
1097    }
1098}
1099
1100impl From<ErrorGuaranteed> for QueryErr {
1101    fn from(err: ErrorGuaranteed) -> Self {
1102        Self::Emitted(err)
1103    }
1104}
1105
1106pub fn try_query<T>(f: impl FnOnce() -> QueryResult<T>) -> QueryResult<T> {
1107    f()
1108}