flux_middle/
global_env.rs

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