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