1use std::{
2 alloc,
3 path::{Path, PathBuf},
4 ptr,
5 rc::Rc,
6 slice,
7};
8
9use flux_arc_interner::List;
10use flux_common::{bug, result::ErrorEmitter};
11use flux_config::{self as config, IncludePattern};
12use flux_errors::FluxSession;
13use flux_rustc_bridge::{self, lowering::Lower, mir, ty};
14use flux_syntax::symbols::sym;
15use rustc_data_structures::unord::UnordSet;
16use rustc_hir::{
17 LangItem,
18 def::DefKind,
19 def_id::{CrateNum, DefId, LocalDefId},
20};
21use rustc_middle::{
22 query::IntoQueryParam,
23 ty::{TyCtxt, Variance},
24};
25use rustc_span::{FileName, Span};
26pub use rustc_span::{Symbol, symbol::Ident};
27use tempfile::TempDir;
28
29use crate::{
30 cstore::CrateStoreDyn,
31 def_id::{FluxDefId, FluxLocalDefId, MaybeExternId, ResolvedDefId},
32 fhir::{self, VariantIdx},
33 queries::{DispatchKey, Providers, Queries, QueryErr, QueryResult},
34 query_bug,
35 rty::{
36 self, QualifierKind,
37 refining::{Refine as _, Refiner},
38 },
39};
40
41#[derive(Clone, Copy)]
42pub struct GlobalEnv<'genv, 'tcx> {
43 inner: &'genv GlobalEnvInner<'genv, 'tcx>,
44}
45
46struct GlobalEnvInner<'genv, 'tcx> {
47 tcx: TyCtxt<'tcx>,
48 sess: &'genv FluxSession,
49 arena: &'genv fhir::Arena,
50 cstore: Box<CrateStoreDyn>,
51 queries: Queries<'genv, 'tcx>,
52 tempdir: TempDir,
53}
54
55impl<'tcx> GlobalEnv<'_, 'tcx> {
56 pub fn enter<'a, R>(
57 tcx: TyCtxt<'tcx>,
58 sess: &'a FluxSession,
59 cstore: Box<CrateStoreDyn>,
60 arena: &'a fhir::Arena,
61 providers: Providers,
62 f: impl for<'genv> FnOnce(GlobalEnv<'genv, 'tcx>) -> R,
63 ) -> R {
64 let tempdir = TempDir::new_in(lean_parent_dir(tcx)).unwrap();
67 let queries = Queries::new(providers);
68 let inner = GlobalEnvInner { tcx, sess, cstore, arena, queries, tempdir };
69 f(GlobalEnv { inner: &inner })
70 }
71}
72
73impl<'genv, 'tcx> GlobalEnv<'genv, 'tcx> {
74 pub fn queried(self, def_id: DefId) -> bool {
75 self.inner.queries.queried(def_id)
76 }
77
78 pub fn run_query_if_reached<K: DispatchKey, R>(
84 self,
85 key: K,
86 query: impl FnOnce(Self, K) -> QueryResult<R>,
87 ) -> QueryResult<R> {
88 if !self.inner.queries.queried(key.def_id()) {
89 return Err(QueryErr::NotIncluded { def_id: key.def_id() });
90 }
91
92 query(self, key)
93 }
94
95 pub fn tcx(self) -> TyCtxt<'tcx> {
96 self.inner.tcx
97 }
98
99 pub fn sess(self) -> &'genv FluxSession {
100 self.inner.sess
101 }
102
103 pub fn collect_specs(self) -> &'genv crate::Specs {
104 self.inner.queries.collect_specs(self)
105 }
106
107 pub fn resolve_crate(self) -> &'genv crate::ResolverOutput {
108 self.inner.queries.resolve_crate(self)
109 }
110
111 pub fn lean_parent_dir(self) -> PathBuf {
113 lean_parent_dir(self.tcx())
114 }
115
116 pub fn temp_dir(self) -> &'genv TempDir {
117 &self.inner.tempdir
118 }
119
120 pub fn desugar(self, def_id: LocalDefId) -> QueryResult<fhir::Node<'genv>> {
121 self.inner.queries.desugar(self, def_id)
122 }
123
124 pub fn fhir_attr_map(self, def_id: LocalDefId) -> fhir::AttrMap<'genv> {
125 self.inner.queries.fhir_attr_map(self, def_id)
126 }
127
128 pub fn fhir_crate(self) -> &'genv fhir::FluxItems<'genv> {
129 self.inner.queries.fhir_crate(self)
130 }
131
132 pub fn alloc<T>(&self, val: T) -> &'genv T {
133 self.inner.arena.alloc(val)
134 }
135
136 pub fn alloc_slice<T: Copy>(self, slice: &[T]) -> &'genv [T] {
137 self.inner.arena.alloc_slice_copy(slice)
138 }
139
140 pub fn alloc_slice_fill_iter<T, I>(self, it: I) -> &'genv [T]
141 where
142 I: IntoIterator<Item = T>,
143 I::IntoIter: ExactSizeIterator,
144 {
145 self.inner.arena.alloc_slice_fill_iter(it)
146 }
147
148 pub fn def_kind(&self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
149 self.tcx().def_kind(def_id.into_query_param())
150 }
151
152 pub fn alloc_slice_with_capacity<T, I>(self, cap: usize, it: I) -> &'genv [T]
162 where
163 I: IntoIterator<Item = T>,
164 {
165 let layout = alloc::Layout::array::<T>(cap).unwrap_or_else(|_| bug!("out of memory"));
166 let dst = self.inner.arena.alloc_layout(layout).cast::<T>();
167 unsafe {
168 let mut len = 0;
169 for (i, v) in it.into_iter().take(cap).enumerate() {
170 len += 1;
171 ptr::write(dst.as_ptr().add(i), v);
172 }
173
174 slice::from_raw_parts(dst.as_ptr(), len)
175 }
176 }
177
178 pub fn inlined_body(self, did: FluxDefId) -> rty::Binder<rty::Expr> {
179 self.normalized_defns(did.krate()).inlined_body(did)
180 }
181
182 pub fn normalized_info(self, did: FluxDefId) -> rty::FuncInfo {
183 self.normalized_defns(did.krate()).func_info(did).clone()
184 }
185
186 pub fn normalized_defns(self, krate: CrateNum) -> Rc<rty::NormalizedDefns> {
187 self.inner.queries.normalized_defns(self, krate)
188 }
189
190 pub fn prim_rel_for(self, op: &rty::BinOp) -> QueryResult<Option<&'genv rty::PrimRel>> {
191 Ok(self.inner.queries.prim_rel(self)?.get(op))
192 }
193
194 pub fn qualifiers(self) -> QueryResult<&'genv [rty::Qualifier]> {
195 self.inner.queries.qualifiers(self)
196 }
197
198 pub fn qualifiers_for(
200 self,
201 did: LocalDefId,
202 ) -> QueryResult<impl Iterator<Item = &'genv rty::Qualifier>> {
203 let quals = self.fhir_attr_map(did).qualifiers;
204 let names: UnordSet<_> = quals.iter().copied().collect();
205 Ok(self.qualifiers()?.iter().filter(move |qual| {
206 match qual.kind {
207 QualifierKind::Global => true,
208 QualifierKind::Hint => qual.def_id.parent() == did,
209 QualifierKind::Local => names.contains(&qual.def_id),
210 }
211 }))
212 }
213
214 pub fn reveals_for(self, did: LocalDefId) -> &'genv [FluxDefId] {
216 self.fhir_attr_map(did).reveals
217 }
218
219 pub fn func_sort(self, def_id: impl IntoQueryParam<FluxDefId>) -> rty::PolyFuncSort {
220 self.inner
221 .queries
222 .func_sort(self, def_id.into_query_param())
223 }
224
225 pub fn func_span(self, def_id: impl IntoQueryParam<FluxDefId>) -> Span {
226 self.inner
227 .queries
228 .func_span(self, def_id.into_query_param())
229 }
230
231 pub fn should_inline_fun(self, def_id: FluxDefId) -> bool {
232 let is_poly = self.func_sort(def_id).params().len() > 0;
233 is_poly || !flux_config::smt_define_fun()
234 }
235
236 pub fn variances_of(self, did: DefId) -> &'tcx [Variance] {
237 self.tcx().variances_of(did)
238 }
239
240 pub fn mir(self, def_id: LocalDefId) -> QueryResult<Rc<mir::BodyRoot<'tcx>>> {
241 self.inner.queries.mir(self, def_id)
242 }
243
244 pub fn lower_generics_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::Generics<'tcx> {
245 self.inner
246 .queries
247 .lower_generics_of(self, def_id.into_query_param())
248 }
249
250 pub fn lower_predicates_of(
251 self,
252 def_id: impl IntoQueryParam<DefId>,
253 ) -> QueryResult<ty::GenericPredicates> {
254 self.inner
255 .queries
256 .lower_predicates_of(self, def_id.into_query_param())
257 }
258
259 pub fn lower_type_of(
260 self,
261 def_id: impl IntoQueryParam<DefId>,
262 ) -> QueryResult<ty::EarlyBinder<ty::Ty>> {
263 self.inner
264 .queries
265 .lower_type_of(self, def_id.into_query_param())
266 }
267
268 pub fn lower_fn_sig(
269 self,
270 def_id: impl Into<DefId>,
271 ) -> QueryResult<ty::EarlyBinder<ty::PolyFnSig>> {
272 self.inner.queries.lower_fn_sig(self, def_id.into())
273 }
274
275 pub fn adt_def(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::AdtDef> {
276 self.inner.queries.adt_def(self, def_id.into_query_param())
277 }
278
279 pub fn constant_info(
280 self,
281 def_id: impl IntoQueryParam<DefId>,
282 ) -> QueryResult<rty::ConstantInfo> {
283 self.inner
284 .queries
285 .constant_info(self, def_id.into_query_param())
286 }
287
288 pub fn static_info(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::StaticInfo> {
289 self.inner
290 .queries
291 .static_info(self, def_id.into_query_param())
292 }
293
294 pub fn adt_sort_def_of(
295 self,
296 def_id: impl IntoQueryParam<DefId>,
297 ) -> QueryResult<rty::AdtSortDef> {
298 self.inner
299 .queries
300 .adt_sort_def_of(self, def_id.into_query_param())
301 }
302
303 pub fn sort_decl_param_count(self, def_id: impl IntoQueryParam<FluxDefId>) -> usize {
304 self.inner
305 .queries
306 .sort_decl_param_count(self, def_id.into_query_param())
307 }
308
309 pub fn check_wf(self, def_id: LocalDefId) -> QueryResult<Rc<rty::WfckResults>> {
310 self.inner.queries.check_wf(self, def_id)
311 }
312
313 pub fn impl_trait_ref(self, impl_id: DefId) -> QueryResult<rty::EarlyBinder<rty::TraitRef>> {
314 let trait_ref = self.tcx().impl_trait_ref(impl_id);
315 let trait_ref = trait_ref.skip_binder();
316 let trait_ref = trait_ref
317 .lower(self.tcx())
318 .map_err(|err| QueryErr::unsupported(impl_id, err.into_err()))?
319 .refine(&Refiner::default_for_item(self, impl_id)?)?;
320 Ok(rty::EarlyBinder(trait_ref))
321 }
322
323 pub fn generics_of(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::Generics> {
324 self.inner
325 .queries
326 .generics_of(self, def_id.into_query_param())
327 }
328
329 pub fn refinement_generics_of(
330 self,
331 def_id: impl IntoQueryParam<DefId>,
332 ) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
333 self.inner
334 .queries
335 .refinement_generics_of(self, def_id.into_query_param())
336 }
337
338 pub fn predicates_of(
339 self,
340 def_id: impl IntoQueryParam<DefId>,
341 ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
342 self.inner
343 .queries
344 .predicates_of(self, def_id.into_query_param())
345 }
346
347 pub fn assoc_refinements_of(
348 self,
349 def_id: impl IntoQueryParam<DefId>,
350 ) -> QueryResult<rty::AssocRefinements> {
351 self.inner
352 .queries
353 .assoc_refinements_of(self, def_id.into_query_param())
354 }
355
356 pub fn assoc_refinement(self, assoc_id: FluxDefId) -> QueryResult<rty::AssocReft> {
357 Ok(self.assoc_refinements_of(assoc_id.parent())?.get(assoc_id))
358 }
359
360 pub fn assoc_refinement_body_for_impl(
368 self,
369 trait_assoc_id: FluxDefId,
370 impl_id: DefId,
371 ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
372 let impl_assoc_refts = self.assoc_refinements_of(impl_id)?;
374 if let Some(impl_assoc_reft) = impl_assoc_refts.find(trait_assoc_id.name()) {
375 return self.assoc_refinement_body(impl_assoc_reft.def_id());
376 }
377
378 if let Some(body) = self.default_assoc_refinement_body(trait_assoc_id)? {
380 let impl_trait_ref = self.impl_trait_ref(impl_id)?.instantiate_identity();
381 return Ok(rty::EarlyBinder(body.instantiate(self.tcx(), &impl_trait_ref.args, &[])));
382 }
383
384 Err(QueryErr::MissingAssocReft {
385 impl_id,
386 trait_id: trait_assoc_id.parent(),
387 name: trait_assoc_id.name(),
388 })
389 }
390
391 pub fn default_assoc_refinement_body(
392 self,
393 trait_assoc_id: FluxDefId,
394 ) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
395 self.inner
396 .queries
397 .default_assoc_refinement_body(self, trait_assoc_id)
398 }
399
400 pub fn assoc_refinement_body(
401 self,
402 impl_assoc_id: FluxDefId,
403 ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
404 self.inner
405 .queries
406 .assoc_refinement_body(self, impl_assoc_id)
407 }
408
409 pub fn sort_of_assoc_reft(
410 self,
411 assoc_id: FluxDefId,
412 ) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
413 self.inner.queries.sort_of_assoc_reft(self, assoc_id)
414 }
415
416 pub fn item_bounds(
417 self,
418 def_id: impl IntoQueryParam<DefId>,
419 ) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>> {
420 self.inner
421 .queries
422 .item_bounds(self, def_id.into_query_param())
423 }
424
425 pub fn type_of(
426 self,
427 def_id: impl IntoQueryParam<DefId>,
428 ) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
429 self.inner.queries.type_of(self, def_id.into_query_param())
430 }
431
432 pub fn fn_sig(
433 self,
434 def_id: impl IntoQueryParam<DefId>,
435 ) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
436 self.inner.queries.fn_sig(self, def_id.into_query_param())
437 }
438
439 pub fn variants_of(
440 self,
441 def_id: impl IntoQueryParam<DefId>,
442 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
443 self.inner
444 .queries
445 .variants_of(self, def_id.into_query_param())
446 }
447
448 pub fn variant_sig(
449 self,
450 def_id: DefId,
451 variant_idx: VariantIdx,
452 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariant>>> {
453 Ok(self
454 .variants_of(def_id)?
455 .map(|variants| variants.map(|variants| variants[variant_idx.as_usize()].clone())))
456 }
457
458 pub fn lower_late_bound_vars(
459 self,
460 def_id: LocalDefId,
461 ) -> QueryResult<List<ty::BoundVariableKind>> {
462 self.inner.queries.lower_late_bound_vars(self, def_id)
463 }
464
465 pub fn no_panic(self, def_id: impl IntoQueryParam<DefId>) -> bool {
467 self.inner.queries.no_panic(self, def_id.into_query_param())
468 }
469
470 pub fn is_box(&self, res: fhir::Res) -> bool {
471 res.is_box(self.tcx())
472 }
473
474 pub fn def_id_to_param_index(&self, def_id: DefId) -> u32 {
475 let parent = self.tcx().parent(def_id);
476 let generics = self.tcx().generics_of(parent);
477 generics.param_def_id_to_index(self.tcx(), def_id).unwrap()
478 }
479
480 pub(crate) fn cstore(self) -> &'genv CrateStoreDyn {
481 &*self.inner.cstore
482 }
483
484 pub fn has_trusted_impl(&self, def_id: DefId) -> bool {
485 if let Some(did) = self
486 .resolve_id(def_id)
487 .as_maybe_extern()
488 .map(|id| id.local_id())
489 {
490 self.trusted_impl(did)
491 } else {
492 false
493 }
494 }
495
496 pub fn is_fn_output(&self, def_id: DefId) -> bool {
500 let def_span = self.tcx().def_span(def_id);
501 self.tcx()
502 .require_lang_item(LangItem::FnOnceOutput, def_span)
503 == def_id
504 }
505
506 pub fn is_fn_call(&self, def_id: DefId) -> bool {
510 let methods_and_names = [
511 (LangItem::Fn, sym::call),
512 (LangItem::FnMut, sym::call_mut),
513 (LangItem::FnOnce, sym::call_once),
514 ];
515 let tcx = self.tcx();
516 let Some(assoc_item) = tcx.opt_associated_item(def_id) else { return false };
517 let Some(trait_id) = assoc_item.trait_container(tcx) else { return false };
518
519 methods_and_names.iter().any(|(lang_item, method_name)| {
520 assoc_item.name() == *method_name && tcx.is_lang_item(trait_id, *lang_item)
521 })
522 }
523
524 pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + use<'tcx, 'genv> {
526 self.tcx().iter_local_def_id().filter(move |&local_def_id| {
527 self.maybe_extern_id(local_def_id).is_local() && !self.is_dummy(local_def_id)
528 })
529 }
530
531 pub fn iter_extern_def_id(self) -> impl Iterator<Item = DefId> + use<'tcx, 'genv> {
532 self.tcx()
533 .iter_local_def_id()
534 .filter_map(move |local_def_id| self.maybe_extern_id(local_def_id).as_extern())
535 }
536
537 pub fn maybe_extern_id(self, local_id: LocalDefId) -> MaybeExternId {
538 self.collect_specs()
539 .local_id_to_extern_id
540 .get(&local_id)
541 .map_or_else(
542 || MaybeExternId::Local(local_id),
543 |def_id| MaybeExternId::Extern(local_id, *def_id),
544 )
545 }
546
547 #[expect(clippy::disallowed_methods)]
548 pub fn resolve_id(self, def_id: DefId) -> ResolvedDefId {
549 let maybe_extern_spec = self
550 .collect_specs()
551 .extern_id_to_local_id
552 .get(&def_id)
553 .copied();
554 if let Some(local_id) = maybe_extern_spec {
555 ResolvedDefId::ExternSpec(local_id, def_id)
556 } else if let Some(local_id) = def_id.as_local() {
557 debug_assert!(
558 self.maybe_extern_id(local_id).is_local(),
559 "def id points to dummy local item `{def_id:?}`"
560 );
561 ResolvedDefId::Local(local_id)
562 } else {
563 ResolvedDefId::Extern(def_id)
564 }
565 }
566
567 pub fn infer_opts(self, def_id: LocalDefId) -> config::InferOpts {
568 let mut opts = config::PartialInferOpts::default();
569 self.traverse_parents(def_id, |did| {
570 if let Some(o) = self.fhir_attr_map(did).infer_opts() {
571 opts.merge(&o);
572 }
573 None::<!>
574 });
575 opts.into()
576 }
577
578 fn matches_file_path<F>(&self, def_id: MaybeExternId, matcher: F) -> bool
579 where
580 F: Fn(&Path) -> bool,
581 {
582 let def_id = def_id.local_id();
583 let tcx = self.tcx();
584 let span = tcx.def_span(def_id);
585 let sm = tcx.sess.source_map();
586 let FileName::Real(file_name) = sm.span_to_filename(span) else { return true };
587 let mut file_path = file_name.local_path_if_available();
588
589 if file_path.is_absolute() {
591 let working_dir = tcx.sess.opts.working_dir.local_path_if_available();
592 let Ok(p) = file_path.strip_prefix(working_dir) else { return true };
593 file_path = p;
594 }
595
596 matcher(file_path)
597 }
598
599 fn matches_def(&self, def_id: MaybeExternId, def: &str) -> bool {
600 let def_path = self.tcx().def_path_str(def_id.local_id());
602 def_path.contains(def)
603 }
604
605 fn matches_pos(&self, def_id: MaybeExternId, line: usize, col: usize) -> bool {
606 let def_id = def_id.local_id();
607 let tcx = self.tcx();
608 let hir_id = tcx.local_def_id_to_hir_id(def_id);
609 let body_span = tcx.hir_span_with_body(hir_id);
610 let source_map = tcx.sess.source_map();
611 let lo_pos = source_map.lookup_char_pos(body_span.lo());
612 let start_line = lo_pos.line;
613 let start_col = lo_pos.col_display;
614 let hi_pos = source_map.lookup_char_pos(body_span.hi());
615 let end_line = hi_pos.line;
616 let end_col = hi_pos.col_display;
617
618 if start_line < end_line {
620 start_line <= line && line <= end_line
622 } else {
623 start_line == line && start_col <= col && col <= end_col
625 }
626 }
627
628 fn matches_pattern(&self, def_id: MaybeExternId, pattern: &IncludePattern) -> bool {
632 if self.matches_file_path(def_id, |path| pattern.glob.is_match(path)) {
633 return true;
634 }
635 if pattern.defs.iter().any(|def| self.matches_def(def_id, def)) {
636 return true;
637 }
638 if pattern.spans.iter().any(|pos| {
639 self.matches_file_path(def_id, |path| path.ends_with(&pos.file))
640 && self.matches_pos(def_id, pos.line, pos.column)
641 }) {
642 return true;
643 }
644 false
645 }
646
647 fn matches_trusted_pattern(&self, def_id: MaybeExternId) -> bool {
651 let Some(pattern) = config::trusted_pattern() else { return false };
652 self.matches_pattern(def_id, pattern)
653 }
654
655 fn matches_trusted_impl_pattern(&self, def_id: MaybeExternId) -> bool {
659 let Some(pattern) = config::trusted_impl_pattern() else { return false };
660 self.matches_pattern(def_id, pattern)
661 }
662
663 fn matches_included_pattern(&self, def_id: MaybeExternId) -> bool {
667 let Some(pattern) = config::include_pattern() else { return true };
668 self.matches_pattern(def_id, pattern)
669 }
670
671 pub fn included(&self, def_id: MaybeExternId) -> bool {
672 self.matches_included_pattern(def_id) || self.matches_trusted_pattern(def_id)
673 }
674
675 pub fn trusted(self, def_id: LocalDefId) -> bool {
679 let annotation = self
680 .traverse_parents(def_id, |did| self.fhir_attr_map(did).trusted())
681 .map(|trusted| trusted.to_bool())
682 .unwrap_or_else(config::trusted_default);
683 annotation || self.matches_trusted_pattern(MaybeExternId::Local(def_id))
684 }
685
686 pub fn trusted_impl(self, def_id: LocalDefId) -> bool {
687 let annotation = self
688 .traverse_parents(def_id, |did| self.fhir_attr_map(did).trusted_impl())
689 .map(|trusted| trusted.to_bool())
690 .unwrap_or(false);
691 annotation || self.matches_trusted_impl_pattern(MaybeExternId::Local(def_id))
692 }
693
694 pub fn is_dummy(self, def_id: LocalDefId) -> bool {
698 self.traverse_parents(def_id, |did| {
699 self.collect_specs()
700 .dummy_extern
701 .contains(&did)
702 .then_some(())
703 })
704 .is_some()
705 }
706
707 pub fn ignored(self, def_id: LocalDefId) -> bool {
711 self.traverse_parents(def_id, |did| self.fhir_attr_map(did).ignored())
712 .map(|ignored| ignored.to_bool())
713 .unwrap_or_else(config::ignore_default)
714 }
715
716 pub fn should_fail(self, def_id: LocalDefId) -> bool {
718 self.fhir_attr_map(def_id).should_fail()
719 }
720
721 pub fn proven_externally(self, def_id: LocalDefId) -> Option<Span> {
723 self.fhir_attr_map(def_id).proven_externally()
724 }
725
726 fn traverse_parents<T>(
728 self,
729 mut def_id: LocalDefId,
730 mut f: impl FnMut(LocalDefId) -> Option<T>,
731 ) -> Option<T> {
732 loop {
733 if let Some(v) = f(def_id) {
734 break Some(v);
735 }
736
737 if let Some(parent) = self.tcx().opt_local_parent(def_id) {
738 def_id = parent;
739 } else {
740 break None;
741 }
742 }
743 }
744}
745
746impl<'genv, 'tcx> GlobalEnv<'genv, 'tcx> {
747 pub fn fhir_iter_flux_items(
748 self,
749 ) -> impl Iterator<Item = (FluxLocalDefId, fhir::FluxItem<'genv>)> {
750 self.fhir_crate()
751 .items
752 .iter()
753 .map(|(id, item)| (*id, *item))
754 }
755
756 pub fn fhir_sort_decl(&self, def_id: FluxLocalDefId) -> Option<&fhir::SortDecl> {
757 self.fhir_crate().items.get(&def_id).and_then(|item| {
758 if let fhir::FluxItem::SortDecl(sort_decl) = item { Some(*sort_decl) } else { None }
759 })
760 }
761
762 pub fn fhir_spec_func_body(
763 &self,
764 def_id: FluxLocalDefId,
765 ) -> Option<&'genv fhir::SpecFunc<'genv>> {
766 self.fhir_crate()
767 .items
768 .get(&def_id)
769 .and_then(|item| if let fhir::FluxItem::Func(defn) = item { Some(*defn) } else { None })
770 }
771
772 pub fn fhir_qualifiers(self) -> impl Iterator<Item = &'genv fhir::Qualifier<'genv>> {
773 self.fhir_crate().items.values().filter_map(|item| {
774 if let fhir::FluxItem::Qualifier(qual) = item { Some(*qual) } else { None }
775 })
776 }
777
778 pub fn fhir_primop_props(self) -> impl Iterator<Item = &'genv fhir::PrimOpProp<'genv>> {
779 self.fhir_crate().items.values().filter_map(|item| {
780 if let fhir::FluxItem::PrimOpProp(prop) = item { Some(*prop) } else { None }
781 })
782 }
783
784 pub fn fhir_get_generics(
785 self,
786 def_id: LocalDefId,
787 ) -> QueryResult<Option<&'genv fhir::Generics<'genv>>> {
788 if matches!(self.def_kind(def_id), DefKind::Closure) {
790 Ok(None)
791 } else {
792 Ok(Some(self.fhir_expect_owner_node(def_id)?.generics()))
793 }
794 }
795
796 pub fn fhir_expect_refinement_kind(
797 self,
798 def_id: LocalDefId,
799 ) -> QueryResult<&'genv fhir::RefinementKind<'genv>> {
800 let kind = match &self.fhir_expect_item(def_id)?.kind {
801 fhir::ItemKind::Enum(enum_def) => &enum_def.refinement,
802 fhir::ItemKind::Struct(struct_def) => &struct_def.refinement,
803 _ => bug!("expected struct, enum or type alias"),
804 };
805 Ok(kind)
806 }
807
808 pub fn fhir_expect_item(self, def_id: LocalDefId) -> QueryResult<&'genv fhir::Item<'genv>> {
809 if let fhir::Node::Item(item) = self.fhir_node(def_id)? {
810 Ok(item)
811 } else {
812 Err(query_bug!(def_id, "expected item: `{def_id:?}`"))
813 }
814 }
815
816 pub fn fhir_expect_owner_node(self, def_id: LocalDefId) -> QueryResult<fhir::OwnerNode<'genv>> {
817 let Some(owner) = self.fhir_node(def_id)?.as_owner() else {
818 return Err(query_bug!(def_id, "cannot find owner node"));
819 };
820 Ok(owner)
821 }
822
823 pub fn fhir_node(self, def_id: LocalDefId) -> QueryResult<fhir::Node<'genv>> {
824 self.desugar(def_id)
825 }
826}
827
828#[macro_export]
829macro_rules! try_alloc_slice {
830 ($genv:expr, $slice:expr, $map:expr $(,)?) => {{
831 let slice = $slice;
832 $crate::try_alloc_slice!($genv, cap: slice.len(), slice.into_iter().map($map))
833 }};
834 ($genv:expr, cap: $cap:expr, $it:expr $(,)?) => {{
835 let mut err = None;
836 let slice = $genv.alloc_slice_with_capacity($cap, $it.into_iter().collect_errors(&mut err));
837 err.map_or(Ok(slice), Err)
838 }};
839}
840
841impl ErrorEmitter for GlobalEnv<'_, '_> {
842 fn emit<'a>(&'a self, err: impl rustc_errors::Diagnostic<'a>) -> rustc_span::ErrorGuaranteed {
843 self.sess().emit(err)
844 }
845}
846
847fn lean_parent_dir(tcx: TyCtxt) -> PathBuf {
848 tcx.sess
849 .opts
850 .working_dir
851 .local_path_if_available()
852 .to_path_buf()
853 .join(config::lean_dir())
854}