Skip to main content

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