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,
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_crate(self) -> &'genv fhir::FluxItems<'genv> {
81 self.inner.queries.fhir_crate(self)
82 }
83
84 pub fn alloc<T>(&self, val: T) -> &'genv T {
85 self.inner.arena.alloc(val)
86 }
87
88 pub fn alloc_slice<T: Copy>(self, slice: &[T]) -> &'genv [T] {
89 self.inner.arena.alloc_slice_copy(slice)
90 }
91
92 pub fn alloc_slice_fill_iter<T, I>(self, it: I) -> &'genv [T]
93 where
94 I: IntoIterator<Item = T>,
95 I::IntoIter: ExactSizeIterator,
96 {
97 self.inner.arena.alloc_slice_fill_iter(it)
98 }
99
100 pub fn def_kind(&self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
101 self.tcx().def_kind(def_id.into_query_param())
102 }
103
104 pub fn alloc_slice_with_capacity<T, I>(self, cap: usize, it: I) -> &'genv [T]
114 where
115 I: IntoIterator<Item = T>,
116 {
117 let layout = alloc::Layout::array::<T>(cap).unwrap_or_else(|_| bug!("out of memory"));
118 let dst = self.inner.arena.alloc_layout(layout).cast::<T>();
119 unsafe {
120 let mut len = 0;
121 for (i, v) in it.into_iter().take(cap).enumerate() {
122 len += 1;
123 ptr::write(dst.as_ptr().add(i), v);
124 }
125
126 slice::from_raw_parts(dst.as_ptr(), len)
127 }
128 }
129
130 pub fn normalized_info(self, did: FluxDefId) -> rty::NormalizeInfo {
131 self.normalized_defns(did.krate()).func_info(did).clone()
132 }
133
134 pub fn normalized_defns(self, krate: CrateNum) -> Rc<rty::NormalizedDefns> {
135 self.inner.queries.normalized_defns(self, krate)
136 }
137
138 pub fn prim_rel_for(self, op: &rty::BinOp) -> QueryResult<Option<&'genv rty::PrimRel>> {
139 Ok(self.inner.queries.prim_rel(self)?.get(op))
140 }
141
142 pub fn qualifiers(self) -> QueryResult<&'genv [rty::Qualifier]> {
143 self.inner.queries.qualifiers(self)
144 }
145
146 pub fn qualifiers_for(
148 self,
149 did: LocalDefId,
150 ) -> QueryResult<impl Iterator<Item = &'genv rty::Qualifier>> {
151 let quals = if let Some(fn_sig) = self.fhir_expect_owner_node(did)?.fn_sig() {
152 fn_sig.qualifiers
153 } else {
154 &[]
155 };
156 let names: UnordSet<_> = quals.iter().copied().collect();
157 Ok(self
158 .qualifiers()?
159 .iter()
160 .filter(move |qual| qual.global || names.contains(&qual.def_id)))
161 }
162
163 pub fn reveals_for(self, did: LocalDefId) -> QueryResult<impl Iterator<Item = FluxDefId>> {
165 let reveals = if let Some(fn_sig) = self.fhir_expect_owner_node(did)?.fn_sig() {
166 fn_sig.reveals
167 } else {
168 &[]
169 };
170 Ok(reveals.iter().copied())
171 }
172
173 pub fn func_sort(self, def_id: impl IntoQueryParam<FluxDefId>) -> rty::PolyFuncSort {
174 self.inner
175 .queries
176 .func_sort(self, def_id.into_query_param())
177 }
178
179 pub fn func_span(self, def_id: impl IntoQueryParam<FluxDefId>) -> Span {
180 self.inner
181 .queries
182 .func_span(self, def_id.into_query_param())
183 }
184
185 pub fn should_inline_fun(self, def_id: FluxDefId) -> bool {
186 let is_poly = self.func_sort(def_id).params().len() > 0;
187 is_poly || !flux_config::smt_define_fun()
188 }
189
190 pub fn variances_of(self, did: DefId) -> &'tcx [Variance] {
191 self.tcx().variances_of(did)
192 }
193
194 pub fn mir(self, def_id: LocalDefId) -> QueryResult<Rc<mir::Body<'tcx>>> {
195 self.inner.queries.mir(self, def_id)
196 }
197
198 pub fn lower_generics_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::Generics<'tcx> {
199 self.inner
200 .queries
201 .lower_generics_of(self, def_id.into_query_param())
202 }
203
204 pub fn lower_predicates_of(
205 self,
206 def_id: impl IntoQueryParam<DefId>,
207 ) -> QueryResult<ty::GenericPredicates> {
208 self.inner
209 .queries
210 .lower_predicates_of(self, def_id.into_query_param())
211 }
212
213 pub fn lower_type_of(
214 self,
215 def_id: impl IntoQueryParam<DefId>,
216 ) -> QueryResult<ty::EarlyBinder<ty::Ty>> {
217 self.inner
218 .queries
219 .lower_type_of(self, def_id.into_query_param())
220 }
221
222 pub fn lower_fn_sig(
223 self,
224 def_id: impl Into<DefId>,
225 ) -> QueryResult<ty::EarlyBinder<ty::PolyFnSig>> {
226 self.inner.queries.lower_fn_sig(self, def_id.into())
227 }
228
229 pub fn adt_def(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::AdtDef> {
230 self.inner.queries.adt_def(self, def_id.into_query_param())
231 }
232
233 pub fn constant_info(
234 self,
235 def_id: impl IntoQueryParam<DefId>,
236 ) -> QueryResult<rty::ConstantInfo> {
237 self.inner
238 .queries
239 .constant_info(self, def_id.into_query_param())
240 }
241
242 pub fn adt_sort_def_of(
243 self,
244 def_id: impl IntoQueryParam<DefId>,
245 ) -> QueryResult<rty::AdtSortDef> {
246 self.inner
247 .queries
248 .adt_sort_def_of(self, def_id.into_query_param())
249 }
250
251 pub fn check_wf(self, def_id: LocalDefId) -> QueryResult<Rc<rty::WfckResults>> {
252 self.inner.queries.check_wf(self, def_id)
253 }
254
255 pub fn impl_trait_ref(
256 self,
257 impl_id: DefId,
258 ) -> QueryResult<Option<rty::EarlyBinder<rty::TraitRef>>> {
259 let Some(trait_ref) = self.tcx().impl_trait_ref(impl_id) else { return Ok(None) };
260 let trait_ref = trait_ref.skip_binder();
261 let trait_ref = trait_ref
262 .lower(self.tcx())
263 .map_err(|err| QueryErr::unsupported(trait_ref.def_id, err.into_err()))?
264 .refine(&Refiner::default_for_item(self, impl_id)?)?;
265 Ok(Some(rty::EarlyBinder(trait_ref)))
266 }
267
268 pub fn generics_of(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::Generics> {
269 self.inner
270 .queries
271 .generics_of(self, def_id.into_query_param())
272 }
273
274 pub fn refinement_generics_of(
275 self,
276 def_id: impl IntoQueryParam<DefId>,
277 ) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
278 self.inner
279 .queries
280 .refinement_generics_of(self, def_id.into_query_param())
281 }
282
283 pub fn predicates_of(
284 self,
285 def_id: impl IntoQueryParam<DefId>,
286 ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
287 self.inner
288 .queries
289 .predicates_of(self, def_id.into_query_param())
290 }
291
292 pub fn assoc_refinements_of(
293 self,
294 def_id: impl IntoQueryParam<DefId>,
295 ) -> QueryResult<rty::AssocRefinements> {
296 self.inner
297 .queries
298 .assoc_refinements_of(self, def_id.into_query_param())
299 }
300
301 pub fn assoc_refinement(self, assoc_id: FluxDefId) -> QueryResult<rty::AssocReft> {
302 Ok(self.assoc_refinements_of(assoc_id.parent())?.get(assoc_id))
303 }
304
305 pub fn assoc_refinement_body_for_impl(
313 self,
314 trait_assoc_id: FluxDefId,
315 impl_id: DefId,
316 ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
317 let impl_assoc_refts = self.assoc_refinements_of(impl_id)?;
319 if let Some(impl_assoc_reft) = impl_assoc_refts.find(trait_assoc_id.name()) {
320 return self.assoc_refinement_body(impl_assoc_reft.def_id());
321 }
322
323 if let Some(body) = self.default_assoc_refinement_body(trait_assoc_id)? {
325 let impl_trait_ref = self
326 .impl_trait_ref(impl_id)?
327 .unwrap()
328 .instantiate_identity();
329 return Ok(rty::EarlyBinder(body.instantiate(self.tcx(), &impl_trait_ref.args, &[])));
330 }
331
332 Err(QueryErr::MissingAssocReft {
333 impl_id,
334 trait_id: trait_assoc_id.parent(),
335 name: trait_assoc_id.name(),
336 })
337 }
338
339 pub fn default_assoc_refinement_body(
340 self,
341 trait_assoc_id: FluxDefId,
342 ) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
343 self.inner
344 .queries
345 .default_assoc_refinement_body(self, trait_assoc_id)
346 }
347
348 pub fn assoc_refinement_body(
349 self,
350 impl_assoc_id: FluxDefId,
351 ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
352 self.inner
353 .queries
354 .assoc_refinement_body(self, impl_assoc_id)
355 }
356
357 pub fn sort_of_assoc_reft(
358 self,
359 assoc_id: FluxDefId,
360 ) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
361 self.inner.queries.sort_of_assoc_reft(self, assoc_id)
362 }
363
364 pub fn item_bounds(self, def_id: DefId) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>> {
365 self.inner.queries.item_bounds(self, def_id)
366 }
367
368 pub fn type_of(
369 self,
370 def_id: impl IntoQueryParam<DefId>,
371 ) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
372 self.inner.queries.type_of(self, def_id.into_query_param())
373 }
374
375 pub fn fn_sig(
376 self,
377 def_id: impl IntoQueryParam<DefId>,
378 ) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
379 self.inner.queries.fn_sig(self, def_id.into_query_param())
380 }
381
382 pub fn variants_of(
383 self,
384 def_id: impl IntoQueryParam<DefId>,
385 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
386 self.inner
387 .queries
388 .variants_of(self, def_id.into_query_param())
389 }
390
391 pub fn variant_sig(
392 self,
393 def_id: DefId,
394 variant_idx: VariantIdx,
395 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariant>>> {
396 Ok(self
397 .variants_of(def_id)?
398 .map(|variants| variants.map(|variants| variants[variant_idx.as_usize()].clone())))
399 }
400
401 pub fn lower_late_bound_vars(
402 self,
403 def_id: LocalDefId,
404 ) -> QueryResult<List<ty::BoundVariableKind>> {
405 self.inner.queries.lower_late_bound_vars(self, def_id)
406 }
407
408 pub fn is_box(&self, res: fhir::Res) -> bool {
409 res.is_box(self.tcx())
410 }
411
412 pub fn def_id_to_param_index(&self, def_id: DefId) -> u32 {
413 let parent = self.tcx().parent(def_id);
414 let generics = self.tcx().generics_of(parent);
415 generics.param_def_id_to_index(self.tcx(), def_id).unwrap()
416 }
417
418 pub(crate) fn cstore(self) -> &'genv CrateStoreDyn {
419 &*self.inner.cstore
420 }
421
422 pub fn has_trusted_impl(&self, def_id: DefId) -> bool {
423 if let Some(did) = self
424 .resolve_id(def_id)
425 .as_maybe_extern()
426 .map(|id| id.local_id())
427 {
428 self.trusted_impl(did)
429 } else {
430 false
431 }
432 }
433
434 pub fn is_fn_output(&self, def_id: DefId) -> bool {
438 let def_span = self.tcx().def_span(def_id);
439 self.tcx()
440 .require_lang_item(rustc_hir::LangItem::FnOnceOutput, def_span)
441 == def_id
442 }
443
444 pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + use<'tcx, 'genv> {
446 self.tcx().iter_local_def_id().filter(move |&local_def_id| {
447 self.maybe_extern_id(local_def_id).is_local() && !self.is_dummy(local_def_id)
448 })
449 }
450
451 pub fn iter_extern_def_id(self) -> impl Iterator<Item = DefId> + use<'tcx, 'genv> {
452 self.tcx()
453 .iter_local_def_id()
454 .filter_map(move |local_def_id| self.maybe_extern_id(local_def_id).as_extern())
455 }
456
457 pub fn maybe_extern_id(self, local_id: LocalDefId) -> MaybeExternId {
458 self.collect_specs()
459 .local_id_to_extern_id
460 .get(&local_id)
461 .map_or_else(
462 || MaybeExternId::Local(local_id),
463 |def_id| MaybeExternId::Extern(local_id, *def_id),
464 )
465 }
466
467 #[expect(clippy::disallowed_methods)]
468 pub fn resolve_id(self, def_id: DefId) -> ResolvedDefId {
469 let maybe_extern_spec = self
470 .collect_specs()
471 .extern_id_to_local_id
472 .get(&def_id)
473 .copied();
474 if let Some(local_id) = maybe_extern_spec {
475 ResolvedDefId::ExternSpec(local_id, def_id)
476 } else if let Some(local_id) = def_id.as_local() {
477 debug_assert!(
478 self.maybe_extern_id(local_id).is_local(),
479 "def id points to dummy local item `{def_id:?}`"
480 );
481 ResolvedDefId::Local(local_id)
482 } else {
483 ResolvedDefId::Extern(def_id)
484 }
485 }
486
487 pub fn infer_opts(self, def_id: LocalDefId) -> config::InferOpts {
488 let mut opts = config::PartialInferOpts::default();
489 let specs = self.collect_specs();
490 self.traverse_parents(def_id, |did| {
491 if let Some(o) = specs.infer_opts.get(&did) {
492 opts.merge(o);
493 }
494 None::<!>
495 });
496 opts.into()
497 }
498
499 pub fn trusted(self, def_id: LocalDefId) -> bool {
503 self.traverse_parents(def_id, |did| self.collect_specs().trusted.get(&did))
504 .map(|trusted| trusted.to_bool())
505 .unwrap_or_else(config::trusted_default)
506 }
507
508 pub fn trusted_impl(self, def_id: LocalDefId) -> bool {
509 self.traverse_parents(def_id, |did| self.collect_specs().trusted_impl.get(&did))
510 .map(|trusted| trusted.to_bool())
511 .unwrap_or(false)
512 }
513
514 pub fn is_dummy(self, def_id: LocalDefId) -> bool {
518 self.traverse_parents(def_id, |did| {
519 self.collect_specs()
520 .dummy_extern
521 .contains(&did)
522 .then_some(())
523 })
524 .is_some()
525 }
526
527 pub fn ignored(self, def_id: LocalDefId) -> bool {
531 self.traverse_parents(def_id, |did| self.collect_specs().ignores.get(&did))
532 .map(|ignored| ignored.to_bool())
533 .unwrap_or_else(config::ignore_default)
534 }
535
536 pub fn should_fail(self, def_id: LocalDefId) -> bool {
538 self.collect_specs().should_fail.contains(&def_id)
539 }
540
541 fn traverse_parents<T>(
543 self,
544 mut def_id: LocalDefId,
545 mut f: impl FnMut(LocalDefId) -> Option<T>,
546 ) -> Option<T> {
547 loop {
548 if let Some(v) = f(def_id) {
549 break Some(v);
550 }
551
552 if let Some(parent) = self.tcx().opt_local_parent(def_id) {
553 def_id = parent;
554 } else {
555 break None;
556 }
557 }
558 }
559}
560
561impl<'genv, 'tcx> GlobalEnv<'genv, 'tcx> {
562 pub fn fhir_iter_flux_items(
563 self,
564 ) -> impl Iterator<Item = (FluxLocalDefId, fhir::FluxItem<'genv>)> {
565 self.fhir_crate()
566 .items
567 .iter()
568 .map(|(id, item)| (*id, *item))
569 }
570
571 pub fn fhir_spec_func_body(
572 &self,
573 def_id: FluxLocalDefId,
574 ) -> Option<&'genv fhir::SpecFunc<'genv>> {
575 self.fhir_crate()
576 .items
577 .get(&def_id)
578 .and_then(|item| if let fhir::FluxItem::Func(defn) = item { Some(*defn) } else { None })
579 }
580
581 pub fn fhir_qualifiers(self) -> impl Iterator<Item = &'genv fhir::Qualifier<'genv>> {
582 self.fhir_crate().items.values().filter_map(|item| {
583 if let fhir::FluxItem::Qualifier(qual) = item { Some(*qual) } else { None }
584 })
585 }
586
587 pub fn fhir_primop_props(self) -> impl Iterator<Item = &'genv fhir::PrimOpProp<'genv>> {
588 self.fhir_crate().items.values().filter_map(|item| {
589 if let fhir::FluxItem::PrimOpProp(prop) = item { Some(*prop) } else { None }
590 })
591 }
592
593 pub fn fhir_get_generics(
594 self,
595 def_id: LocalDefId,
596 ) -> QueryResult<Option<&'genv fhir::Generics<'genv>>> {
597 if matches!(self.def_kind(def_id), DefKind::Closure) {
599 Ok(None)
600 } else {
601 Ok(Some(self.fhir_expect_owner_node(def_id)?.generics()))
602 }
603 }
604
605 pub fn fhir_expect_refinement_kind(
606 self,
607 def_id: LocalDefId,
608 ) -> QueryResult<&'genv fhir::RefinementKind<'genv>> {
609 let kind = match &self.fhir_expect_item(def_id)?.kind {
610 fhir::ItemKind::Enum(enum_def) => &enum_def.refinement,
611 fhir::ItemKind::Struct(struct_def) => &struct_def.refinement,
612 _ => bug!("expected struct, enum or type alias"),
613 };
614 Ok(kind)
615 }
616
617 pub fn fhir_expect_item(self, def_id: LocalDefId) -> QueryResult<&'genv fhir::Item<'genv>> {
618 if let fhir::Node::Item(item) = self.fhir_node(def_id)? {
619 Ok(item)
620 } else {
621 Err(query_bug!(def_id, "expected item: `{def_id:?}`"))
622 }
623 }
624
625 pub fn fhir_expect_owner_node(self, def_id: LocalDefId) -> QueryResult<fhir::OwnerNode<'genv>> {
626 let Some(owner) = self.fhir_node(def_id)?.as_owner() else {
627 return Err(query_bug!(def_id, "cannot find owner node"));
628 };
629 Ok(owner)
630 }
631
632 pub fn fhir_node(self, def_id: LocalDefId) -> QueryResult<fhir::Node<'genv>> {
633 self.desugar(def_id)
634 }
635}
636
637#[macro_export]
638macro_rules! try_alloc_slice {
639 ($genv:expr, $slice:expr, $map:expr $(,)?) => {{
640 let slice = $slice;
641 $crate::try_alloc_slice!($genv, cap: slice.len(), slice.into_iter().map($map))
642 }};
643 ($genv:expr, cap: $cap:expr, $it:expr $(,)?) => {{
644 let mut err = None;
645 let slice = $genv.alloc_slice_with_capacity($cap, $it.into_iter().collect_errors(&mut err));
646 err.map_or(Ok(slice), Err)
647 }};
648}
649
650impl ErrorEmitter for GlobalEnv<'_, '_> {
651 fn emit<'a>(&'a self, err: impl rustc_errors::Diagnostic<'a>) -> rustc_span::ErrorGuaranteed {
652 self.sess().emit(err)
653 }
654}