flux_middle/
queries.rs

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