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 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 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 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 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 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 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 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 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 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 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 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 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 pub fn should_fail(self, def_id: LocalDefId) -> bool {
546 self.fhir_attr_map(def_id).should_fail()
547 }
548
549 pub fn proven_externally(self, def_id: LocalDefId) -> Option<Span> {
551 self.fhir_attr_map(def_id).proven_externally()
552 }
553
554 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 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}