flux_middle/
global_env.rs

1use std::{alloc, path::PathBuf, ptr, rc::Rc, slice};
2
3use flux_arc_interner::List;
4use flux_common::{bug, result::ErrorEmitter};
5use flux_config as config;
6use flux_errors::FluxSession;
7use flux_rustc_bridge::{self, lowering::Lower, mir, ty};
8use rustc_data_structures::unord::UnordSet;
9use rustc_hir::{
10    def::DefKind,
11    def_id::{CrateNum, DefId, LocalDefId},
12};
13use rustc_middle::{
14    query::IntoQueryParam,
15    ty::{TyCtxt, Variance},
16};
17use rustc_span::Span;
18pub use rustc_span::{Symbol, symbol::Ident};
19use tempfile::TempDir;
20
21use crate::{
22    cstore::CrateStoreDyn,
23    def_id::{FluxDefId, FluxLocalDefId, MaybeExternId, ResolvedDefId},
24    fhir::{self, VariantIdx},
25    queries::{Providers, Queries, QueryErr, QueryResult},
26    query_bug,
27    rty::{
28        self, QualifierKind,
29        refining::{Refine as _, Refiner},
30    },
31};
32
33#[derive(Clone, Copy)]
34pub struct GlobalEnv<'genv, 'tcx> {
35    inner: &'genv GlobalEnvInner<'genv, 'tcx>,
36}
37
38struct GlobalEnvInner<'genv, 'tcx> {
39    tcx: TyCtxt<'tcx>,
40    sess: &'genv FluxSession,
41    arena: &'genv fhir::Arena,
42    cstore: Box<CrateStoreDyn>,
43    queries: Queries<'genv, 'tcx>,
44    tempdir: TempDir,
45}
46
47impl<'tcx> GlobalEnv<'_, 'tcx> {
48    pub fn enter<'a, R>(
49        tcx: TyCtxt<'tcx>,
50        sess: &'a FluxSession,
51        cstore: Box<CrateStoreDyn>,
52        arena: &'a fhir::Arena,
53        providers: Providers,
54        f: impl for<'genv> FnOnce(GlobalEnv<'genv, 'tcx>) -> R,
55    ) -> R {
56        // The tempdir must be in the same partition as the target directory so we can `fs::rename`
57        // files in it.
58        let tempdir = TempDir::new_in(lean_parent_dir(tcx)).unwrap();
59        let queries = Queries::new(providers);
60        let inner = GlobalEnvInner { tcx, sess, cstore, arena, queries, tempdir };
61        f(GlobalEnv { inner: &inner })
62    }
63}
64
65impl<'genv, 'tcx> GlobalEnv<'genv, 'tcx> {
66    pub fn tcx(self) -> TyCtxt<'tcx> {
67        self.inner.tcx
68    }
69
70    pub fn sess(self) -> &'genv FluxSession {
71        self.inner.sess
72    }
73
74    pub fn collect_specs(self) -> &'genv crate::Specs {
75        self.inner.queries.collect_specs(self)
76    }
77
78    pub fn resolve_crate(self) -> &'genv crate::ResolverOutput {
79        self.inner.queries.resolve_crate(self)
80    }
81
82    /// Parent directory of the Lean project.
83    pub fn lean_parent_dir(self) -> PathBuf {
84        lean_parent_dir(self.tcx())
85    }
86
87    pub fn temp_dir(self) -> &'genv TempDir {
88        &self.inner.tempdir
89    }
90
91    pub fn desugar(self, def_id: LocalDefId) -> QueryResult<fhir::Node<'genv>> {
92        self.inner.queries.desugar(self, def_id)
93    }
94
95    pub fn fhir_attr_map(self, def_id: LocalDefId) -> fhir::AttrMap<'genv> {
96        self.inner.queries.fhir_attr_map(self, def_id)
97    }
98
99    pub fn fhir_crate(self) -> &'genv fhir::FluxItems<'genv> {
100        self.inner.queries.fhir_crate(self)
101    }
102
103    pub fn alloc<T>(&self, val: T) -> &'genv T {
104        self.inner.arena.alloc(val)
105    }
106
107    pub fn alloc_slice<T: Copy>(self, slice: &[T]) -> &'genv [T] {
108        self.inner.arena.alloc_slice_copy(slice)
109    }
110
111    pub fn alloc_slice_fill_iter<T, I>(self, it: I) -> &'genv [T]
112    where
113        I: IntoIterator<Item = T>,
114        I::IntoIter: ExactSizeIterator,
115    {
116        self.inner.arena.alloc_slice_fill_iter(it)
117    }
118
119    pub fn def_kind(&self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
120        self.tcx().def_kind(def_id.into_query_param())
121    }
122
123    /// Allocates space to store `cap` elements of type `T`.
124    ///
125    /// The elements are initialized using the supplied iterator. At most `cap` elements will be
126    /// retrieved from the iterator. If the iterator yields fewer than `cap` elements, the returned
127    /// slice will be of length less than the allocated capacity.
128    ///
129    /// ## Panics
130    ///
131    /// Panics if reserving space for the slice fails.
132    pub fn alloc_slice_with_capacity<T, I>(self, cap: usize, it: I) -> &'genv [T]
133    where
134        I: IntoIterator<Item = T>,
135    {
136        let layout = alloc::Layout::array::<T>(cap).unwrap_or_else(|_| bug!("out of memory"));
137        let dst = self.inner.arena.alloc_layout(layout).cast::<T>();
138        unsafe {
139            let mut len = 0;
140            for (i, v) in it.into_iter().take(cap).enumerate() {
141                len += 1;
142                ptr::write(dst.as_ptr().add(i), v);
143            }
144
145            slice::from_raw_parts(dst.as_ptr(), len)
146        }
147    }
148
149    pub fn normalized_info(self, did: FluxDefId) -> rty::NormalizeInfo {
150        self.normalized_defns(did.krate()).func_info(did).clone()
151    }
152
153    pub fn normalized_defns(self, krate: CrateNum) -> Rc<rty::NormalizedDefns> {
154        self.inner.queries.normalized_defns(self, krate)
155    }
156
157    pub fn prim_rel_for(self, op: &rty::BinOp) -> QueryResult<Option<&'genv rty::PrimRel>> {
158        Ok(self.inner.queries.prim_rel(self)?.get(op))
159    }
160
161    pub fn qualifiers(self) -> QueryResult<&'genv [rty::Qualifier]> {
162        self.inner.queries.qualifiers(self)
163    }
164
165    /// Return all the qualifiers that apply to an item, including both global and local qualifiers.
166    pub fn qualifiers_for(
167        self,
168        did: LocalDefId,
169    ) -> QueryResult<impl Iterator<Item = &'genv rty::Qualifier>> {
170        let quals = self.fhir_attr_map(did).qualifiers;
171        let names: UnordSet<_> = quals.iter().copied().collect();
172        Ok(self.qualifiers()?.iter().filter(move |qual| {
173            match qual.kind {
174                QualifierKind::Global => true,
175                QualifierKind::Hint => qual.def_id.parent() == did,
176                QualifierKind::Local => names.contains(&qual.def_id),
177            }
178        }))
179    }
180
181    /// Return the list of flux function definitions that should be revelaed for item
182    pub fn reveals_for(self, did: LocalDefId) -> &'genv [FluxDefId] {
183        self.fhir_attr_map(did).reveals
184    }
185
186    pub fn func_sort(self, def_id: impl IntoQueryParam<FluxDefId>) -> rty::PolyFuncSort {
187        self.inner
188            .queries
189            .func_sort(self, def_id.into_query_param())
190    }
191
192    pub fn func_span(self, def_id: impl IntoQueryParam<FluxDefId>) -> Span {
193        self.inner
194            .queries
195            .func_span(self, def_id.into_query_param())
196    }
197
198    pub fn should_inline_fun(self, def_id: FluxDefId) -> bool {
199        let is_poly = self.func_sort(def_id).params().len() > 0;
200        is_poly || !flux_config::smt_define_fun()
201    }
202
203    pub fn variances_of(self, did: DefId) -> &'tcx [Variance] {
204        self.tcx().variances_of(did)
205    }
206
207    pub fn mir(self, def_id: LocalDefId) -> QueryResult<Rc<mir::BodyRoot<'tcx>>> {
208        self.inner.queries.mir(self, def_id)
209    }
210
211    pub fn lower_generics_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::Generics<'tcx> {
212        self.inner
213            .queries
214            .lower_generics_of(self, def_id.into_query_param())
215    }
216
217    pub fn lower_predicates_of(
218        self,
219        def_id: impl IntoQueryParam<DefId>,
220    ) -> QueryResult<ty::GenericPredicates> {
221        self.inner
222            .queries
223            .lower_predicates_of(self, def_id.into_query_param())
224    }
225
226    pub fn lower_type_of(
227        self,
228        def_id: impl IntoQueryParam<DefId>,
229    ) -> QueryResult<ty::EarlyBinder<ty::Ty>> {
230        self.inner
231            .queries
232            .lower_type_of(self, def_id.into_query_param())
233    }
234
235    pub fn lower_fn_sig(
236        self,
237        def_id: impl Into<DefId>,
238    ) -> QueryResult<ty::EarlyBinder<ty::PolyFnSig>> {
239        self.inner.queries.lower_fn_sig(self, def_id.into())
240    }
241
242    pub fn adt_def(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::AdtDef> {
243        self.inner.queries.adt_def(self, def_id.into_query_param())
244    }
245
246    pub fn constant_info(
247        self,
248        def_id: impl IntoQueryParam<DefId>,
249    ) -> QueryResult<rty::ConstantInfo> {
250        self.inner
251            .queries
252            .constant_info(self, def_id.into_query_param())
253    }
254
255    pub fn adt_sort_def_of(
256        self,
257        def_id: impl IntoQueryParam<DefId>,
258    ) -> QueryResult<rty::AdtSortDef> {
259        self.inner
260            .queries
261            .adt_sort_def_of(self, def_id.into_query_param())
262    }
263
264    pub fn sort_decl_param_count(self, def_id: impl IntoQueryParam<FluxDefId>) -> usize {
265        self.inner
266            .queries
267            .sort_decl_param_count(self, def_id.into_query_param())
268    }
269
270    pub fn check_wf(self, def_id: LocalDefId) -> QueryResult<Rc<rty::WfckResults>> {
271        self.inner.queries.check_wf(self, def_id)
272    }
273
274    pub fn impl_trait_ref(
275        self,
276        impl_id: DefId,
277    ) -> QueryResult<Option<rty::EarlyBinder<rty::TraitRef>>> {
278        let Some(trait_ref) = self.tcx().impl_trait_ref(impl_id) else { return Ok(None) };
279        let trait_ref = trait_ref.skip_binder();
280        let trait_ref = trait_ref
281            .lower(self.tcx())
282            .map_err(|err| QueryErr::unsupported(trait_ref.def_id, err.into_err()))?
283            .refine(&Refiner::default_for_item(self, impl_id)?)?;
284        Ok(Some(rty::EarlyBinder(trait_ref)))
285    }
286
287    pub fn generics_of(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::Generics> {
288        self.inner
289            .queries
290            .generics_of(self, def_id.into_query_param())
291    }
292
293    pub fn refinement_generics_of(
294        self,
295        def_id: impl IntoQueryParam<DefId>,
296    ) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
297        self.inner
298            .queries
299            .refinement_generics_of(self, def_id.into_query_param())
300    }
301
302    pub fn predicates_of(
303        self,
304        def_id: impl IntoQueryParam<DefId>,
305    ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
306        self.inner
307            .queries
308            .predicates_of(self, def_id.into_query_param())
309    }
310
311    pub fn assoc_refinements_of(
312        self,
313        def_id: impl IntoQueryParam<DefId>,
314    ) -> QueryResult<rty::AssocRefinements> {
315        self.inner
316            .queries
317            .assoc_refinements_of(self, def_id.into_query_param())
318    }
319
320    pub fn assoc_refinement(self, assoc_id: FluxDefId) -> QueryResult<rty::AssocReft> {
321        Ok(self.assoc_refinements_of(assoc_id.parent())?.get(assoc_id))
322    }
323
324    /// Given the id of an associated refinement in a trait definition returns the body for the
325    /// corresponding associated refinement in the implementation with id `impl_id`.
326    ///
327    /// This function returns [`QueryErr::MissingAssocReft`] if the associated refinement is not
328    /// found in the implementation and there's no default body in the trait. This can happen if an
329    /// extern spec adds an associated refinement without a default body because we are currently
330    /// not checking `compare_impl_item` for those definitions.
331    pub fn assoc_refinement_body_for_impl(
332        self,
333        trait_assoc_id: FluxDefId,
334        impl_id: DefId,
335    ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
336        // Check if the implementation has the associated refinement
337        let impl_assoc_refts = self.assoc_refinements_of(impl_id)?;
338        if let Some(impl_assoc_reft) = impl_assoc_refts.find(trait_assoc_id.name()) {
339            return self.assoc_refinement_body(impl_assoc_reft.def_id());
340        }
341
342        // Otherwise, check if the trait has a default body
343        if let Some(body) = self.default_assoc_refinement_body(trait_assoc_id)? {
344            let impl_trait_ref = self
345                .impl_trait_ref(impl_id)?
346                .unwrap()
347                .instantiate_identity();
348            return Ok(rty::EarlyBinder(body.instantiate(self.tcx(), &impl_trait_ref.args, &[])));
349        }
350
351        Err(QueryErr::MissingAssocReft {
352            impl_id,
353            trait_id: trait_assoc_id.parent(),
354            name: trait_assoc_id.name(),
355        })
356    }
357
358    pub fn default_assoc_refinement_body(
359        self,
360        trait_assoc_id: FluxDefId,
361    ) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
362        self.inner
363            .queries
364            .default_assoc_refinement_body(self, trait_assoc_id)
365    }
366
367    pub fn assoc_refinement_body(
368        self,
369        impl_assoc_id: FluxDefId,
370    ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
371        self.inner
372            .queries
373            .assoc_refinement_body(self, impl_assoc_id)
374    }
375
376    pub fn sort_of_assoc_reft(
377        self,
378        assoc_id: FluxDefId,
379    ) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
380        self.inner.queries.sort_of_assoc_reft(self, assoc_id)
381    }
382
383    pub fn item_bounds(self, def_id: DefId) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>> {
384        self.inner.queries.item_bounds(self, def_id)
385    }
386
387    pub fn type_of(
388        self,
389        def_id: impl IntoQueryParam<DefId>,
390    ) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
391        self.inner.queries.type_of(self, def_id.into_query_param())
392    }
393
394    pub fn fn_sig(
395        self,
396        def_id: impl IntoQueryParam<DefId>,
397    ) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
398        self.inner.queries.fn_sig(self, def_id.into_query_param())
399    }
400
401    pub fn variants_of(
402        self,
403        def_id: impl IntoQueryParam<DefId>,
404    ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
405        self.inner
406            .queries
407            .variants_of(self, def_id.into_query_param())
408    }
409
410    pub fn variant_sig(
411        self,
412        def_id: DefId,
413        variant_idx: VariantIdx,
414    ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariant>>> {
415        Ok(self
416            .variants_of(def_id)?
417            .map(|variants| variants.map(|variants| variants[variant_idx.as_usize()].clone())))
418    }
419
420    pub fn lower_late_bound_vars(
421        self,
422        def_id: LocalDefId,
423    ) -> QueryResult<List<ty::BoundVariableKind>> {
424        self.inner.queries.lower_late_bound_vars(self, def_id)
425    }
426
427    /// Whether the function is marked with `#[flux::no_panic]`
428    pub fn no_panic(self, def_id: impl IntoQueryParam<DefId>) -> bool {
429        self.inner.queries.no_panic(self, def_id.into_query_param())
430    }
431
432    pub fn is_box(&self, res: fhir::Res) -> bool {
433        res.is_box(self.tcx())
434    }
435
436    pub fn def_id_to_param_index(&self, def_id: DefId) -> u32 {
437        let parent = self.tcx().parent(def_id);
438        let generics = self.tcx().generics_of(parent);
439        generics.param_def_id_to_index(self.tcx(), def_id).unwrap()
440    }
441
442    pub(crate) fn cstore(self) -> &'genv CrateStoreDyn {
443        &*self.inner.cstore
444    }
445
446    pub fn has_trusted_impl(&self, def_id: DefId) -> bool {
447        if let Some(did) = self
448            .resolve_id(def_id)
449            .as_maybe_extern()
450            .map(|id| id.local_id())
451        {
452            self.trusted_impl(did)
453        } else {
454            false
455        }
456    }
457
458    /// The `Output` associated type is defined in `FnOnce`, and `Fn`/`FnMut`
459    /// inherit it, so this should suffice to check if the `def_id`
460    /// corresponds to `LangItem::FnOnceOutput`.
461    pub fn is_fn_output(&self, def_id: DefId) -> bool {
462        let def_span = self.tcx().def_span(def_id);
463        self.tcx()
464            .require_lang_item(rustc_hir::LangItem::FnOnceOutput, def_span)
465            == def_id
466    }
467
468    /// Iterator over all local def ids that are not a extern spec
469    pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + use<'tcx, 'genv> {
470        self.tcx().iter_local_def_id().filter(move |&local_def_id| {
471            self.maybe_extern_id(local_def_id).is_local() && !self.is_dummy(local_def_id)
472        })
473    }
474
475    pub fn iter_extern_def_id(self) -> impl Iterator<Item = DefId> + use<'tcx, 'genv> {
476        self.tcx()
477            .iter_local_def_id()
478            .filter_map(move |local_def_id| self.maybe_extern_id(local_def_id).as_extern())
479    }
480
481    pub fn maybe_extern_id(self, local_id: LocalDefId) -> MaybeExternId {
482        self.collect_specs()
483            .local_id_to_extern_id
484            .get(&local_id)
485            .map_or_else(
486                || MaybeExternId::Local(local_id),
487                |def_id| MaybeExternId::Extern(local_id, *def_id),
488            )
489    }
490
491    #[expect(clippy::disallowed_methods)]
492    pub fn resolve_id(self, def_id: DefId) -> ResolvedDefId {
493        let maybe_extern_spec = self
494            .collect_specs()
495            .extern_id_to_local_id
496            .get(&def_id)
497            .copied();
498        if let Some(local_id) = maybe_extern_spec {
499            ResolvedDefId::ExternSpec(local_id, def_id)
500        } else if let Some(local_id) = def_id.as_local() {
501            debug_assert!(
502                self.maybe_extern_id(local_id).is_local(),
503                "def id points to dummy local item `{def_id:?}`"
504            );
505            ResolvedDefId::Local(local_id)
506        } else {
507            ResolvedDefId::Extern(def_id)
508        }
509    }
510
511    pub fn infer_opts(self, def_id: LocalDefId) -> config::InferOpts {
512        let mut opts = config::PartialInferOpts::default();
513        self.traverse_parents(def_id, |did| {
514            if let Some(o) = self.fhir_attr_map(did).infer_opts() {
515                opts.merge(&o);
516            }
517            None::<!>
518        });
519        opts.into()
520    }
521
522    /// Transitively follow the parent-chain of `def_id` to find the first containing item with an
523    /// explicit `#[flux::trusted(..)]` annotation and return whether that item is trusted or not.
524    /// If no explicit annotation is found, return `false`.
525    pub fn trusted(self, def_id: LocalDefId) -> bool {
526        self.traverse_parents(def_id, |did| self.fhir_attr_map(did).trusted())
527            .map(|trusted| trusted.to_bool())
528            .unwrap_or_else(config::trusted_default)
529    }
530
531    pub fn trusted_impl(self, def_id: LocalDefId) -> bool {
532        self.traverse_parents(def_id, |did| self.fhir_attr_map(did).trusted_impl())
533            .map(|trusted| trusted.to_bool())
534            .unwrap_or(false)
535    }
536
537    /// Whether the item is a dummy item created by the extern spec macro.
538    ///
539    /// See [`crate::Specs::dummy_extern`]
540    pub fn is_dummy(self, def_id: LocalDefId) -> bool {
541        self.traverse_parents(def_id, |did| {
542            self.collect_specs()
543                .dummy_extern
544                .contains(&did)
545                .then_some(())
546        })
547        .is_some()
548    }
549
550    /// Transitively follow the parent-chain of `def_id` to find the first containing item with an
551    /// explicit `#[flux::ignore(..)]` annotation and return whether that item is ignored or not.
552    /// If no explicit annotation is found, return `false`.
553    pub fn ignored(self, def_id: LocalDefId) -> bool {
554        self.traverse_parents(def_id, |did| self.fhir_attr_map(did).ignored())
555            .map(|ignored| ignored.to_bool())
556            .unwrap_or_else(config::ignore_default)
557    }
558
559    /// Whether the function is marked with `#[flux::should_fail]`
560    pub fn should_fail(self, def_id: LocalDefId) -> bool {
561        self.fhir_attr_map(def_id).should_fail()
562    }
563
564    /// Whether the function is marked with `#[proven_externally]`
565    pub fn proven_externally(self, def_id: LocalDefId) -> Option<Span> {
566        self.fhir_attr_map(def_id).proven_externally()
567    }
568
569    /// Traverse the parent chain of `def_id` until the first node for which `f` returns [`Some`].
570    fn traverse_parents<T>(
571        self,
572        mut def_id: LocalDefId,
573        mut f: impl FnMut(LocalDefId) -> Option<T>,
574    ) -> Option<T> {
575        loop {
576            if let Some(v) = f(def_id) {
577                break Some(v);
578            }
579
580            if let Some(parent) = self.tcx().opt_local_parent(def_id) {
581                def_id = parent;
582            } else {
583                break None;
584            }
585        }
586    }
587}
588
589impl<'genv, 'tcx> GlobalEnv<'genv, 'tcx> {
590    pub fn fhir_iter_flux_items(
591        self,
592    ) -> impl Iterator<Item = (FluxLocalDefId, fhir::FluxItem<'genv>)> {
593        self.fhir_crate()
594            .items
595            .iter()
596            .map(|(id, item)| (*id, *item))
597    }
598
599    pub fn fhir_sort_decl(&self, def_id: FluxLocalDefId) -> Option<&fhir::SortDecl> {
600        self.fhir_crate().items.get(&def_id).and_then(|item| {
601            if let fhir::FluxItem::SortDecl(sort_decl) = item { Some(*sort_decl) } else { None }
602        })
603    }
604
605    pub fn fhir_spec_func_body(
606        &self,
607        def_id: FluxLocalDefId,
608    ) -> Option<&'genv fhir::SpecFunc<'genv>> {
609        self.fhir_crate()
610            .items
611            .get(&def_id)
612            .and_then(|item| if let fhir::FluxItem::Func(defn) = item { Some(*defn) } else { None })
613    }
614
615    pub fn fhir_qualifiers(self) -> impl Iterator<Item = &'genv fhir::Qualifier<'genv>> {
616        self.fhir_crate().items.values().filter_map(|item| {
617            if let fhir::FluxItem::Qualifier(qual) = item { Some(*qual) } else { None }
618        })
619    }
620
621    pub fn fhir_primop_props(self) -> impl Iterator<Item = &'genv fhir::PrimOpProp<'genv>> {
622        self.fhir_crate().items.values().filter_map(|item| {
623            if let fhir::FluxItem::PrimOpProp(prop) = item { Some(*prop) } else { None }
624        })
625    }
626
627    pub fn fhir_get_generics(
628        self,
629        def_id: LocalDefId,
630    ) -> QueryResult<Option<&'genv fhir::Generics<'genv>>> {
631        // We don't have nodes for closures and coroutines
632        if matches!(self.def_kind(def_id), DefKind::Closure) {
633            Ok(None)
634        } else {
635            Ok(Some(self.fhir_expect_owner_node(def_id)?.generics()))
636        }
637    }
638
639    pub fn fhir_expect_refinement_kind(
640        self,
641        def_id: LocalDefId,
642    ) -> QueryResult<&'genv fhir::RefinementKind<'genv>> {
643        let kind = match &self.fhir_expect_item(def_id)?.kind {
644            fhir::ItemKind::Enum(enum_def) => &enum_def.refinement,
645            fhir::ItemKind::Struct(struct_def) => &struct_def.refinement,
646            _ => bug!("expected struct, enum or type alias"),
647        };
648        Ok(kind)
649    }
650
651    pub fn fhir_expect_item(self, def_id: LocalDefId) -> QueryResult<&'genv fhir::Item<'genv>> {
652        if let fhir::Node::Item(item) = self.fhir_node(def_id)? {
653            Ok(item)
654        } else {
655            Err(query_bug!(def_id, "expected item: `{def_id:?}`"))
656        }
657    }
658
659    pub fn fhir_expect_owner_node(self, def_id: LocalDefId) -> QueryResult<fhir::OwnerNode<'genv>> {
660        let Some(owner) = self.fhir_node(def_id)?.as_owner() else {
661            return Err(query_bug!(def_id, "cannot find owner node"));
662        };
663        Ok(owner)
664    }
665
666    pub fn fhir_node(self, def_id: LocalDefId) -> QueryResult<fhir::Node<'genv>> {
667        self.desugar(def_id)
668    }
669}
670
671#[macro_export]
672macro_rules! try_alloc_slice {
673    ($genv:expr, $slice:expr, $map:expr $(,)?) => {{
674        let slice = $slice;
675        $crate::try_alloc_slice!($genv, cap: slice.len(), slice.into_iter().map($map))
676    }};
677    ($genv:expr, cap: $cap:expr, $it:expr $(,)?) => {{
678        let mut err = None;
679        let slice = $genv.alloc_slice_with_capacity($cap, $it.into_iter().collect_errors(&mut err));
680        err.map_or(Ok(slice), Err)
681    }};
682}
683
684impl ErrorEmitter for GlobalEnv<'_, '_> {
685    fn emit<'a>(&'a self, err: impl rustc_errors::Diagnostic<'a>) -> rustc_span::ErrorGuaranteed {
686        self.sess().emit(err)
687    }
688}
689
690fn lean_parent_dir(tcx: TyCtxt) -> PathBuf {
691    tcx.sess
692        .opts
693        .working_dir
694        .local_path_if_available()
695        .to_path_buf()
696        .join(config::lean_dir())
697}