Skip to main content

flux_middle/
queries.rs

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