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, 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    desugar: Cache<LocalDefId, QueryResult<fhir::Node<'genv>>>,
265    fhir_attr_map: Cache<LocalDefId, fhir::AttrMap<'genv>>,
266    fhir_crate: OnceCell<fhir::FluxItems<'genv>>,
267    lower_generics_of: Cache<DefId, ty::Generics<'tcx>>,
268    lower_predicates_of: Cache<DefId, QueryResult<ty::GenericPredicates>>,
269    lower_type_of: Cache<DefId, QueryResult<ty::EarlyBinder<ty::Ty>>>,
270    lower_fn_sig: Cache<DefId, QueryResult<ty::EarlyBinder<ty::PolyFnSig>>>,
271    normalized_defns: Cache<CrateNum, Rc<rty::NormalizedDefns>>,
272    func_sort: Cache<FluxDefId, rty::PolyFuncSort>,
273    func_span: Cache<FluxDefId, Span>,
274    qualifiers: OnceCell<QueryResult<Vec<rty::Qualifier>>>,
275    prim_rel: OnceCell<QueryResult<UnordMap<rty::BinOp, rty::PrimRel>>>,
276    adt_sort_def_of: Cache<DefId, QueryResult<rty::AdtSortDef>>,
277    check_wf: Cache<LocalDefId, QueryResult<Rc<rty::WfckResults>>>,
278    adt_def: Cache<DefId, QueryResult<rty::AdtDef>>,
279    constant_info: Cache<DefId, QueryResult<rty::ConstantInfo>>,
280    static_info: Cache<DefId, QueryResult<rty::StaticInfo>>,
281    generics_of: Cache<DefId, QueryResult<rty::Generics>>,
282    refinement_generics_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>>,
283    predicates_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::GenericPredicates>>>,
284    assoc_refinements_of: Cache<DefId, QueryResult<rty::AssocRefinements>>,
285    assoc_refinement_body: Cache<FluxDefId, QueryResult<rty::EarlyBinder<rty::Lambda>>>,
286    default_assoc_refinement_body:
287        Cache<FluxDefId, QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>>,
288    sort_of_assoc_reft: Cache<FluxDefId, QueryResult<rty::EarlyBinder<rty::FuncSort>>>,
289    item_bounds: Cache<DefId, QueryResult<rty::EarlyBinder<List<rty::Clause>>>>,
290    type_of: Cache<DefId, QueryResult<rty::EarlyBinder<rty::TyOrCtor>>>,
291    variants_of: Cache<DefId, QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>>,
292    fn_sig: Cache<DefId, QueryResult<rty::EarlyBinder<rty::PolyFnSig>>>,
293    sort_decl_param_count: Cache<FluxDefId, usize>,
294    no_panic: Cache<DefId, bool>,
295    assume_parametric_params: Cache<DefId, UnordSet<u32>>,
296    call_graph: OnceCell<CallGraph<'tcx>>,
297    /// The no-panic inference result for the local crate, keyed by `NodeKey`.
298    inferred_no_panic: OnceCell<Rc<UnordMap<NodeKey<'tcx>, PanicSpec>>>,
299}
300
301impl<'genv, 'tcx> Queries<'genv, 'tcx> {
302    pub(crate) fn new(providers: Providers) -> Self {
303        Self {
304            providers,
305            queried_def_ids: RefCell::new(UnordSet::new()),
306            mir: Default::default(),
307            collect_specs: Default::default(),
308            resolve_crate: Default::default(),
309            desugar: Default::default(),
310            fhir_attr_map: Default::default(),
311            fhir_crate: Default::default(),
312            lower_generics_of: Default::default(),
313            lower_predicates_of: Default::default(),
314            lower_type_of: Default::default(),
315            lower_fn_sig: Default::default(),
316            normalized_defns: Default::default(),
317            func_sort: Default::default(),
318            func_span: Default::default(),
319            qualifiers: Default::default(),
320            prim_rel: Default::default(),
321            adt_sort_def_of: Default::default(),
322            check_wf: Default::default(),
323            adt_def: Default::default(),
324            constant_info: Default::default(),
325            static_info: Default::default(),
326            generics_of: Default::default(),
327            refinement_generics_of: Default::default(),
328            predicates_of: Default::default(),
329            assoc_refinements_of: Default::default(),
330            assoc_refinement_body: Default::default(),
331            default_assoc_refinement_body: Default::default(),
332            sort_of_assoc_reft: Default::default(),
333            item_bounds: Default::default(),
334            type_of: Default::default(),
335            variants_of: Default::default(),
336            fn_sig: Default::default(),
337            sort_decl_param_count: Default::default(),
338            no_panic: Default::default(),
339            assume_parametric_params: Default::default(),
340            call_graph: Default::default(),
341            inferred_no_panic: Default::default(),
342        }
343    }
344
345    pub(crate) fn queried(&self, def_id: DefId) -> bool {
346        self.queried_def_ids.borrow().contains(&def_id)
347    }
348
349    pub(crate) fn mir(
350        &self,
351        genv: GlobalEnv<'genv, 'tcx>,
352        def_id: LocalDefId,
353    ) -> QueryResult<Rc<mir::BodyRoot<'tcx>>> {
354        run_with_cache(&self.mir, def_id, || {
355            let mir = unsafe { flux_common::mir_storage::retrieve_mir_body(genv.tcx(), def_id) };
356            let mir =
357                lowering::MirLoweringCtxt::lower_mir_body(genv.tcx(), genv.sess(), def_id, mir)?;
358            Ok(Rc::new(mir))
359        })
360    }
361
362    pub(crate) fn collect_specs(&'genv self, genv: GlobalEnv<'genv, 'tcx>) -> &'genv crate::Specs {
363        self.collect_specs
364            .get_or_init(|| (self.providers.collect_specs)(genv))
365    }
366
367    pub(crate) fn resolve_crate(
368        &'genv self,
369        genv: GlobalEnv<'genv, 'tcx>,
370    ) -> &'genv crate::ResolverOutput {
371        self.resolve_crate
372            .get_or_init(|| (self.providers.resolve_crate)(genv))
373    }
374
375    pub(crate) fn desugar(
376        &'genv self,
377        genv: GlobalEnv<'genv, 'tcx>,
378        def_id: LocalDefId,
379    ) -> QueryResult<fhir::Node<'genv>> {
380        if let Some(v) = self.desugar.borrow().get(&def_id) {
381            return v.clone();
382        }
383        match (self.providers.desugar)(genv, def_id) {
384            Ok(nodes) => {
385                let mut cache = self.desugar.borrow_mut();
386                cache.extend_unord(nodes.into_items().map(|(def_id, node)| (def_id, Ok(node))));
387                let Some(res) = cache.get(&def_id) else {
388                    tracked_span_bug!("cannot desugar {def_id:?}")
389                };
390                res.clone()
391            }
392            Err(err) => {
393                self.desugar.borrow_mut().insert(def_id, Err(err.clone()));
394                Err(err)
395            }
396        }
397    }
398
399    pub(crate) fn fhir_attr_map(
400        &'genv self,
401        genv: GlobalEnv<'genv, 'tcx>,
402        def_id: LocalDefId,
403    ) -> fhir::AttrMap<'genv> {
404        run_with_cache(&self.fhir_attr_map, def_id, || (self.providers.fhir_attr_map)(genv, def_id))
405    }
406
407    pub(crate) fn fhir_crate(
408        &'genv self,
409        genv: GlobalEnv<'genv, 'tcx>,
410    ) -> &'genv fhir::FluxItems<'genv> {
411        self.fhir_crate
412            .get_or_init(|| (self.providers.fhir_crate)(genv))
413    }
414
415    pub(crate) fn lower_generics_of(
416        &self,
417        genv: GlobalEnv<'genv, 'tcx>,
418        def_id: DefId,
419    ) -> ty::Generics<'tcx> {
420        run_with_cache(&self.lower_generics_of, def_id, || {
421            genv.tcx().generics_of(def_id).lower(genv.tcx())
422        })
423    }
424
425    pub(crate) fn lower_predicates_of(
426        &self,
427        genv: GlobalEnv,
428        def_id: DefId,
429    ) -> QueryResult<ty::GenericPredicates> {
430        run_with_cache(&self.lower_predicates_of, def_id, || {
431            genv.tcx()
432                .predicates_of(def_id)
433                .lower(genv.tcx())
434                .map_err(|err| QueryErr::unsupported(def_id, err))
435        })
436    }
437
438    pub(crate) fn lower_type_of(
439        &self,
440        genv: GlobalEnv,
441        def_id: DefId,
442    ) -> QueryResult<ty::EarlyBinder<ty::Ty>> {
443        run_with_cache(&self.lower_type_of, def_id, || {
444            let ty = genv.tcx().type_of(def_id).instantiate_identity();
445            Ok(ty::EarlyBinder(
446                ty.lower(genv.tcx())
447                    .map_err(|err| QueryErr::unsupported(def_id, err.into_err()))?,
448            ))
449        })
450    }
451
452    pub(crate) fn lower_fn_sig(
453        &self,
454        genv: GlobalEnv,
455        def_id: DefId,
456    ) -> QueryResult<ty::EarlyBinder<ty::PolyFnSig>> {
457        run_with_cache(&self.lower_fn_sig, def_id, || {
458            let fn_sig = genv.tcx().fn_sig(def_id).instantiate_identity();
459            Ok(ty::EarlyBinder(
460                fn_sig
461                    .lower(genv.tcx())
462                    .map_err(|err| QueryErr::unsupported(def_id, err.into_err()))?,
463            ))
464        })
465    }
466
467    pub(crate) fn normalized_defns(
468        &self,
469        genv: GlobalEnv,
470        krate: CrateNum,
471    ) -> Rc<rty::NormalizedDefns> {
472        run_with_cache(&self.normalized_defns, krate, || {
473            if krate == LOCAL_CRATE {
474                Rc::new((self.providers.normalized_defns)(genv))
475            } else {
476                genv.cstore().normalized_defns(krate)
477            }
478        })
479    }
480
481    pub(crate) fn func_sort(&self, genv: GlobalEnv, def_id: FluxDefId) -> rty::PolyFuncSort {
482        run_with_cache(&self.func_sort, def_id, || {
483            def_id.dispatch_query(
484                genv,
485                self,
486                |def_id| {
487                    // refinement functions cannot be extern specs so we simply grab the local id
488                    (self.providers.func_sort)(genv, def_id)
489                },
490                |def_id| genv.cstore().func_sort(def_id),
491                |_| {
492                    bug!(
493                        "cannot generate default function sort, the refinement must be defined somewhere"
494                    )
495                },
496            )
497        })
498    }
499
500    pub(crate) fn func_span(&self, genv: GlobalEnv, def_id: FluxDefId) -> Span {
501        run_with_cache(&self.func_span, def_id, || {
502            def_id.dispatch_query(
503                genv,
504                self,
505                |def_id| {
506                    // refinement functions cannot be extern specs so we simply grab the local id
507                    (self.providers.func_span)(genv, def_id)
508                },
509                |def_id| genv.cstore().func_span(def_id),
510                |_|
511                bug!(
512                        "cannot generate default function sort, the refinement must be defined somewhere"
513                    )
514                ,
515            )
516        })
517    }
518
519    pub(crate) fn qualifiers(&self, genv: GlobalEnv) -> QueryResult<&[rty::Qualifier]> {
520        self.qualifiers
521            .get_or_init(|| (self.providers.qualifiers)(genv))
522            .as_deref()
523            .map_err(Clone::clone)
524    }
525
526    pub(crate) fn prim_rel(
527        &self,
528        genv: GlobalEnv,
529    ) -> QueryResult<&UnordMap<rty::BinOp, rty::PrimRel>> {
530        self.prim_rel
531            .get_or_init(|| (self.providers.prim_rel)(genv))
532            .as_ref()
533            .map_err(|err| err.clone())
534    }
535
536    pub(crate) fn adt_sort_def_of(
537        &self,
538        genv: GlobalEnv,
539        def_id: DefId,
540    ) -> QueryResult<rty::AdtSortDef> {
541        run_with_cache(&self.adt_sort_def_of, def_id, || {
542            def_id.dispatch_query(
543                genv,
544                self,
545                |def_id| (self.providers.adt_sort_def_of)(genv, def_id),
546                |def_id| genv.cstore().adt_sort_def(def_id),
547                |def_id| {
548                    let variants = IndexVec::from([rty::AdtSortVariant::new(vec![])]);
549                    Ok(rty::AdtSortDef::new(def_id, vec![], variants, false, true))
550                },
551            )
552        })
553    }
554
555    pub(crate) fn sort_decl_param_count(&self, genv: GlobalEnv, def_id: FluxDefId) -> usize {
556        run_with_cache(&self.sort_decl_param_count, def_id, || {
557            def_id.dispatch_query(
558                genv,
559                self,
560                |def_id| {
561                    (self.providers.sort_decl_param_count)(genv, def_id)
562                },
563                |def_id| genv.cstore().sort_decl_param_count(def_id),
564                |_| {
565                    bug!(
566                        "cannot generate default param count for sort declaration, it must be defined somewhere"
567                    )
568                }
569            )
570        })
571    }
572
573    pub(crate) fn check_wf(
574        &self,
575        genv: GlobalEnv<'genv, '_>,
576        def_id: LocalDefId,
577    ) -> QueryResult<Rc<rty::WfckResults>> {
578        run_with_cache(&self.check_wf, def_id, || (self.providers.check_wf)(genv, def_id))
579    }
580
581    pub(crate) fn constant_info(
582        &self,
583        genv: GlobalEnv,
584        def_id: DefId,
585    ) -> QueryResult<rty::ConstantInfo> {
586        run_with_cache(&self.constant_info, def_id, || {
587            def_id.dispatch_query(
588                genv,
589                self,
590                |def_id| (self.providers.constant_info)(genv, def_id),
591                |def_id| genv.cstore().constant_info(def_id),
592                |def_id| {
593                    // TODO(RJ): fix duplication with [`conv_constant`]` in `flux-fhir-analysis`
594                    let ty = genv.tcx().type_of(def_id).no_bound_vars().unwrap();
595                    if ty.is_integral() {
596                        let val = genv.tcx().const_eval_poly(def_id).ok().and_then(|val| {
597                            let val = val.try_to_scalar_int()?;
598                            rty::Constant::from_scalar_int(genv.tcx(), val, &ty)
599                        });
600                        if let Some(constant_) = val {
601                            return Ok(rty::ConstantInfo::Interpreted(
602                                rty::Expr::constant(constant_),
603                                rty::Sort::Int,
604                            ));
605                        }
606                    }
607                    Ok(rty::ConstantInfo::Uninterpreted)
608                },
609            )
610        })
611    }
612
613    pub fn call_graph(&'genv self, genv: GlobalEnv<'genv, 'tcx>) -> &'genv CallGraph<'tcx> {
614        self.call_graph
615            .get_or_init(|| (self.providers.call_graph)(genv))
616    }
617
618    /// The no-panic inference result for the local crate, keyed by `NodeKey`.
619    pub fn inferred_no_panic(
620        &'genv self,
621        genv: GlobalEnv<'genv, 'tcx>,
622    ) -> Rc<UnordMap<NodeKey<'tcx>, PanicSpec>> {
623        self.inferred_no_panic
624            .get_or_init(|| Rc::new((self.providers.inferred_no_panic)(genv)))
625            .clone()
626    }
627
628    pub(crate) fn static_info(
629        &self,
630        genv: GlobalEnv,
631        def_id: DefId,
632    ) -> QueryResult<rty::StaticInfo> {
633        run_with_cache(&self.static_info, def_id, || {
634            def_id.dispatch_query(
635                genv,
636                self,
637                |def_id| (self.providers.static_info)(genv, def_id),
638                |def_id| genv.cstore().static_info(def_id),
639                |_def_id| Ok(rty::StaticInfo::Unknown),
640            )
641        })
642    }
643
644    pub(crate) fn no_panic(&self, genv: GlobalEnv, def_id: DefId) -> bool {
645        run_with_cache(&self.no_panic, def_id, || {
646            def_id.dispatch_query(
647                genv,
648                self,
649                |def_id| {
650                    let mut current_id = def_id.local_id();
651
652                    // Walk up the entire parent chain within this closure
653                    loop {
654                        // Skip dummy items
655                        if genv.is_dummy(current_id) {
656                            if let Some(parent) = genv.tcx().opt_local_parent(current_id) {
657                                current_id = parent;
658                                continue;
659                            } else {
660                                return false; // Reached top without finding non-dummy
661                            }
662                        }
663
664                        // Check if current non-dummy item has the `no_panic` attribute
665                        if genv.fhir_attr_map(current_id).no_panic() {
666                            return true;
667                        }
668
669                        // Move to the next parent
670                        if let Some(parent) = genv.tcx().opt_local_parent(current_id) {
671                            current_id = parent;
672                        } else {
673                            break; // Reached the top
674                        }
675                    }
676
677                    config::no_panic()
678                },
679                |def_id| genv.cstore().no_panic(def_id),
680                |_| false,
681            )
682        })
683    }
684
685    pub(crate) fn assume_parametric_params(&self, genv: GlobalEnv, def_id: DefId) -> UnordSet<u32> {
686        run_with_cache(&self.assume_parametric_params, def_id, || {
687            def_id.dispatch_query(
688                genv,
689                self,
690                |def_id| {
691                    let tcx = genv.tcx();
692                    let generics = tcx.generics_of(def_id);
693                    genv.fhir_attr_map(def_id.local_id())
694                        .parametric_params()
695                        .iter()
696                        .map(|param_id| generics.param_def_id_to_index(tcx, *param_id).unwrap())
697                        .collect()
698                },
699                |def_id| genv.cstore().assume_parametric_params(def_id),
700                |_| UnordSet::default(),
701            )
702        })
703    }
704
705    pub(crate) fn adt_def(&self, genv: GlobalEnv, def_id: DefId) -> QueryResult<rty::AdtDef> {
706        run_with_cache(&self.adt_def, def_id, || {
707            def_id.dispatch_query(
708                genv,
709                self,
710                |def_id| (self.providers.adt_def)(genv, def_id),
711                |def_id| genv.cstore().adt_def(def_id),
712                |def_id| {
713                    let adt_def = genv.tcx().adt_def(def_id).lower(genv.tcx());
714                    Ok(rty::AdtDef::new(adt_def, genv.adt_sort_def_of(def_id)?, vec![], false))
715                },
716            )
717        })
718    }
719
720    pub(crate) fn generics_of(&self, genv: GlobalEnv, def_id: DefId) -> QueryResult<rty::Generics> {
721        // Box is special: its first type parameter (the pointee `T`) is refined as a `Type` rather
722        // than a `Base`. This allows refinements to "see through" the Box, similar to how references
723        // work.
724        if genv.tcx().is_lang_item(def_id, LangItem::OwnedBox) {
725            let generics = genv.lower_generics_of(def_id);
726            debug_assert_eq!(generics.params.len(), 2);
727            let deref_ty = &generics.params[0];
728            let alloc = &generics.params[1];
729            return Ok(rty::Generics {
730                own_params: List::from_arr([
731                    refine_generic_param_def(true, deref_ty),
732                    refine_generic_param_def(false, alloc),
733                ]),
734                parent: generics.parent(),
735                parent_count: generics.parent_count(),
736                has_self: generics.orig.has_self,
737            });
738        }
739        // `MetaSized` is a marker trait with a single `Self` type parameter. We refine it as `Type`
740        // (rather than `Base`) so that a type parameter `T` of kind `Type` can flow through bounds
741        // like `T: MetaSized`. This is required because `Box` is defined as `Box<T: ?Sized, ...>`
742        // which desugars to the bound `T: MetaSized`. This should be mostly fine because parameters
743        // of both kinds should be able to satisfy `MetaSized` bounds, but it will cause problems
744        // if we ever try to add associated refinements to `MetaSized` like we did for `Sized`.
745        if genv.tcx().is_lang_item(def_id, LangItem::MetaSized) {
746            let generics = genv.lower_generics_of(def_id);
747            debug_assert_eq!(generics.params.len(), 1);
748            let self_ty = &generics.params[0];
749            return Ok(rty::Generics {
750                own_params: List::from_arr([refine_generic_param_def(true, self_ty)]),
751                parent: generics.parent(),
752                parent_count: generics.parent_count(),
753                has_self: generics.orig.has_self,
754            });
755        }
756
757        run_with_cache(&self.generics_of, def_id, || {
758            def_id.dispatch_query(
759                genv,
760                self,
761                |def_id| (self.providers.generics_of)(genv, def_id),
762                |def_id| genv.cstore().generics_of(def_id),
763                |def_id| Ok(refining::refine_generics(&genv.lower_generics_of(def_id))),
764            )
765        })
766    }
767
768    pub(crate) fn refinement_generics_of(
769        &self,
770        genv: GlobalEnv,
771        def_id: DefId,
772    ) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
773        run_with_cache(&self.refinement_generics_of, def_id, || {
774            def_id.dispatch_query(
775                genv,
776                self,
777                |def_id| (self.providers.refinement_generics_of)(genv, def_id),
778                |def_id| genv.cstore().refinement_generics_of(def_id),
779                |def_id| {
780                    let parent = genv.tcx().generics_of(def_id).parent;
781                    Ok(rty::EarlyBinder(rty::RefinementGenerics {
782                        parent,
783                        parent_count: 0,
784                        own_params: List::empty(),
785                    }))
786                },
787            )
788        })
789    }
790
791    pub(crate) fn item_bounds(
792        &self,
793        genv: GlobalEnv<'genv, 'tcx>,
794        def_id: DefId,
795    ) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>> {
796        run_with_cache(&self.item_bounds, def_id, || {
797            def_id.dispatch_query(
798                genv,
799                self,
800                |def_id| (self.providers.item_bounds)(genv, def_id),
801                |def_id| genv.cstore().item_bounds(def_id),
802                |def_id| {
803                    let clauses = genv
804                        .tcx()
805                        .item_bounds(def_id)
806                        .skip_binder()
807                        .lower(genv.tcx())
808                        .map_err(|err| QueryErr::unsupported(def_id, err))?
809                        .refine(&Refiner::default_for_item(genv, def_id)?)?;
810
811                    Ok(rty::EarlyBinder(clauses))
812                },
813            )
814        })
815    }
816
817    pub(crate) fn predicates_of(
818        &self,
819        genv: GlobalEnv,
820        def_id: DefId,
821    ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
822        run_with_cache(&self.predicates_of, def_id, || {
823            def_id.dispatch_query(
824                genv,
825                self,
826                |def_id| (self.providers.predicates_of)(genv, def_id),
827                |def_id| genv.cstore().predicates_of(def_id),
828                |def_id| {
829                    let predicates = genv
830                        .lower_predicates_of(def_id)?
831                        .refine(&Refiner::default_for_item(genv, def_id)?)?;
832                    Ok(rty::EarlyBinder(predicates))
833                },
834            )
835        })
836    }
837
838    pub(crate) fn assoc_refinements_of(
839        &self,
840        genv: GlobalEnv,
841        def_id: DefId,
842    ) -> QueryResult<rty::AssocRefinements> {
843        run_with_cache(&self.assoc_refinements_of, def_id, || {
844            def_id.dispatch_query(
845                genv,
846                self,
847                |def_id| (self.providers.assoc_refinements_of)(genv, def_id),
848                |def_id| genv.cstore().assoc_refinements_of(def_id),
849                |def_id| Ok(genv.builtin_assoc_refts(def_id).unwrap_or_default()),
850            )
851        })
852    }
853
854    pub(crate) fn assoc_refinement_body(
855        &self,
856        genv: GlobalEnv,
857        impl_assoc_id: FluxDefId,
858    ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
859        run_with_cache(&self.assoc_refinement_body, impl_assoc_id, || {
860            impl_assoc_id.dispatch_query(
861                genv,
862                self,
863                |impl_assoc_id| (self.providers.assoc_refinement_body)(genv, impl_assoc_id),
864                |impl_assoc_id| genv.cstore().assoc_refinements_def(impl_assoc_id),
865                |impl_assoc_id| {
866                    Err(query_bug!(
867                        impl_assoc_id.parent(),
868                        "cannot generate default associate refinement for extern impl"
869                    ))
870                },
871            )
872        })
873    }
874
875    pub(crate) fn default_assoc_refinement_body(
876        &self,
877        genv: GlobalEnv,
878        trait_assoc_id: FluxDefId,
879    ) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
880        run_with_cache(&self.default_assoc_refinement_body, trait_assoc_id, || {
881            trait_assoc_id.dispatch_query(
882                genv,
883                self,
884                |trait_assoc_id| {
885                    (self.providers.default_assoc_refinement_body)(genv, trait_assoc_id)
886                },
887                |trait_assoc_id| genv.cstore().default_assoc_refinements_def(trait_assoc_id),
888                |trait_assoc_id| {
889                    Err(query_bug!(
890                        trait_assoc_id.parent(),
891                        "cannot generate default assoc refinement for extern trait"
892                    ))
893                },
894            )
895        })
896    }
897
898    pub(crate) fn sort_of_assoc_reft(
899        &self,
900        genv: GlobalEnv,
901        assoc_id: FluxDefId,
902    ) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
903        run_with_cache(&self.sort_of_assoc_reft, assoc_id, || {
904            assoc_id.dispatch_query(
905                genv,
906                self,
907                |assoc_id| (self.providers.sort_of_assoc_reft)(genv, assoc_id),
908                |assoc_id| genv.cstore().sort_of_assoc_reft(assoc_id),
909                |assoc_id| {
910                    genv.builtin_assoc_reft_sort(assoc_id).ok_or_else(|| {
911                        query_bug!(
912                            assoc_id.parent(),
913                            "assoc refinement on extern crate is not builtin"
914                        )
915                    })
916                },
917            )
918        })
919    }
920
921    pub(crate) fn type_of(
922        &self,
923        genv: GlobalEnv,
924        def_id: DefId,
925    ) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
926        run_with_cache(&self.type_of, def_id, || {
927            def_id.dispatch_query(
928                genv,
929                self,
930                |def_id| (self.providers.type_of)(genv, def_id),
931                |def_id| genv.cstore().type_of(def_id),
932                |def_id| {
933                    // If we're given a type parameter, provide the generics of the parent container.
934                    let generics_def_id = match genv.def_kind(def_id) {
935                        DefKind::TyParam => genv.tcx().parent(def_id),
936                        _ => def_id,
937                    };
938                    let ty = genv.lower_type_of(def_id)?.skip_binder();
939                    Ok(rty::EarlyBinder(
940                        Refiner::default_for_item(genv, generics_def_id)?
941                            .refine_ty_or_base(&ty)?
942                            .into(),
943                    ))
944                },
945            )
946        })
947    }
948
949    pub(crate) fn variants_of(
950        &self,
951        genv: GlobalEnv,
952        def_id: DefId,
953    ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
954        run_with_cache(&self.variants_of, def_id, || {
955            def_id.dispatch_query(
956                genv,
957                self,
958                |def_id| (self.providers.variants_of)(genv, def_id),
959                |def_id| genv.cstore().variants_of(def_id),
960                |def_id| {
961                    let variants = genv
962                        .tcx()
963                        .adt_def(def_id)
964                        .variants()
965                        .indices()
966                        .map(|variant_idx| {
967                            Refiner::default_for_item(genv, def_id)?
968                                .refine_variant_def(def_id, variant_idx)
969                        })
970                        .try_collect()?;
971                    Ok(rty::Opaqueness::Transparent(rty::EarlyBinder(variants)))
972                },
973            )
974        })
975    }
976
977    pub(crate) fn fn_sig(
978        &self,
979        genv: GlobalEnv,
980        def_id: DefId,
981    ) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
982        run_with_cache(&self.fn_sig, def_id, || {
983            def_id.dispatch_query(
984                genv,
985                self,
986                |def_id| (self.providers.fn_sig)(genv, def_id),
987                |def_id| genv.cstore().fn_sig(def_id),
988                |def_id| {
989                    let tcx = genv.tcx();
990
991                    let mut poly_sig = genv
992                        .lower_fn_sig(def_id)?
993                        .skip_binder()
994                        .refine(&Refiner::default_for_item(genv, def_id)?)?
995                        .hoist_input_binders();
996
997                    if genv.is_fn_call(def_id) {
998                        let fn_once_id = tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP);
999
1000                        let fn_once_no_panic = genv
1001                            .builtin_assoc_refts(fn_once_id)
1002                            .unwrap()
1003                            .find(sym::no_panic)
1004                            .unwrap();
1005
1006                        let args = GenericArg::identity_for_item(genv, fn_once_id)?;
1007
1008                        let alias_reft = AliasReft { assoc_id: fn_once_no_panic.def_id, args };
1009
1010                        poly_sig = poly_sig.map(|mut fn_sig| {
1011                            fn_sig.no_panic = Expr::alias(alias_reft, List::empty());
1012                            fn_sig
1013                        });
1014                    }
1015
1016                    Ok(rty::EarlyBinder(poly_sig))
1017                },
1018            )
1019        })
1020    }
1021}
1022
1023/// Logic to *dispatch* a `def_id` to a provider (`local`, `external`, or `default`).
1024/// This is a trait so it can be implemented for [`DefId`] and for [`FluxDefId`].
1025pub trait DispatchKey: Sized + Copy {
1026    type LocalId;
1027
1028    fn dispatch_query<R>(
1029        self,
1030        genv: GlobalEnv,
1031        queries: &Queries,
1032        local: impl FnOnce(Self::LocalId) -> R,
1033        external: impl FnOnce(Self) -> Option<R>,
1034        default: impl FnOnce(Self) -> R,
1035    ) -> R;
1036
1037    fn def_id(self) -> DefId;
1038}
1039
1040impl DispatchKey for DefId {
1041    type LocalId = MaybeExternId;
1042
1043    fn dispatch_query<R>(
1044        self,
1045        genv: GlobalEnv,
1046        queries: &Queries,
1047        local: impl FnOnce(MaybeExternId) -> R,
1048        external: impl FnOnce(Self) -> Option<R>,
1049        default: impl FnOnce(Self) -> R,
1050    ) -> R {
1051        queries.queried_def_ids.borrow_mut().insert(self);
1052        match genv.resolve_id(self) {
1053            ResolvedDefId::Local(local_id) => {
1054                // Case 1: `def_id` is a `LocalDefId` so forward it to the *local provider*
1055                local(MaybeExternId::Local(local_id))
1056            }
1057            ResolvedDefId::ExternSpec(local_id, def_id) => {
1058                // Case 2: `def_id` is a `LocalDefId` wrapping an extern spec, so we also
1059                // forward it to the local provider
1060                local(MaybeExternId::Extern(local_id, def_id))
1061            }
1062            ResolvedDefId::Extern(def_id) if let Some(v) = external(def_id) => {
1063                // Case 3: `def_id` is an external `def_id` for which we have an annotation in the
1064                // *external provider*
1065                v
1066            }
1067            ResolvedDefId::Extern(def_id) => {
1068                // Case 4: If none of the above, we generate a default annotation
1069                default(def_id)
1070            }
1071        }
1072    }
1073
1074    fn def_id(self) -> DefId {
1075        self
1076    }
1077}
1078
1079impl DispatchKey for FluxDefId {
1080    type LocalId = FluxId<MaybeExternId>;
1081
1082    fn dispatch_query<R>(
1083        self,
1084        genv: GlobalEnv,
1085        queries: &Queries,
1086        local: impl FnOnce(FluxId<MaybeExternId>) -> R,
1087        external: impl FnOnce(FluxId<DefId>) -> Option<R>,
1088        default: impl FnOnce(FluxId<DefId>) -> R,
1089    ) -> R {
1090        #[allow(
1091            clippy::disallowed_methods,
1092            reason = "we are mapping the parent id to a different representation which still guarantees the existence of the item"
1093        )]
1094        self.parent().dispatch_query(
1095            genv,
1096            queries,
1097            |container_id| local(FluxId::new(container_id, self.name())),
1098            |container_id| external(FluxId::new(container_id, self.name())),
1099            |container_id| default(FluxId::new(container_id, self.name())),
1100        )
1101    }
1102
1103    fn def_id(self) -> DefId {
1104        self.parent()
1105    }
1106}
1107
1108fn run_with_cache<K, V>(cache: &Cache<K, V>, key: K, f: impl FnOnce() -> V) -> V
1109where
1110    K: std::hash::Hash + Eq,
1111    V: Clone,
1112{
1113    if let Some(v) = cache.borrow().get(&key) {
1114        return v.clone();
1115    }
1116    let v = f();
1117    cache.borrow_mut().insert(key, v.clone());
1118    v
1119}
1120
1121impl<'a> Diagnostic<'a> for QueryErr {
1122    #[track_caller]
1123    fn into_diag(
1124        self,
1125        dcx: rustc_errors::DiagCtxtHandle<'a>,
1126        _level: rustc_errors::Level,
1127    ) -> rustc_errors::Diag<'a, ErrorGuaranteed> {
1128        use crate::fluent_generated as fluent;
1129
1130        rustc_middle::ty::tls::with_opt(
1131            #[track_caller]
1132            |tcx| {
1133                let tcx = tcx.expect("no TyCtxt stored in tls");
1134                match self {
1135                    QueryErr::Unsupported { def_id, err } => {
1136                        let span = err.span.unwrap_or_else(|| tcx.def_span(def_id));
1137                        let mut diag = dcx.struct_span_err(span, fluent::middle_query_unsupported);
1138                        diag.code(E0999);
1139                        diag.note(err.descr);
1140                        diag
1141                    }
1142                    QueryErr::Ignored { def_id } => {
1143                        let def_span = tcx.def_span(def_id);
1144                        let mut diag =
1145                            dcx.struct_span_err(def_span, fluent::middle_query_ignored_item);
1146                        diag.code(E0999);
1147                        diag
1148                    }
1149                    QueryErr::NotIncluded { def_id } => {
1150                        let def_span = tcx.def_span(def_id);
1151                        let mut diag =
1152                            dcx.struct_span_err(def_span, fluent::middle_query_not_included_item);
1153                        diag.code(E0999);
1154                        diag
1155                    }
1156                    QueryErr::InvalidGenericArg { def_id } => {
1157                        let def_span = tcx.def_span(def_id);
1158                        let mut diag =
1159                            dcx.struct_span_err(def_span, fluent::middle_query_invalid_generic_arg);
1160                        diag.code(E0999);
1161                        diag
1162                    }
1163                    QueryErr::MissingAssocReft { impl_id, name, .. } => {
1164                        let def_span = tcx.def_span(impl_id);
1165                        let mut diag =
1166                            dcx.struct_span_err(def_span, fluent::middle_query_missing_assoc_reft);
1167                        diag.arg("name", name);
1168                        diag.code(E0999);
1169                        diag
1170                    }
1171                    QueryErr::Bug { def_id, location, msg } => {
1172                        let mut diag = dcx.struct_err(fluent::middle_query_bug);
1173                        if let Some(def_id) = def_id {
1174                            diag.span(tcx.def_span(def_id));
1175                        }
1176                        diag.arg("location", location);
1177                        diag.note(msg);
1178                        diag
1179                    }
1180                    QueryErr::Emitted(_) => {
1181                        let mut diag = dcx.struct_err("QueryErr::Emitted should be emitted");
1182                        diag.downgrade_to_delayed_bug();
1183                        diag
1184                    }
1185                    QueryErr::OpaqueStruct { struct_id } => {
1186                        let struct_span = tcx.def_span(struct_id);
1187                        let mut diag =
1188                            dcx.struct_span_err(struct_span, fluent::middle_query_opaque_struct);
1189                        diag.arg("struct", tcx.def_path_str(struct_id));
1190                        diag
1191                    }
1192                }
1193            },
1194        )
1195    }
1196}
1197
1198impl<'a> Diagnostic<'a> for QueryErrAt {
1199    #[track_caller]
1200    fn into_diag(
1201        self,
1202        dcx: rustc_errors::DiagCtxtHandle<'a>,
1203        level: rustc_errors::Level,
1204    ) -> rustc_errors::Diag<'a, ErrorGuaranteed> {
1205        use crate::fluent_generated as fluent;
1206
1207        rustc_middle::ty::tls::with_opt(
1208            #[track_caller]
1209            |tcx| {
1210                let tcx = tcx.expect("no TyCtxt stored in tls");
1211                let cx_span = self.cx.span();
1212                let mut diag = match self.err {
1213                    QueryErr::Unsupported { def_id, err, .. } => {
1214                        let mut diag =
1215                            dcx.struct_span_err(cx_span, fluent::middle_query_unsupported_at);
1216                        diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
1217                        if let Some(def_ident_span) = tcx.def_ident_span(def_id) {
1218                            diag.span_note(def_ident_span, fluent::_subdiag::note);
1219                        }
1220                        diag.note(err.descr);
1221                        diag
1222                    }
1223                    QueryErr::Ignored { def_id } => {
1224                        let mut diag =
1225                            dcx.struct_span_err(cx_span, fluent::middle_query_ignored_at);
1226                        diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
1227                        diag.arg("name", def_id_to_string(def_id));
1228                        diag.span_label(cx_span, fluent::_subdiag::label);
1229                        diag
1230                    }
1231                    QueryErr::NotIncluded { def_id } => {
1232                        let mut diag =
1233                            dcx.struct_span_err(cx_span, fluent::middle_query_not_included_at);
1234                        diag.arg("kind", tcx.def_kind(def_id).descr(def_id));
1235                        diag.arg("name", def_id_to_string(def_id));
1236                        let span = tcx
1237                            .def_ident_span(def_id)
1238                            .unwrap_or_else(|| tcx.def_span(def_id));
1239                        diag.span_help(span, fluent::_subdiag::help);
1240                        diag
1241                    }
1242                    QueryErr::MissingAssocReft { name, .. } => {
1243                        let mut diag = dcx
1244                            .struct_span_err(cx_span, fluent::middle_query_missing_assoc_reft_at);
1245                        diag.arg("name", name);
1246                        diag.code(E0999);
1247                        diag
1248                    }
1249                    QueryErr::OpaqueStruct { struct_id } => {
1250                        let mut diag =
1251                            dcx.struct_span_err(cx_span, fluent::middle_query_opaque_struct);
1252                        diag.arg("struct", tcx.def_path_str(struct_id));
1253                        diag.span_label(cx_span, fluent::_subdiag::label);
1254                        if let ErrCtxt::FnCheck(_, fn_def_id) = self.cx {
1255                            let fn_span = tcx.def_span(fn_def_id);
1256                            diag.arg("def_kind", tcx.def_descr(fn_def_id.to_def_id()));
1257                            diag.span_label(fn_span, fluent::middle_query_opaque_struct_help);
1258                            diag.note(fluent::middle_query_opaque_struct_note);
1259                        }
1260                        diag
1261                    }
1262                    QueryErr::InvalidGenericArg { .. }
1263                    | QueryErr::Emitted(_)
1264                    | QueryErr::Bug { .. } => {
1265                        let mut diag = self.err.into_diag(dcx, level);
1266                        diag.span(cx_span);
1267                        diag
1268                    }
1269                };
1270                diag.code(E0999);
1271                diag
1272            },
1273        )
1274    }
1275}
1276
1277impl From<ErrorGuaranteed> for QueryErr {
1278    fn from(err: ErrorGuaranteed) -> Self {
1279        Self::Emitted(err)
1280    }
1281}
1282
1283pub fn try_query<T>(f: impl FnOnce() -> QueryResult<T>) -> QueryResult<T> {
1284    f()
1285}