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