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