flux_middle/
queries.rs

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