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, FluxLocalDefId, 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_crate: for<'genv> fn(GlobalEnv<'genv, '_>) -> fhir::FluxItems<'genv>,
163    pub qualifiers: fn(GlobalEnv) -> QueryResult<Vec<rty::Qualifier>>,
164    pub prim_rel: fn(GlobalEnv) -> QueryResult<UnordMap<rty::BinOp, rty::PrimRel>>,
165    pub normalized_defns: fn(GlobalEnv) -> rty::NormalizedDefns,
166    pub func_sort: fn(GlobalEnv, FluxLocalDefId) -> rty::PolyFuncSort,
167    pub adt_sort_def_of: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::AdtSortDef>,
168    pub check_wf: for<'genv> fn(GlobalEnv, LocalDefId) -> QueryResult<Rc<rty::WfckResults>>,
169    pub adt_def: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::AdtDef>,
170    pub constant_info: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::ConstantInfo>,
171    pub type_of: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>>,
172    pub variants_of: fn(
173        GlobalEnv,
174        LocalDefId,
175    ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>,
176    pub fn_sig: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>>,
177    pub generics_of: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::Generics>,
178    pub refinement_generics_of:
179        fn(GlobalEnv, LocalDefId) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>,
180    pub predicates_of:
181        fn(GlobalEnv, LocalDefId) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>>,
182    pub assoc_refinements_of: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::AssocRefinements>,
183    pub sort_of_assoc_reft:
184        fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<rty::EarlyBinder<rty::FuncSort>>,
185    pub assoc_refinement_body:
186        fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<rty::EarlyBinder<rty::Lambda>>,
187    #[allow(clippy::type_complexity)]
188    pub default_assoc_refinement_body:
189        fn(GlobalEnv, FluxId<MaybeExternId>) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>,
190    pub item_bounds: fn(GlobalEnv, LocalDefId) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>>,
191}
192
193macro_rules! empty_query {
194    () => {
195        flux_common::bug!("query not provided")
196    };
197}
198
199impl Default for Providers {
200    fn default() -> Self {
201        Self {
202            collect_specs: |_| empty_query!(),
203            resolve_crate: |_| empty_query!(),
204            desugar: |_, _| empty_query!(),
205            fhir_crate: |_| empty_query!(),
206            normalized_defns: |_| empty_query!(),
207            func_sort: |_, _| empty_query!(),
208            qualifiers: |_| empty_query!(),
209            prim_rel: |_| empty_query!(),
210            adt_sort_def_of: |_, _| empty_query!(),
211            check_wf: |_, _| empty_query!(),
212            adt_def: |_, _| empty_query!(),
213            type_of: |_, _| empty_query!(),
214            variants_of: |_, _| empty_query!(),
215            fn_sig: |_, _| empty_query!(),
216            generics_of: |_, _| empty_query!(),
217            refinement_generics_of: |_, _| empty_query!(),
218            predicates_of: |_, _| empty_query!(),
219            assoc_refinements_of: |_, _| empty_query!(),
220            assoc_refinement_body: |_, _| empty_query!(),
221            default_assoc_refinement_body: |_, _| empty_query!(),
222            sort_of_assoc_reft: |_, _| empty_query!(),
223            item_bounds: |_, _| empty_query!(),
224            constant_info: |_, _| empty_query!(),
225        }
226    }
227}
228
229pub struct Queries<'genv, 'tcx> {
230    pub(crate) providers: Providers,
231    mir: Cache<LocalDefId, QueryResult<Rc<mir::Body<'tcx>>>>,
232    collect_specs: OnceCell<crate::Specs>,
233    resolve_crate: OnceCell<crate::ResolverOutput>,
234    desugar: Cache<LocalDefId, QueryResult<fhir::Node<'genv>>>,
235    fhir_crate: OnceCell<fhir::FluxItems<'genv>>,
236    lower_generics_of: Cache<DefId, ty::Generics<'tcx>>,
237    lower_predicates_of: Cache<DefId, QueryResult<ty::GenericPredicates>>,
238    lower_type_of: Cache<DefId, QueryResult<ty::EarlyBinder<ty::Ty>>>,
239    lower_fn_sig: Cache<DefId, QueryResult<ty::EarlyBinder<ty::PolyFnSig>>>,
240    normalized_defns: Cache<CrateNum, Rc<rty::NormalizedDefns>>,
241    func_sort: Cache<FluxDefId, rty::PolyFuncSort>,
242    qualifiers: OnceCell<QueryResult<Vec<rty::Qualifier>>>,
243    prim_rel: OnceCell<QueryResult<UnordMap<rty::BinOp, rty::PrimRel>>>,
244    adt_sort_def_of: Cache<DefId, QueryResult<rty::AdtSortDef>>,
245    check_wf: Cache<LocalDefId, QueryResult<Rc<rty::WfckResults>>>,
246    adt_def: Cache<DefId, QueryResult<rty::AdtDef>>,
247    constant_info: Cache<DefId, QueryResult<rty::ConstantInfo>>,
248    generics_of: Cache<DefId, QueryResult<rty::Generics>>,
249    refinement_generics_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>>,
250    predicates_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::GenericPredicates>>>,
251    assoc_refinements_of: Cache<DefId, QueryResult<rty::AssocRefinements>>,
252    assoc_refinement_body: Cache<FluxDefId, QueryResult<rty::EarlyBinder<rty::Lambda>>>,
253    default_assoc_refinement_body:
254        Cache<FluxDefId, QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>>,
255    sort_of_assoc_reft: Cache<FluxDefId, QueryResult<rty::EarlyBinder<rty::FuncSort>>>,
256    item_bounds: Cache<DefId, QueryResult<rty::EarlyBinder<List<rty::Clause>>>>,
257    type_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::TyOrCtor>>>,
258    variants_of: Cache<DefId, QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>>,
259    fn_sig: Cache<DefId, QueryResult<rty::EarlyBinder<rty::PolyFnSig>>>,
260    lower_late_bound_vars: Cache<LocalDefId, QueryResult<List<ty::BoundVariableKind>>>,
261}
262
263impl<'genv, 'tcx> Queries<'genv, 'tcx> {
264    pub(crate) fn new(providers: Providers) -> Self {
265        Self {
266            providers,
267            mir: Default::default(),
268            collect_specs: Default::default(),
269            resolve_crate: Default::default(),
270            desugar: Default::default(),
271            fhir_crate: Default::default(),
272            lower_generics_of: Default::default(),
273            lower_predicates_of: Default::default(),
274            lower_type_of: Default::default(),
275            lower_fn_sig: Default::default(),
276            normalized_defns: Default::default(),
277            func_sort: Default::default(),
278            qualifiers: Default::default(),
279            prim_rel: Default::default(),
280            adt_sort_def_of: Default::default(),
281            check_wf: Default::default(),
282            adt_def: Default::default(),
283            constant_info: Default::default(),
284            generics_of: Default::default(),
285            refinement_generics_of: Default::default(),
286            predicates_of: Default::default(),
287            assoc_refinements_of: Default::default(),
288            assoc_refinement_body: Default::default(),
289            default_assoc_refinement_body: Default::default(),
290            sort_of_assoc_reft: Default::default(),
291            item_bounds: Default::default(),
292            type_of: Default::default(),
293            variants_of: Default::default(),
294            fn_sig: Default::default(),
295            lower_late_bound_vars: Default::default(),
296        }
297    }
298
299    pub(crate) fn mir(
300        &self,
301        genv: GlobalEnv<'genv, 'tcx>,
302        def_id: LocalDefId,
303    ) -> QueryResult<Rc<mir::Body<'tcx>>> {
304        run_with_cache(&self.mir, def_id, || {
305            let mir = unsafe { flux_common::mir_storage::retrieve_mir_body(genv.tcx(), def_id) };
306            let mir =
307                lowering::MirLoweringCtxt::lower_mir_body(genv.tcx(), genv.sess(), def_id, mir)?;
308            Ok(Rc::new(mir))
309        })
310    }
311
312    pub(crate) fn collect_specs(&'genv self, genv: GlobalEnv<'genv, 'tcx>) -> &'genv crate::Specs {
313        self.collect_specs
314            .get_or_init(|| (self.providers.collect_specs)(genv))
315    }
316
317    pub(crate) fn resolve_crate(
318        &'genv self,
319        genv: GlobalEnv<'genv, 'tcx>,
320    ) -> &'genv crate::ResolverOutput {
321        self.resolve_crate
322            .get_or_init(|| (self.providers.resolve_crate)(genv))
323    }
324
325    pub(crate) fn desugar(
326        &'genv self,
327        genv: GlobalEnv<'genv, 'tcx>,
328        def_id: LocalDefId,
329    ) -> QueryResult<fhir::Node<'genv>> {
330        if let Some(v) = self.desugar.borrow().get(&def_id) {
331            return v.clone();
332        }
333        match (self.providers.desugar)(genv, def_id) {
334            Ok(nodes) => {
335                let mut cache = self.desugar.borrow_mut();
336                cache.extend_unord(nodes.into_items().map(|(def_id, node)| (def_id, Ok(node))));
337                let Some(res) = cache.get(&def_id) else {
338                    tracked_span_bug!("cannot desugar {def_id:?}")
339                };
340                res.clone()
341            }
342            Err(err) => {
343                self.desugar.borrow_mut().insert(def_id, Err(err.clone()));
344                Err(err)
345            }
346        }
347    }
348
349    pub(crate) fn fhir_crate(
350        &'genv self,
351        genv: GlobalEnv<'genv, 'tcx>,
352    ) -> &'genv fhir::FluxItems<'genv> {
353        self.fhir_crate
354            .get_or_init(|| (self.providers.fhir_crate)(genv))
355    }
356
357    pub(crate) fn lower_generics_of(
358        &self,
359        genv: GlobalEnv<'genv, 'tcx>,
360        def_id: DefId,
361    ) -> ty::Generics<'tcx> {
362        run_with_cache(&self.lower_generics_of, def_id, || {
363            genv.tcx().generics_of(def_id).lower(genv.tcx())
364        })
365    }
366
367    pub(crate) fn lower_predicates_of(
368        &self,
369        genv: GlobalEnv,
370        def_id: DefId,
371    ) -> QueryResult<ty::GenericPredicates> {
372        run_with_cache(&self.lower_predicates_of, def_id, || {
373            genv.tcx()
374                .predicates_of(def_id)
375                .lower(genv.tcx())
376                .map_err(|err| QueryErr::unsupported(def_id, err))
377        })
378    }
379
380    pub(crate) fn lower_type_of(
381        &self,
382        genv: GlobalEnv,
383        def_id: DefId,
384    ) -> QueryResult<ty::EarlyBinder<ty::Ty>> {
385        run_with_cache(&self.lower_type_of, def_id, || {
386            let ty = genv.tcx().type_of(def_id).instantiate_identity();
387            Ok(ty::EarlyBinder(
388                ty.lower(genv.tcx())
389                    .map_err(|err| QueryErr::unsupported(def_id, err.into_err()))?,
390            ))
391        })
392    }
393
394    pub(crate) fn lower_fn_sig(
395        &self,
396        genv: GlobalEnv,
397        def_id: DefId,
398    ) -> QueryResult<ty::EarlyBinder<ty::PolyFnSig>> {
399        run_with_cache(&self.lower_fn_sig, def_id, || {
400            let fn_sig = genv.tcx().fn_sig(def_id).instantiate_identity();
401            Ok(ty::EarlyBinder(
402                fn_sig
403                    .lower(genv.tcx())
404                    .map_err(|err| QueryErr::unsupported(def_id, err.into_err()))?,
405            ))
406        })
407    }
408
409    pub(crate) fn lower_late_bound_vars(
410        &self,
411        genv: GlobalEnv,
412        def_id: LocalDefId,
413    ) -> QueryResult<List<ty::BoundVariableKind>> {
414        run_with_cache(&self.lower_late_bound_vars, def_id, || {
415            let hir_id = genv.tcx().local_def_id_to_hir_id(def_id);
416            genv.tcx()
417                .late_bound_vars(hir_id)
418                .lower(genv.tcx())
419                .map_err(|err| QueryErr::unsupported(def_id.to_def_id(), err.into_err()))
420        })
421    }
422
423    pub(crate) fn normalized_defns(
424        &self,
425        genv: GlobalEnv,
426        krate: CrateNum,
427    ) -> Rc<rty::NormalizedDefns> {
428        run_with_cache(&self.normalized_defns, krate, || {
429            if krate == LOCAL_CRATE {
430                Rc::new((self.providers.normalized_defns)(genv))
431            } else {
432                genv.cstore().normalized_defns(krate)
433            }
434        })
435    }
436
437    pub(crate) fn func_sort(&self, genv: GlobalEnv, def_id: FluxDefId) -> rty::PolyFuncSort {
438        run_with_cache(&self.func_sort, def_id, || {
439            dispatch_query_flux_id(
440                genv,
441                def_id,
442                |def_id| {
443                    // refinement functions cannot be extern specs so we simply grab the local id
444                    (self.providers.func_sort)(genv, def_id.local_id())
445                },
446                |def_id| genv.cstore().func_sort(def_id),
447                |_| {
448                    bug!(
449                        "cannot generate default function sort, the refinement must be defined somewhere"
450                    )
451                },
452            )
453        })
454    }
455
456    pub(crate) fn qualifiers(&self, genv: GlobalEnv) -> QueryResult<&[rty::Qualifier]> {
457        self.qualifiers
458            .get_or_init(|| (self.providers.qualifiers)(genv))
459            .as_deref()
460            .map_err(Clone::clone)
461    }
462
463    pub(crate) fn prim_rel(
464        &self,
465        genv: GlobalEnv,
466    ) -> QueryResult<&UnordMap<rty::BinOp, rty::PrimRel>> {
467        self.prim_rel
468            .get_or_init(|| (self.providers.prim_rel)(genv))
469            .as_ref()
470            .map_err(|err| err.clone())
471    }
472
473    pub(crate) fn adt_sort_def_of(
474        &self,
475        genv: GlobalEnv,
476        def_id: DefId,
477    ) -> QueryResult<rty::AdtSortDef> {
478        run_with_cache(&self.adt_sort_def_of, def_id, || {
479            dispatch_query(
480                genv,
481                def_id,
482                |def_id| (self.providers.adt_sort_def_of)(genv, def_id.local_id()),
483                |def_id| genv.cstore().adt_sort_def(def_id),
484                |def_id| {
485                    let variants = IndexVec::from([rty::AdtSortVariant::new(vec![])]);
486                    Ok(rty::AdtSortDef::new(def_id, vec![], variants, false, true))
487                },
488            )
489        })
490    }
491
492    pub(crate) fn check_wf(
493        &self,
494        genv: GlobalEnv<'genv, '_>,
495        def_id: LocalDefId,
496    ) -> QueryResult<Rc<rty::WfckResults>> {
497        run_with_cache(&self.check_wf, def_id, || (self.providers.check_wf)(genv, def_id))
498    }
499
500    pub(crate) fn constant_info(
501        &self,
502        genv: GlobalEnv,
503        def_id: DefId,
504    ) -> QueryResult<rty::ConstantInfo> {
505        run_with_cache(&self.constant_info, def_id, || {
506            dispatch_query(
507                genv,
508                def_id,
509                |def_id| (self.providers.constant_info)(genv, def_id.local_id()),
510                |def_id| genv.cstore().constant_info(def_id),
511                |def_id| {
512                    // TODO(RJ): fix duplication with [`conv_constant`]` in `flux-fhir-analysis`
513                    let ty = genv.tcx().type_of(def_id).no_bound_vars().unwrap();
514                    if ty.is_integral() {
515                        let val = genv.tcx().const_eval_poly(def_id).ok().and_then(|val| {
516                            let val = val.try_to_scalar_int()?;
517                            rty::Constant::from_scalar_int(genv.tcx(), val, &ty)
518                        });
519                        if let Some(constant_) = val {
520                            return Ok(rty::ConstantInfo::Interpreted(
521                                rty::Expr::constant(constant_),
522                                rty::Sort::Int,
523                            ));
524                        }
525                    }
526                    Ok(rty::ConstantInfo::Uninterpreted)
527                },
528            )
529        })
530    }
531
532    pub(crate) fn adt_def(&self, genv: GlobalEnv, def_id: DefId) -> QueryResult<rty::AdtDef> {
533        run_with_cache(&self.adt_def, def_id, || {
534            dispatch_query(
535                genv,
536                def_id,
537                |def_id| (self.providers.adt_def)(genv, def_id.local_id()),
538                |def_id| genv.cstore().adt_def(def_id),
539                |def_id| {
540                    let adt_def = genv.tcx().adt_def(def_id).lower(genv.tcx());
541                    Ok(rty::AdtDef::new(adt_def, genv.adt_sort_def_of(def_id)?, vec![], false))
542                },
543            )
544        })
545    }
546
547    pub(crate) fn generics_of(&self, genv: GlobalEnv, def_id: DefId) -> QueryResult<rty::Generics> {
548        run_with_cache(&self.generics_of, def_id, || {
549            dispatch_query(
550                genv,
551                def_id,
552                |def_id| (self.providers.generics_of)(genv, def_id.local_id()),
553                |def_id| genv.cstore().generics_of(def_id),
554                |def_id| {
555                    Ok(refining::refine_generics(genv, def_id, &genv.lower_generics_of(def_id)))
556                },
557            )
558        })
559    }
560
561    pub(crate) fn refinement_generics_of(
562        &self,
563        genv: GlobalEnv,
564        def_id: DefId,
565    ) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
566        run_with_cache(&self.refinement_generics_of, def_id, || {
567            dispatch_query(
568                genv,
569                def_id,
570                |def_id| (self.providers.refinement_generics_of)(genv, def_id.local_id()),
571                |def_id| genv.cstore().refinement_generics_of(def_id),
572                |def_id| {
573                    let parent = genv.tcx().generics_of(def_id).parent;
574                    Ok(rty::EarlyBinder(rty::RefinementGenerics {
575                        parent,
576                        parent_count: 0,
577                        own_params: List::empty(),
578                    }))
579                },
580            )
581        })
582    }
583
584    pub(crate) fn item_bounds(
585        &self,
586        genv: GlobalEnv<'genv, 'tcx>,
587        def_id: DefId,
588    ) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>> {
589        run_with_cache(&self.item_bounds, def_id, || {
590            dispatch_query(
591                genv,
592                def_id,
593                |def_id| (self.providers.item_bounds)(genv, def_id.local_id()),
594                |def_id| genv.cstore().item_bounds(def_id),
595                |def_id| {
596                    let clauses = genv
597                        .tcx()
598                        .item_bounds(def_id)
599                        .skip_binder()
600                        .lower(genv.tcx())
601                        .map_err(|err| QueryErr::unsupported(def_id, err))?
602                        .refine(&Refiner::default_for_item(genv, def_id)?)?;
603
604                    Ok(rty::EarlyBinder(clauses))
605                },
606            )
607        })
608    }
609
610    pub(crate) fn predicates_of(
611        &self,
612        genv: GlobalEnv,
613        def_id: DefId,
614    ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
615        run_with_cache(&self.predicates_of, def_id, || {
616            dispatch_query(
617                genv,
618                def_id,
619                |def_id| (self.providers.predicates_of)(genv, def_id.local_id()),
620                |def_id| genv.cstore().predicates_of(def_id),
621                |def_id| {
622                    let predicates = genv
623                        .lower_predicates_of(def_id)?
624                        .refine(&Refiner::default_for_item(genv, def_id)?)?;
625                    Ok(rty::EarlyBinder(predicates))
626                },
627            )
628        })
629    }
630
631    pub(crate) fn assoc_refinements_of(
632        &self,
633        genv: GlobalEnv,
634        def_id: DefId,
635    ) -> QueryResult<rty::AssocRefinements> {
636        run_with_cache(&self.assoc_refinements_of, def_id, || {
637            dispatch_query(
638                genv,
639                def_id,
640                |def_id| (self.providers.assoc_refinements_of)(genv, def_id.local_id()),
641                |def_id| genv.cstore().assoc_refinements_of(def_id),
642                |_| Ok(rty::AssocRefinements::default()),
643            )
644        })
645    }
646
647    pub(crate) fn assoc_refinement_body(
648        &self,
649        genv: GlobalEnv,
650        impl_assoc_id: FluxDefId,
651    ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
652        run_with_cache(&self.assoc_refinement_body, impl_assoc_id, || {
653            dispatch_query_flux_id(
654                genv,
655                impl_assoc_id,
656                |impl_assoc_id| (self.providers.assoc_refinement_body)(genv, impl_assoc_id),
657                |impl_assoc_id| genv.cstore().assoc_refinements_def(impl_assoc_id),
658                |impl_assoc_id| {
659                    Err(query_bug!(
660                        impl_assoc_id.parent(),
661                        "cannot generate default associate refinement for extern impl"
662                    ))
663                },
664            )
665        })
666    }
667
668    pub(crate) fn default_assoc_refinement_body(
669        &self,
670        genv: GlobalEnv,
671        trait_assoc_id: FluxDefId,
672    ) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
673        run_with_cache(&self.default_assoc_refinement_body, trait_assoc_id, || {
674            dispatch_query_flux_id(
675                genv,
676                trait_assoc_id,
677                |trait_assoc_id| {
678                    (self.providers.default_assoc_refinement_body)(genv, trait_assoc_id)
679                },
680                |trait_assoc_id| genv.cstore().default_assoc_refinements_def(trait_assoc_id),
681                |trait_assoc_id| {
682                    Err(query_bug!(
683                        trait_assoc_id.parent(),
684                        "cannot generate default assoc refinement for extern trait"
685                    ))
686                },
687            )
688        })
689    }
690
691    pub(crate) fn sort_of_assoc_reft(
692        &self,
693        genv: GlobalEnv,
694        assoc_id: FluxDefId,
695    ) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
696        run_with_cache(&self.sort_of_assoc_reft, assoc_id, || {
697            dispatch_query_flux_id(
698                genv,
699                assoc_id,
700                |assoc_id| (self.providers.sort_of_assoc_reft)(genv, assoc_id),
701                |assoc_id| genv.cstore().sort_of_assoc_reft(assoc_id),
702                |assoc_id| {
703                    Err(query_bug!(
704                        assoc_id.parent(),
705                        "cannot generate default sort for assoc refinement in extern crate"
706                    ))
707                },
708            )
709        })
710    }
711
712    pub(crate) fn type_of(
713        &self,
714        genv: GlobalEnv,
715        def_id: DefId,
716    ) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
717        run_with_cache(&self.type_of, def_id, || {
718            dispatch_query(
719                genv,
720                def_id,
721                |def_id| (self.providers.type_of)(genv, def_id.local_id()),
722                |def_id| genv.cstore().type_of(def_id),
723                |def_id| {
724                    // If we're given a type parameter, provide the generics of the parent container.
725                    let generics_def_id = match genv.def_kind(def_id) {
726                        DefKind::TyParam => genv.tcx().parent(def_id),
727                        _ => def_id,
728                    };
729                    let ty = genv.lower_type_of(def_id)?.skip_binder();
730                    Ok(rty::EarlyBinder(
731                        Refiner::default_for_item(genv, generics_def_id)?
732                            .refine_ty_or_base(&ty)?
733                            .into(),
734                    ))
735                },
736            )
737        })
738    }
739
740    pub(crate) fn variants_of(
741        &self,
742        genv: GlobalEnv,
743        def_id: DefId,
744    ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
745        run_with_cache(&self.variants_of, def_id, || {
746            dispatch_query(
747                genv,
748                def_id,
749                |def_id| (self.providers.variants_of)(genv, def_id.local_id()),
750                |def_id| genv.cstore().variants(def_id),
751                |def_id| {
752                    let variants = genv
753                        .tcx()
754                        .adt_def(def_id)
755                        .variants()
756                        .indices()
757                        .map(|variant_idx| {
758                            Refiner::default_for_item(genv, def_id)?
759                                .refine_variant_def(def_id, variant_idx)
760                        })
761                        .try_collect()?;
762                    Ok(rty::Opaqueness::Transparent(rty::EarlyBinder(variants)))
763                },
764            )
765        })
766    }
767
768    pub(crate) fn fn_sig(
769        &self,
770        genv: GlobalEnv,
771        def_id: DefId,
772    ) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
773        run_with_cache(&self.fn_sig, def_id, || {
774            dispatch_query(
775                genv,
776                def_id,
777                |def_id| (self.providers.fn_sig)(genv, def_id.local_id()),
778                |def_id| genv.cstore().fn_sig(def_id),
779                |def_id| {
780                    let fn_sig = genv
781                        .lower_fn_sig(def_id)?
782                        .skip_binder()
783                        .refine(&Refiner::default_for_item(genv, def_id)?)?
784                        .hoist_input_binders();
785                    Ok(rty::EarlyBinder(fn_sig))
786                },
787            )
788        })
789    }
790}
791
792/// [Resolve] the `def_id` and *dispatch* it to a provider (`local`, `external`, or `default`).
793///
794/// [Resolve]: GlobalEnv::resolve_id
795fn dispatch_query<R>(
796    genv: GlobalEnv,
797    def_id: DefId,
798    local: impl FnOnce(MaybeExternId) -> R,
799    external: impl FnOnce(DefId) -> Option<R>,
800    default: impl FnOnce(DefId) -> R,
801) -> R {
802    match genv.resolve_id(def_id) {
803        ResolvedDefId::Local(local_id) => {
804            // Case 1: `def_id` is a `LocalDefId` so forward it to the *local provider*
805            local(MaybeExternId::Local(local_id))
806        }
807        ResolvedDefId::ExternSpec(local_id, def_id) => {
808            // Case 2: `def_id` is a `LocalDefId` wrapping an extern spec, so we also
809            // forward it to the local provider
810            local(MaybeExternId::Extern(local_id, def_id))
811        }
812        ResolvedDefId::Extern(def_id) if let Some(v) = external(def_id) => {
813            // Case 3: `def_id` is an external `def_id` for which we have an annotation in the
814            // *external provider*
815            v
816        }
817        ResolvedDefId::Extern(def_id) => {
818            // Case 4: If none of the above, we generate a default annotation
819            default(def_id)
820        }
821    }
822}
823
824fn dispatch_query_flux_id<R>(
825    genv: GlobalEnv,
826    def_id: FluxId<DefId>,
827    local: impl FnOnce(FluxId<MaybeExternId>) -> R,
828    external: impl FnOnce(FluxId<DefId>) -> Option<R>,
829    default: impl FnOnce(FluxId<DefId>) -> R,
830) -> R {
831    #[allow(
832        clippy::disallowed_methods,
833        reason = "we are mapping the parent id to a different representation which still guarantees the existence of the item"
834    )]
835    dispatch_query(
836        genv,
837        def_id.parent(),
838        |container_id| local(FluxId::new(container_id, def_id.name())),
839        |container_id| external(FluxId::new(container_id, def_id.name())),
840        |container_id| default(FluxId::new(container_id, def_id.name())),
841    )
842}
843
844fn run_with_cache<K, V>(cache: &Cache<K, V>, key: K, f: impl FnOnce() -> V) -> V
845where
846    K: std::hash::Hash + Eq,
847    V: Clone,
848{
849    if let Some(v) = cache.borrow().get(&key) {
850        return v.clone();
851    }
852    let v = f();
853    cache.borrow_mut().insert(key, v.clone());
854    v
855}
856
857impl<'a> Diagnostic<'a> for QueryErr {
858    #[track_caller]
859    fn into_diag(
860        self,
861        dcx: rustc_errors::DiagCtxtHandle<'a>,
862        _level: rustc_errors::Level,
863    ) -> rustc_errors::Diag<'a, ErrorGuaranteed> {
864        use crate::fluent_generated as fluent;
865
866        rustc_middle::ty::tls::with_opt(
867            #[track_caller]
868            |tcx| {
869                let tcx = tcx.expect("no TyCtxt stored in tls");
870                match self {
871                    QueryErr::Unsupported { def_id, err } => {
872                        let span = err.span.unwrap_or_else(|| tcx.def_span(def_id));
873                        let mut diag = dcx.struct_span_err(span, fluent::middle_query_unsupported);
874                        diag.code(E0999);
875                        diag.note(err.descr);
876                        diag
877                    }
878                    QueryErr::Ignored { def_id } => {
879                        let def_span = tcx.def_span(def_id);
880                        let mut diag =
881                            dcx.struct_span_err(def_span, fluent::middle_query_ignored_item);
882                        diag.code(E0999);
883                        diag
884                    }
885                    QueryErr::InvalidGenericArg { def_id } => {
886                        let def_span = tcx.def_span(def_id);
887                        let mut diag =
888                            dcx.struct_span_err(def_span, fluent::middle_query_invalid_generic_arg);
889                        diag.code(E0999);
890                        diag
891                    }
892                    QueryErr::MissingAssocReft { impl_id, name, .. } => {
893                        let def_span = tcx.def_span(impl_id);
894                        let mut diag =
895                            dcx.struct_span_err(def_span, fluent::middle_query_missing_assoc_reft);
896                        diag.arg("name", name);
897                        diag.code(E0999);
898                        diag
899                    }
900                    QueryErr::Bug { def_id, location, msg } => {
901                        let mut diag = dcx.struct_err(fluent::middle_query_bug);
902                        if let Some(def_id) = def_id {
903                            diag.span(tcx.def_span(def_id));
904                        }
905                        diag.arg("location", location);
906                        diag.note(msg);
907                        diag
908                    }
909                    QueryErr::Emitted(_) => {
910                        let mut diag = dcx.struct_err("QueryErr::Emitted should be emitted");
911                        diag.downgrade_to_delayed_bug();
912                        diag
913                    }
914                    QueryErr::OpaqueStruct { struct_id } => {
915                        let struct_span = tcx.def_span(struct_id);
916                        let mut diag =
917                            dcx.struct_span_err(struct_span, fluent::middle_query_opaque_struct);
918                        diag.arg("struct", tcx.def_path_str(struct_id));
919                        diag
920                    }
921                }
922            },
923        )
924    }
925}
926
927impl<'a> Diagnostic<'a> for QueryErrAt {
928    #[track_caller]
929    fn into_diag(
930        self,
931        dcx: rustc_errors::DiagCtxtHandle<'a>,
932        level: rustc_errors::Level,
933    ) -> rustc_errors::Diag<'a, ErrorGuaranteed> {
934        use crate::fluent_generated as fluent;
935
936        rustc_middle::ty::tls::with_opt(
937            #[track_caller]
938            |tcx| {
939                let tcx = tcx.expect("no TyCtxt stored in tls");
940                let cx_span = self.cx.span();
941                let mut diag = match self.err {
942                    QueryErr::Unsupported { def_id, err, .. } => {
943                        let mut diag =
944                            dcx.struct_span_err(cx_span, fluent::middle_query_unsupported_at);
945                        diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
946                        if let Some(def_ident_span) = tcx.def_ident_span(def_id) {
947                            diag.span_note(def_ident_span, fluent::_subdiag::note);
948                        }
949                        diag.note(err.descr);
950                        diag
951                    }
952                    QueryErr::Ignored { def_id } => {
953                        let mut diag =
954                            dcx.struct_span_err(cx_span, fluent::middle_query_ignored_at);
955                        diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
956                        diag.arg("name", def_id_to_string(def_id));
957                        diag.span_label(cx_span, fluent::_subdiag::label);
958                        diag
959                    }
960                    QueryErr::MissingAssocReft { name, .. } => {
961                        let mut diag = dcx
962                            .struct_span_err(cx_span, fluent::middle_query_missing_assoc_reft_at);
963                        diag.arg("name", name);
964                        diag.code(E0999);
965                        diag
966                    }
967                    QueryErr::OpaqueStruct { struct_id } => {
968                        let mut diag =
969                            dcx.struct_span_err(cx_span, fluent::middle_query_opaque_struct);
970                        diag.arg("struct", tcx.def_path_str(struct_id));
971                        diag.span_label(cx_span, fluent::_subdiag::label);
972                        if let ErrCtxt::FnCheck(_, fn_def_id) = self.cx {
973                            let fn_span = tcx.def_span(fn_def_id);
974                            diag.arg("def_kind", tcx.def_descr(fn_def_id.to_def_id()));
975                            diag.span_label(fn_span, fluent::middle_query_opaque_struct_help);
976                            diag.note(fluent::middle_query_opaque_struct_note);
977                        }
978                        diag
979                    }
980                    QueryErr::InvalidGenericArg { .. }
981                    | QueryErr::Emitted(_)
982                    | QueryErr::Bug { .. } => {
983                        let mut diag = self.err.into_diag(dcx, level);
984                        diag.span(cx_span);
985                        diag
986                    }
987                };
988                diag.code(E0999);
989                diag
990            },
991        )
992    }
993}
994
995impl From<ErrorGuaranteed> for QueryErr {
996    fn from(err: ErrorGuaranteed) -> Self {
997        Self::Emitted(err)
998    }
999}
1000
1001pub fn try_query<T>(f: impl FnOnce() -> QueryResult<T>) -> QueryResult<T> {
1002    f()
1003}