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