1use std::{
2 alloc,
3 cell::RefCell,
4 path::{Path, PathBuf},
5 ptr,
6 rc::Rc,
7 slice,
8};
9
10use flux_arc_interner::List;
11use flux_common::{bug, result::ErrorEmitter};
12use flux_config::{self as config, IncludePattern};
13use flux_errors::FluxSession;
14use flux_rustc_bridge::{self, lowering::Lower, mir, ty};
15use flux_syntax::symbols::sym;
16use rustc_attr_ir::LangItem;
17use rustc_data_structures::unord::{UnordMap, UnordSet};
18use rustc_hir::{
19 def::DefKind,
20 def_id::{CrateNum, DefId, LocalDefId},
21};
22use rustc_middle::{
23 query::IntoQueryKey,
24 ty::{TyCtxt, Variance},
25};
26use rustc_span::{FileName, Span};
27pub use rustc_span::{Symbol, symbol::Ident};
28use tempfile::TempDir;
29
30use crate::{
31 PanicReason, PanicSpec,
32 call_graph::NodeKey,
33 cstore::CrateStoreDyn,
34 def_id::{FluxDefId, FluxLocalDefId, MaybeExternId, ResolvedDefId},
35 fhir::{self, VariantIdx},
36 queries::{DispatchKey, Providers, Queries, QueryErr, QueryResult},
37 query_bug,
38 rty::{
39 self, QualifierKind,
40 refining::{Refine as _, Refiner},
41 },
42};
43
44#[derive(Clone, Copy)]
45pub struct GlobalEnv<'genv, 'tcx> {
46 inner: &'genv GlobalEnvInner<'genv, 'tcx>,
47}
48
49pub struct WeakKvarInfo {
50 pub solutions: Vec<rty::Binder<rty::Expr>>,
53 pub sorts: Vec<rty::Sort>,
56}
57pub type WeakKvarMap = UnordMap<u32, WeakKvarInfo>;
58
59struct GlobalEnvInner<'genv, 'tcx> {
60 tcx: TyCtxt<'tcx>,
61 sess: &'genv FluxSession,
62 arena: &'genv fhir::Arena,
63 cstore: Box<CrateStoreDyn<'tcx>>,
64 queries: Queries<'genv, 'tcx>,
65 tempdir: TempDir,
66 weak_kvars: RefCell<UnordMap<DefId, Rc<WeakKvarMap>>>,
67}
68
69impl<'tcx> GlobalEnv<'_, 'tcx> {
70 pub fn enter<'a, R>(
71 tcx: TyCtxt<'tcx>,
72 sess: &'a FluxSession,
73 cstore: Box<CrateStoreDyn<'tcx>>,
74 arena: &'a fhir::Arena,
75 providers: Providers,
76 f: impl for<'genv> FnOnce(GlobalEnv<'genv, 'tcx>) -> R,
77 ) -> R {
78 let tempdir = TempDir::new_in(lean_parent_dir(tcx)).unwrap();
81 let queries = Queries::new(providers);
82 let inner = GlobalEnvInner {
83 tcx,
84 sess,
85 cstore,
86 arena,
87 queries,
88 tempdir,
89 weak_kvars: Default::default(),
90 };
91 f(GlobalEnv { inner: &inner })
92 }
93}
94
95impl<'genv, 'tcx> GlobalEnv<'genv, 'tcx> {
96 pub fn queried(self, def_id: DefId) -> bool {
97 self.inner.queries.queried(def_id)
98 }
99
100 pub fn run_query_if_reached<K: DispatchKey, R>(
106 self,
107 key: K,
108 query: impl FnOnce(Self, K) -> QueryResult<R>,
109 ) -> QueryResult<R> {
110 if !self.inner.queries.queried(key.def_id()) {
111 return Err(QueryErr::NotIncluded { def_id: key.def_id() });
112 }
113
114 query(self, key)
115 }
116
117 pub fn tcx(self) -> TyCtxt<'tcx> {
118 self.inner.tcx
119 }
120
121 pub fn sess(self) -> &'genv FluxSession {
122 self.inner.sess
123 }
124
125 pub fn collect_specs(self) -> &'genv crate::Specs {
126 self.inner.queries.collect_specs(self)
127 }
128
129 pub fn resolve_crate(self) -> &'genv crate::ResolverOutput {
130 self.inner.queries.resolve_crate(self)
131 }
132
133 pub fn flux_module_children(self, def_id: DefId) -> &'genv [fhir::FluxModChild] {
136 self.inner.queries.flux_module_children(self, def_id)
137 }
138
139 pub fn lean_parent_dir(self) -> PathBuf {
141 lean_parent_dir(self.tcx())
142 }
143
144 pub fn temp_dir(self) -> &'genv TempDir {
145 &self.inner.tempdir
146 }
147
148 pub fn desugar(self, def_id: LocalDefId) -> QueryResult<fhir::Node<'genv>> {
149 self.inner.queries.desugar(self, def_id)
150 }
151
152 pub fn fhir_attr_map(self, def_id: LocalDefId) -> fhir::AttrMap<'genv> {
153 self.inner.queries.fhir_attr_map(self, def_id)
154 }
155
156 pub fn fhir_crate(self) -> &'genv fhir::FluxItems<'genv> {
157 self.inner.queries.fhir_crate(self)
158 }
159
160 pub fn alloc<T>(&self, val: T) -> &'genv T {
161 self.inner.arena.alloc(val)
162 }
163
164 pub fn alloc_slice<T: Copy>(self, slice: &[T]) -> &'genv [T] {
165 self.inner.arena.alloc_slice_copy(slice)
166 }
167
168 pub fn alloc_slice_fill_iter<T, I>(self, it: I) -> &'genv [T]
169 where
170 I: IntoIterator<Item = T>,
171 I::IntoIter: ExactSizeIterator,
172 {
173 self.inner.arena.alloc_slice_fill_iter(it)
174 }
175
176 pub fn def_kind(&self, def_id: impl IntoQueryKey<DefId>) -> DefKind {
177 self.tcx().def_kind(def_id.into_query_key())
178 }
179
180 pub fn alloc_slice_with_capacity<T, I>(self, cap: usize, it: I) -> &'genv [T]
190 where
191 I: IntoIterator<Item = T>,
192 {
193 let layout = alloc::Layout::array::<T>(cap).unwrap_or_else(|_| bug!("out of memory"));
194 let dst = self.inner.arena.alloc_layout(layout).cast::<T>();
195 unsafe {
196 let mut len = 0;
197 for (i, v) in it.into_iter().take(cap).enumerate() {
198 len += 1;
199 ptr::write(dst.as_ptr().add(i), v);
200 }
201
202 slice::from_raw_parts(dst.as_ptr(), len)
203 }
204 }
205
206 pub fn call_graph(self) -> &'genv crate::call_graph::CallGraph<'tcx> {
207 self.inner.queries.call_graph(self)
208 }
209
210 pub fn inferred_no_panic_key(self, key: NodeKey<'tcx>) -> PanicSpec {
213 self.inferred_no_panic_local()
214 .get(&key)
215 .copied()
216 .unwrap_or(PanicSpec::MightPanic(PanicReason::NotInCallGraph))
217 }
218
219 pub fn inferred_no_panic_local(self) -> Rc<UnordMap<NodeKey<'tcx>, PanicSpec>> {
221 self.inner.queries.inferred_no_panic(self)
222 }
223
224 pub fn inferred_no_panic_external(self, key: NodeKey<'tcx>) -> PanicSpec {
230 let table = self.cstore().inferred_no_panic(key.def_id().krate);
231 if let Some(&spec) = table.get(&key) {
232 return spec;
233 }
234 if let NodeKey::Mono(instance) = key
235 && let Some(&spec) = table.get(&NodeKey::Item(instance.def_id()))
236 {
237 return spec;
238 }
239 PanicSpec::MightPanic(PanicReason::NotInCallGraph)
240 }
241
242 pub fn inlined_body(self, did: FluxDefId) -> rty::Binder<rty::Expr> {
246 self.inner.queries.inlined_body(self, did)
247 }
248
249 pub fn spec_func(self, did: FluxDefId) -> rty::SpecFunc {
250 self.spec_funcs(did.krate()).get(did.index()).clone()
251 }
252
253 pub fn spec_func_rank(self, did: FluxDefId) -> usize {
255 self.spec_funcs(did.krate()).rank(did.index())
256 }
257
258 pub fn spec_funcs(self, krate: CrateNum) -> Rc<rty::SpecFuncs> {
260 self.inner.queries.spec_funcs(self, krate)
261 }
262
263 pub fn prim_rel_for(self, op: &rty::BinOp) -> QueryResult<Option<&'genv rty::PrimRel>> {
264 Ok(self.inner.queries.prim_rel(self)?.get(op))
265 }
266
267 pub fn qualifiers(self) -> QueryResult<&'genv [rty::Qualifier]> {
268 self.inner.queries.qualifiers(self)
269 }
270
271 pub fn axioms(self) -> QueryResult<&'genv [rty::Axiom]> {
273 self.inner.queries.axioms(self)
274 }
275
276 pub fn qualifiers_for(
278 self,
279 did: LocalDefId,
280 ) -> QueryResult<impl Iterator<Item = &'genv rty::Qualifier>> {
281 let quals = self.fhir_attr_map(did).qualifiers;
282 let names: UnordSet<_> = quals.iter().copied().collect();
283 Ok(self.qualifiers()?.iter().filter(move |qual| {
284 match qual.kind {
285 QualifierKind::Global => true,
286 QualifierKind::Hint => {
287 self.flux_item_enclosing_item(qual.def_id.to_def_id()) == did.to_def_id()
288 }
289 QualifierKind::Local => names.contains(&qual.def_id),
290 }
291 }))
292 }
293
294 fn flux_item_enclosing_item(self, def_id: FluxDefId) -> DefId {
298 let declarer = def_id.parent();
299 if self.def_kind(declarer) == DefKind::Const {
300 self.tcx().typeck_root_def_id(self.tcx().parent(declarer))
301 } else {
302 declarer
303 }
304 }
305
306 pub fn reveals_for(self, did: LocalDefId) -> impl Iterator<Item = FluxDefId> + 'genv {
308 self.fhir_attr_map(did)
309 .reveals
310 .iter()
311 .map(|(def_id, _)| *def_id)
312 }
313
314 pub fn hides_for(self, did: LocalDefId) -> impl Iterator<Item = FluxDefId> + 'genv {
316 self.fhir_attr_map(did)
317 .hides
318 .iter()
319 .map(|(def_id, _)| *def_id)
320 }
321
322 pub fn func_sort(self, def_id: impl IntoQueryKey<FluxDefId>) -> rty::PolyFuncSort {
323 self.inner.queries.func_sort(self, def_id.into_query_key())
324 }
325
326 pub fn func_span(self, def_id: impl IntoQueryKey<FluxDefId>) -> Span {
327 self.inner.queries.func_span(self, def_id.into_query_key())
328 }
329
330 pub fn should_inline_fun(self, def_id: FluxDefId) -> bool {
334 self.func_sort(def_id).params().len() > 0
335 }
336
337 pub fn variances_of(self, did: DefId) -> &'tcx [Variance] {
338 self.tcx().variances_of(did)
339 }
340
341 pub fn mir(self, def_id: LocalDefId) -> QueryResult<Rc<mir::BodyRoot<'tcx>>> {
342 self.inner.queries.mir(self, def_id)
343 }
344
345 pub fn lower_generics_of(self, def_id: impl IntoQueryKey<DefId>) -> ty::Generics<'tcx> {
346 self.inner
347 .queries
348 .lower_generics_of(self, def_id.into_query_key())
349 }
350
351 pub fn lower_predicates_of(
352 self,
353 def_id: impl IntoQueryKey<DefId>,
354 ) -> QueryResult<ty::GenericPredicates> {
355 self.inner
356 .queries
357 .lower_predicates_of(self, def_id.into_query_key())
358 }
359
360 pub fn lower_type_of(
361 self,
362 def_id: impl IntoQueryKey<DefId>,
363 ) -> QueryResult<ty::EarlyBinder<ty::Ty>> {
364 self.inner
365 .queries
366 .lower_type_of(self, def_id.into_query_key())
367 }
368
369 pub fn lower_fn_sig(
370 self,
371 def_id: impl Into<DefId>,
372 ) -> QueryResult<ty::EarlyBinder<ty::PolyFnSig>> {
373 self.inner.queries.lower_fn_sig(self, def_id.into())
374 }
375
376 pub fn adt_def(self, def_id: impl IntoQueryKey<DefId>) -> QueryResult<rty::AdtDef> {
377 self.inner.queries.adt_def(self, def_id.into_query_key())
378 }
379
380 pub fn invariants_of(
381 self,
382 def_id: impl IntoQueryKey<DefId>,
383 ) -> rty::EarlyBinder<List<rty::Invariant>> {
384 self.inner
385 .queries
386 .invariants_of(self, def_id.into_query_key())
387 }
388
389 pub fn constant_info(self, def_id: impl IntoQueryKey<DefId>) -> QueryResult<rty::ConstantInfo> {
390 self.inner
391 .queries
392 .constant_info(self, def_id.into_query_key())
393 }
394
395 pub fn static_info(self, def_id: impl IntoQueryKey<DefId>) -> QueryResult<rty::Ty> {
397 self.inner
398 .queries
399 .static_info(self, def_id.into_query_key())
400 }
401
402 pub fn adt_sort_def_of(self, def_id: impl IntoQueryKey<DefId>) -> QueryResult<rty::AdtSortDef> {
403 self.inner
404 .queries
405 .adt_sort_def_of(self, def_id.into_query_key())
406 }
407
408 pub fn sort_decl_param_count(self, def_id: impl IntoQueryKey<FluxDefId>) -> usize {
409 self.inner
410 .queries
411 .sort_decl_param_count(self, def_id.into_query_key())
412 }
413
414 pub fn check_wf(self, def_id: LocalDefId) -> QueryResult<Rc<rty::WfckResults>> {
415 self.inner.queries.check_wf(self, def_id)
416 }
417
418 pub fn late_bound_refinement_params(
426 self,
427 def_id: LocalDefId,
428 ) -> QueryResult<&'genv [fhir::ParamId]> {
429 self.inner
430 .queries
431 .late_bound_refinement_params(self, def_id)
432 }
433
434 pub fn impl_trait_ref(self, impl_id: DefId) -> QueryResult<rty::EarlyBinder<rty::TraitRef>> {
435 let trait_ref = self.tcx().impl_trait_ref(impl_id);
436 let trait_ref = trait_ref.skip_binder();
437 let trait_ref = trait_ref
438 .lower(self.tcx())
439 .map_err(|err| QueryErr::unsupported(impl_id, err.into_err()))?
440 .refine(&Refiner::default_for_item(self, impl_id)?)?;
441 Ok(rty::EarlyBinder(trait_ref))
442 }
443
444 pub fn generics_of(self, def_id: impl IntoQueryKey<DefId>) -> QueryResult<rty::Generics> {
445 self.inner
446 .queries
447 .generics_of(self, def_id.into_query_key())
448 }
449
450 pub fn refinement_generics_of(
451 self,
452 def_id: impl IntoQueryKey<DefId>,
453 ) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
454 self.inner
455 .queries
456 .refinement_generics_of(self, def_id.into_query_key())
457 }
458
459 pub fn predicates_of(
460 self,
461 def_id: impl IntoQueryKey<DefId>,
462 ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
463 self.inner
464 .queries
465 .predicates_of(self, def_id.into_query_key())
466 }
467
468 pub fn assoc_refinements_of(
469 self,
470 def_id: impl IntoQueryKey<DefId>,
471 ) -> QueryResult<rty::AssocRefinements> {
472 self.inner
473 .queries
474 .assoc_refinements_of(self, def_id.into_query_key())
475 }
476
477 pub fn assoc_refinement(self, assoc_id: FluxDefId) -> QueryResult<rty::AssocReft> {
478 Ok(self.assoc_refinements_of(assoc_id.parent())?.get(assoc_id))
479 }
480
481 pub fn assoc_refinement_body_for_impl(
489 self,
490 trait_assoc_id: FluxDefId,
491 impl_id: DefId,
492 ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
493 let impl_assoc_refts = self.assoc_refinements_of(impl_id)?;
495 if let Some(impl_assoc_reft) = impl_assoc_refts.find(trait_assoc_id.name()) {
496 return self.assoc_refinement_body(impl_assoc_reft.def_id());
497 }
498
499 if let Some(body) = self.default_assoc_refinement_body(trait_assoc_id)? {
501 let impl_trait_ref = self.impl_trait_ref(impl_id)?.instantiate_identity();
502 return Ok(rty::EarlyBinder(body.instantiate(self.tcx(), &impl_trait_ref.args, &[])));
503 }
504
505 Err(QueryErr::MissingAssocReft {
506 impl_id,
507 trait_id: trait_assoc_id.parent(),
508 name: trait_assoc_id.name(),
509 })
510 }
511
512 pub fn default_assoc_refinement_body(
513 self,
514 trait_assoc_id: FluxDefId,
515 ) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
516 self.inner
517 .queries
518 .default_assoc_refinement_body(self, trait_assoc_id)
519 }
520
521 pub fn assoc_refinement_body(
522 self,
523 impl_assoc_id: FluxDefId,
524 ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
525 self.inner
526 .queries
527 .assoc_refinement_body(self, impl_assoc_id)
528 }
529
530 pub fn sort_of_assoc_reft(
531 self,
532 assoc_id: FluxDefId,
533 ) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
534 self.inner.queries.sort_of_assoc_reft(self, assoc_id)
535 }
536
537 pub fn item_bounds(
538 self,
539 def_id: impl IntoQueryKey<DefId>,
540 ) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>> {
541 self.inner
542 .queries
543 .item_bounds(self, def_id.into_query_key())
544 }
545
546 pub fn type_of(
547 self,
548 def_id: impl IntoQueryKey<DefId>,
549 ) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
550 self.inner.queries.type_of(self, def_id.into_query_key())
551 }
552
553 pub fn fn_sig(
554 self,
555 def_id: impl IntoQueryKey<DefId>,
556 ) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
557 self.inner.queries.fn_sig(self, def_id.into_query_key())
558 }
559
560 pub fn feed_weak_kvars(self, def_id: DefId, wk: WeakKvarMap) {
561 self.inner
562 .weak_kvars
563 .borrow_mut()
564 .insert(def_id, Rc::new(wk));
565 }
566
567 pub fn weak_kvars_for(self, def_id: DefId) -> Option<Rc<WeakKvarMap>> {
568 self.inner.weak_kvars.borrow().get(&def_id).cloned()
569 }
570
571 pub fn variants_of(
572 self,
573 def_id: impl IntoQueryKey<DefId>,
574 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
575 self.inner
576 .queries
577 .variants_of(self, def_id.into_query_key())
578 }
579
580 pub fn variant_sig(
581 self,
582 def_id: DefId,
583 variant_idx: VariantIdx,
584 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariant>>> {
585 Ok(self
586 .variants_of(def_id)?
587 .map(|variants| variants.map(|variants| variants[variant_idx.as_usize()].clone())))
588 }
589
590 pub fn cstore_has_crate(self, krate: CrateNum) -> bool {
592 self.cstore().has_crate(krate)
593 }
594
595 pub fn no_panic(self, def_id: impl IntoQueryKey<DefId>) -> bool {
597 self.inner.queries.no_panic(self, def_id.into_query_key())
598 }
599
600 pub fn assume_parametric_params(self, def_id: impl IntoQueryKey<DefId>) -> UnordSet<u32> {
601 self.inner
602 .queries
603 .assume_parametric_params(self, def_id.into_query_key())
604 }
605
606 pub fn is_box(&self, res: fhir::Res) -> bool {
607 res.is_box(self.tcx())
608 }
609
610 pub fn def_id_to_param_index(&self, def_id: DefId) -> u32 {
611 let parent = self.tcx().parent(def_id);
612 let generics = self.tcx().generics_of(parent);
613 generics.param_def_id_to_index(self.tcx(), def_id).unwrap()
614 }
615
616 pub(crate) fn cstore(self) -> &'genv CrateStoreDyn<'tcx> {
617 &*self.inner.cstore
618 }
619
620 pub fn has_trusted_impl(&self, def_id: DefId) -> bool {
621 if let Some(did) = self
622 .resolve_id(def_id)
623 .as_maybe_extern()
624 .map(|id| id.local_id())
625 {
626 self.trusted_impl(did)
627 } else {
628 false
629 }
630 }
631
632 pub fn is_fn_output(&self, def_id: DefId) -> bool {
636 let def_span = self.tcx().def_span(def_id);
637 self.tcx()
638 .require_lang_item(LangItem::FnOnceOutput, def_span)
639 == def_id
640 }
641
642 pub fn is_fn_call(&self, def_id: DefId) -> bool {
646 let methods_and_names = [
647 (LangItem::Fn, sym::call),
648 (LangItem::FnMut, sym::call_mut),
649 (LangItem::FnOnce, sym::call_once),
650 ];
651 let tcx = self.tcx();
652 let Some(assoc_item) = tcx.opt_associated_item(def_id) else { return false };
653 let Some(trait_id) = assoc_item.trait_container(tcx) else { return false };
654
655 methods_and_names.iter().any(|(lang_item, method_name)| {
656 assoc_item.name() == *method_name && tcx.is_lang_item(trait_id, *lang_item)
657 })
658 }
659
660 pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + use<'tcx, 'genv> {
662 self.tcx().iter_local_def_id().filter(move |&local_def_id| {
663 self.maybe_extern_id(local_def_id).is_local() && !self.is_dummy(local_def_id)
664 })
665 }
666
667 pub fn iter_extern_def_id(self) -> impl Iterator<Item = DefId> + use<'tcx, 'genv> {
668 self.tcx()
669 .iter_local_def_id()
670 .filter_map(move |local_def_id| self.maybe_extern_id(local_def_id).as_extern())
671 }
672
673 pub fn maybe_extern_id(self, local_id: LocalDefId) -> MaybeExternId {
674 self.collect_specs()
675 .local_id_to_extern_id
676 .get(&local_id)
677 .map_or_else(
678 || MaybeExternId::Local(local_id),
679 |def_id| MaybeExternId::Extern(local_id, *def_id),
680 )
681 }
682
683 #[expect(clippy::disallowed_methods)]
684 pub fn resolve_id(self, def_id: DefId) -> ResolvedDefId {
685 let maybe_extern_spec = self
686 .collect_specs()
687 .extern_id_to_local_id
688 .get(&def_id)
689 .copied();
690 if let Some(local_id) = maybe_extern_spec {
691 ResolvedDefId::ExternSpec(local_id, def_id)
692 } else if let Some(local_id) = def_id.as_local() {
693 debug_assert!(
694 self.maybe_extern_id(local_id).is_local(),
695 "def id points to dummy local item `{def_id:?}`"
696 );
697 ResolvedDefId::Local(local_id)
698 } else {
699 ResolvedDefId::Extern(def_id)
700 }
701 }
702
703 pub fn infer_opts(self, def_id: LocalDefId) -> config::InferOpts {
704 let mut opts = config::PartialInferOpts::default();
705 self.traverse_parents(def_id, |did| {
706 if let Some(o) = self.fhir_attr_map(did).infer_opts() {
707 opts.merge(&o);
708 }
709 None::<!>
710 });
711 opts.into()
712 }
713
714 fn matches_file_path<F>(&self, def_id: MaybeExternId, matcher: F) -> bool
715 where
716 F: Fn(&Path) -> bool,
717 {
718 let def_id = def_id.local_id();
719 let tcx = self.tcx();
720 let span = tcx.def_span(def_id);
721 let sm = tcx.sess.source_map();
722 let FileName::Real(file_name) = sm.span_to_filename(span) else { return true };
723 let Some(mut file_path) = file_name.local_path() else { return true };
724
725 if file_path.is_absolute() {
727 let Some(working_dir) = sm.working_dir().local_path() else { return true };
728 let Ok(p) = file_path.strip_prefix(working_dir) else { return true };
729 file_path = p;
730 }
731
732 matcher(file_path)
733 }
734
735 fn matches_def(&self, def_id: MaybeExternId, def: &str) -> bool {
736 let def_path = self.tcx().def_path_str(def_id.local_id());
738 def_path.contains(def)
739 }
740
741 fn matches_pos(&self, def_id: MaybeExternId, line: usize, col: usize) -> bool {
742 let def_id = def_id.local_id();
743 let tcx = self.tcx();
744 let hir_id = tcx.local_def_id_to_hir_id(def_id);
745 let body_span = tcx.hir_span_with_body(hir_id);
746 let source_map = tcx.sess.source_map();
747 let lo_pos = source_map.lookup_char_pos(body_span.lo());
748 let start_line = lo_pos.line;
749 let start_col = lo_pos.col_display;
750 let hi_pos = source_map.lookup_char_pos(body_span.hi());
751 let end_line = hi_pos.line;
752 let end_col = hi_pos.col_display;
753
754 if start_line < end_line {
756 start_line <= line && line <= end_line
758 } else {
759 start_line == line && start_col <= col && col <= end_col
761 }
762 }
763
764 fn matches_pattern(&self, def_id: MaybeExternId, pattern: &IncludePattern) -> bool {
768 if self.matches_file_path(def_id, |path| pattern.glob.is_match(path)) {
769 return true;
770 }
771 if pattern.defs.iter().any(|def| self.matches_def(def_id, def)) {
772 return true;
773 }
774 if pattern.spans.iter().any(|pos| {
775 self.matches_file_path(def_id, |path| path.ends_with(&pos.file))
776 && self.matches_pos(def_id, pos.line, pos.column)
777 }) {
778 return true;
779 }
780 false
781 }
782
783 fn matches_trusted_pattern(&self, def_id: MaybeExternId) -> bool {
787 let Some(pattern) = config::trusted_pattern() else { return false };
788 self.matches_pattern(def_id, pattern)
789 }
790
791 fn matches_trusted_impl_pattern(&self, def_id: MaybeExternId) -> bool {
795 let Some(pattern) = config::trusted_impl_pattern() else { return false };
796 self.matches_pattern(def_id, pattern)
797 }
798
799 fn matches_included_pattern(&self, def_id: MaybeExternId) -> bool {
803 let Some(pattern) = config::include_pattern() else { return true };
804 self.matches_pattern(def_id, pattern)
805 }
806
807 pub fn included(&self, def_id: MaybeExternId) -> bool {
808 self.matches_included_pattern(def_id) || self.matches_trusted_pattern(def_id)
809 }
810
811 pub fn trusted(self, def_id: LocalDefId) -> bool {
815 let annotation = self
816 .traverse_parents(def_id, |did| self.fhir_attr_map(did).trusted())
817 .map(|trusted| trusted.to_bool())
818 .unwrap_or_else(config::trusted_default);
819 annotation || self.matches_trusted_pattern(MaybeExternId::Local(def_id))
820 }
821
822 pub fn trusted_impl(self, def_id: LocalDefId) -> bool {
823 let annotation = self
824 .traverse_parents(def_id, |did| self.fhir_attr_map(did).trusted_impl())
825 .map(|trusted| trusted.to_bool())
826 .unwrap_or(false);
827 annotation || self.matches_trusted_impl_pattern(MaybeExternId::Local(def_id))
828 }
829
830 pub fn trusted_derive(self, def_id: LocalDefId) -> bool {
833 if let Some(trusted) = self.fhir_attr_map(def_id).trusted_derive() {
834 return trusted.to_bool();
835 }
836 self.adt_def(def_id)
837 .is_ok_and(|adt_def| adt_def.is_opaque())
838 }
839
840 pub fn derive_self_ty(self, def_id: LocalDefId) -> Option<LocalDefId> {
849 let tcx = self.tcx();
850 let impl_id = tcx.local_parent(def_id);
851 if !matches!(tcx.def_kind(impl_id), DefKind::Impl { .. }) {
852 return None;
853 }
854 let adt_def_id = tcx
855 .type_of(impl_id)
856 .instantiate_identity()
857 .skip_norm_wip()
858 .ty_adt_def()?
859 .did();
860 match self.resolve_id(adt_def_id) {
861 ResolvedDefId::Local(local_id) | ResolvedDefId::ExternSpec(local_id, _) => {
862 Some(local_id)
863 }
864 ResolvedDefId::Extern(_) => None,
865 }
866 }
867
868 pub fn no_suggestions(self, def_id: LocalDefId) -> bool {
871 if !config::suggestions() {
872 return true;
873 }
874 self.traverse_parents(def_id, |did| {
875 if self.fhir_attr_map(did).no_suggestions() {
877 Some(true)
878 } else {
880 None
881 }
882 })
883 .unwrap_or(false)
884 }
885
886 pub fn is_dummy(self, def_id: LocalDefId) -> bool {
890 self.traverse_parents(def_id, |did| {
891 self.collect_specs()
892 .dummy_extern
893 .contains(&did)
894 .then_some(())
895 })
896 .is_some()
897 }
898
899 pub fn ignored(self, def_id: LocalDefId) -> bool {
903 self.traverse_parents(def_id, |did| self.fhir_attr_map(did).ignored())
904 .map(|ignored| ignored.to_bool())
905 .unwrap_or_else(config::ignore_default)
906 }
907
908 pub fn should_fail(self, def_id: LocalDefId) -> bool {
910 self.fhir_attr_map(def_id).should_fail()
911 }
912
913 pub fn proven_externally(self, def_id: LocalDefId) -> Option<Span> {
915 self.fhir_attr_map(def_id).proven_externally()
916 }
917
918 pub fn spec_attr_span(self, def_id: DefId) -> Option<Span> {
921 let specs = self.collect_specs();
922 specs
923 .get_spec_attr_span(def_id)
924 .or_else(|| {
925 let local_id = specs.extern_id_to_local_id.get(&def_id)?;
926 specs.get_spec_attr_span(local_id.to_def_id())
927 })
928 .or_else(|| self.cstore().spec_attr_span(def_id))
929 }
930
931 pub fn spec_attr_string(self, def_id: DefId) -> Option<String> {
934 let span = self.spec_attr_span(def_id)?;
935 self.tcx().sess.source_map().span_to_snippet(span).ok()
936 }
937
938 fn traverse_parents<T>(
940 self,
941 mut def_id: LocalDefId,
942 mut f: impl FnMut(LocalDefId) -> Option<T>,
943 ) -> Option<T> {
944 loop {
945 if let Some(v) = f(def_id) {
946 break Some(v);
947 }
948
949 if let Some(parent) = self.tcx().opt_local_parent(def_id) {
950 def_id = parent;
951 } else {
952 break None;
953 }
954 }
955 }
956}
957
958impl<'genv, 'tcx> GlobalEnv<'genv, 'tcx> {
959 pub fn fhir_iter_flux_items(
960 self,
961 ) -> impl Iterator<Item = (FluxLocalDefId, fhir::FluxItem<'genv>)> {
962 self.fhir_crate()
963 .items
964 .iter()
965 .map(|(id, item)| (*id, *item))
966 }
967
968 pub fn fhir_sort_decl(&self, def_id: FluxLocalDefId) -> Option<&fhir::SortDecl> {
969 self.fhir_crate().items.get(&def_id).and_then(|item| {
970 if let fhir::FluxItem::SortDecl(sort_decl) = item { Some(*sort_decl) } else { None }
971 })
972 }
973
974 pub fn fhir_spec_func_body(
975 &self,
976 def_id: FluxLocalDefId,
977 ) -> Option<&'genv fhir::SpecFunc<'genv>> {
978 self.fhir_crate()
979 .items
980 .get(&def_id)
981 .and_then(|item| if let fhir::FluxItem::Func(defn) = item { Some(*defn) } else { None })
982 }
983
984 pub fn fhir_qualifiers(self) -> impl Iterator<Item = &'genv fhir::Qualifier<'genv>> {
985 self.fhir_crate().items.values().filter_map(|item| {
986 if let fhir::FluxItem::Qualifier(qual) = item { Some(*qual) } else { None }
987 })
988 }
989
990 pub fn fhir_primop_props(self) -> impl Iterator<Item = &'genv fhir::PrimOpProp<'genv>> {
991 self.fhir_crate().items.values().filter_map(|item| {
992 if let fhir::FluxItem::PrimOpProp(prop) = item { Some(*prop) } else { None }
993 })
994 }
995
996 pub fn fhir_axioms(self) -> impl Iterator<Item = &'genv fhir::Axiom<'genv>> {
997 self.fhir_crate().items.values().filter_map(|item| {
998 if let fhir::FluxItem::Axiom(axiom) = item { Some(*axiom) } else { None }
999 })
1000 }
1001
1002 pub fn fhir_get_generics(
1003 self,
1004 def_id: LocalDefId,
1005 ) -> QueryResult<Option<&'genv fhir::Generics<'genv>>> {
1006 if matches!(self.def_kind(def_id), DefKind::Closure) {
1008 Ok(None)
1009 } else {
1010 Ok(Some(self.fhir_expect_owner_node(def_id)?.generics()))
1011 }
1012 }
1013
1014 pub fn fhir_split_refinement_params(
1018 self,
1019 def_id: LocalDefId,
1020 ) -> QueryResult<(Vec<fhir::RefineParam<'genv>>, Vec<fhir::RefineParam<'genv>>)> {
1021 let Some(generics) = self.fhir_get_generics(def_id)? else {
1022 return Ok((vec![], vec![]));
1023 };
1024 let late_bound = self.late_bound_refinement_params(def_id)?;
1025 Ok(generics
1026 .refinement_params
1027 .iter()
1028 .copied()
1029 .partition(|param| !late_bound.contains(¶m.id)))
1030 }
1031
1032 pub fn fhir_expect_refinement_kind(
1033 self,
1034 def_id: LocalDefId,
1035 ) -> QueryResult<&'genv fhir::RefinementKind<'genv>> {
1036 let kind = match &self.fhir_expect_item(def_id)?.kind {
1037 fhir::ItemKind::Enum(enum_def) => &enum_def.refinement,
1038 fhir::ItemKind::Struct(struct_def) => &struct_def.refinement,
1039 _ => bug!("expected struct, enum or type alias"),
1040 };
1041 Ok(kind)
1042 }
1043
1044 pub fn fhir_expect_item(self, def_id: LocalDefId) -> QueryResult<&'genv fhir::Item<'genv>> {
1045 if let fhir::Node::Item(item) = self.fhir_node(def_id)? {
1046 Ok(item)
1047 } else {
1048 Err(query_bug!(def_id, "expected item: `{def_id:?}`"))
1049 }
1050 }
1051
1052 pub fn fhir_expect_owner_node(self, def_id: LocalDefId) -> QueryResult<fhir::OwnerNode<'genv>> {
1053 let Some(owner) = self.fhir_node(def_id)?.as_owner() else {
1054 return Err(query_bug!(def_id, "cannot find owner node"));
1055 };
1056 Ok(owner)
1057 }
1058
1059 pub fn fhir_node(self, def_id: LocalDefId) -> QueryResult<fhir::Node<'genv>> {
1060 self.desugar(def_id)
1061 }
1062}
1063
1064#[macro_export]
1065macro_rules! try_alloc_slice {
1066 ($genv:expr, $slice:expr, $map:expr $(,)?) => {{
1067 let slice = $slice;
1068 $crate::try_alloc_slice!($genv, cap: slice.len(), slice.into_iter().map($map))
1069 }};
1070 ($genv:expr, cap: $cap:expr, $it:expr $(,)?) => {{
1071 let mut err = None;
1072 let slice = $genv.alloc_slice_with_capacity($cap, $it.into_iter().collect_errors(&mut err));
1073 err.map_or(Ok(slice), Err)
1074 }};
1075}
1076
1077impl ErrorEmitter for GlobalEnv<'_, '_> {
1078 fn emit<'a>(&'a self, err: impl rustc_errors::Diagnostic<'a>) -> rustc_span::ErrorGuaranteed {
1079 self.sess().emit(err)
1080 }
1081}
1082
1083fn lean_parent_dir(tcx: TyCtxt) -> PathBuf {
1084 tcx.sess
1085 .source_map()
1086 .working_dir()
1087 .local_path()
1088 .unwrap()
1089 .join(config::lean_dir())
1090}