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_data_structures::unord::{UnordMap, UnordSet};
17use rustc_hir::{
18 LangItem,
19 def::DefKind,
20 def_id::{CrateNum, DefId, LocalDefId},
21};
22use rustc_middle::{
23 query::IntoQueryParam,
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 lean_parent_dir(self) -> PathBuf {
135 lean_parent_dir(self.tcx())
136 }
137
138 pub fn temp_dir(self) -> &'genv TempDir {
139 &self.inner.tempdir
140 }
141
142 pub fn desugar(self, def_id: LocalDefId) -> QueryResult<fhir::Node<'genv>> {
143 self.inner.queries.desugar(self, def_id)
144 }
145
146 pub fn fhir_attr_map(self, def_id: LocalDefId) -> fhir::AttrMap<'genv> {
147 self.inner.queries.fhir_attr_map(self, def_id)
148 }
149
150 pub fn fhir_crate(self) -> &'genv fhir::FluxItems<'genv> {
151 self.inner.queries.fhir_crate(self)
152 }
153
154 pub fn alloc<T>(&self, val: T) -> &'genv T {
155 self.inner.arena.alloc(val)
156 }
157
158 pub fn alloc_slice<T: Copy>(self, slice: &[T]) -> &'genv [T] {
159 self.inner.arena.alloc_slice_copy(slice)
160 }
161
162 pub fn alloc_slice_fill_iter<T, I>(self, it: I) -> &'genv [T]
163 where
164 I: IntoIterator<Item = T>,
165 I::IntoIter: ExactSizeIterator,
166 {
167 self.inner.arena.alloc_slice_fill_iter(it)
168 }
169
170 pub fn def_kind(&self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
171 self.tcx().def_kind(def_id.into_query_param())
172 }
173
174 pub fn alloc_slice_with_capacity<T, I>(self, cap: usize, it: I) -> &'genv [T]
184 where
185 I: IntoIterator<Item = T>,
186 {
187 let layout = alloc::Layout::array::<T>(cap).unwrap_or_else(|_| bug!("out of memory"));
188 let dst = self.inner.arena.alloc_layout(layout).cast::<T>();
189 unsafe {
190 let mut len = 0;
191 for (i, v) in it.into_iter().take(cap).enumerate() {
192 len += 1;
193 ptr::write(dst.as_ptr().add(i), v);
194 }
195
196 slice::from_raw_parts(dst.as_ptr(), len)
197 }
198 }
199
200 pub fn call_graph(self) -> &'genv crate::call_graph::CallGraph<'tcx> {
201 self.inner.queries.call_graph(self)
202 }
203
204 pub fn inferred_no_panic_key(self, key: NodeKey<'tcx>) -> PanicSpec {
207 self.inferred_no_panic_local()
208 .get(&key)
209 .copied()
210 .unwrap_or(PanicSpec::MightPanic(PanicReason::NotInCallGraph))
211 }
212
213 pub fn inferred_no_panic_local(self) -> Rc<UnordMap<NodeKey<'tcx>, PanicSpec>> {
215 self.inner.queries.inferred_no_panic(self)
216 }
217
218 pub fn inferred_no_panic_external(self, key: NodeKey<'tcx>) -> PanicSpec {
224 let table = self.cstore().inferred_no_panic(key.def_id().krate);
225 if let Some(&spec) = table.get(&key) {
226 return spec;
227 }
228 if let NodeKey::Mono(instance) = key
229 && let Some(&spec) = table.get(&NodeKey::Item(instance.def_id()))
230 {
231 return spec;
232 }
233 PanicSpec::MightPanic(PanicReason::NotInCallGraph)
234 }
235
236 pub fn inlined_body(self, did: FluxDefId) -> rty::Binder<rty::Expr> {
237 self.normalized_defns(did.krate()).inlined_body(did)
238 }
239
240 pub fn normalized_info(self, did: FluxDefId) -> rty::FuncInfo {
241 self.normalized_defns(did.krate()).func_info(did).clone()
242 }
243
244 pub fn normalized_defns(self, krate: CrateNum) -> Rc<rty::NormalizedDefns> {
245 self.inner.queries.normalized_defns(self, krate)
246 }
247
248 pub fn prim_rel_for(self, op: &rty::BinOp) -> QueryResult<Option<&'genv rty::PrimRel>> {
249 Ok(self.inner.queries.prim_rel(self)?.get(op))
250 }
251
252 pub fn qualifiers(self) -> QueryResult<&'genv [rty::Qualifier]> {
253 self.inner.queries.qualifiers(self)
254 }
255
256 pub fn qualifiers_for(
258 self,
259 did: LocalDefId,
260 ) -> QueryResult<impl Iterator<Item = &'genv rty::Qualifier>> {
261 let quals = self.fhir_attr_map(did).qualifiers;
262 let names: UnordSet<_> = quals.iter().copied().collect();
263 Ok(self.qualifiers()?.iter().filter(move |qual| {
264 match qual.kind {
265 QualifierKind::Global => true,
266 QualifierKind::Hint => qual.def_id.parent() == did,
267 QualifierKind::Local => names.contains(&qual.def_id),
268 }
269 }))
270 }
271
272 pub fn reveals_for(self, did: LocalDefId) -> &'genv [FluxDefId] {
274 self.fhir_attr_map(did).reveals
275 }
276
277 pub fn func_sort(self, def_id: impl IntoQueryParam<FluxDefId>) -> rty::PolyFuncSort {
278 self.inner
279 .queries
280 .func_sort(self, def_id.into_query_param())
281 }
282
283 pub fn func_span(self, def_id: impl IntoQueryParam<FluxDefId>) -> Span {
284 self.inner
285 .queries
286 .func_span(self, def_id.into_query_param())
287 }
288
289 pub fn should_inline_fun(self, def_id: FluxDefId) -> bool {
290 let is_poly = self.func_sort(def_id).params().len() > 0;
291 is_poly || !flux_config::smt_define_fun()
292 }
293
294 pub fn variances_of(self, did: DefId) -> &'tcx [Variance] {
295 self.tcx().variances_of(did)
296 }
297
298 pub fn mir(self, def_id: LocalDefId) -> QueryResult<Rc<mir::BodyRoot<'tcx>>> {
299 self.inner.queries.mir(self, def_id)
300 }
301
302 pub fn lower_generics_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::Generics<'tcx> {
303 self.inner
304 .queries
305 .lower_generics_of(self, def_id.into_query_param())
306 }
307
308 pub fn lower_predicates_of(
309 self,
310 def_id: impl IntoQueryParam<DefId>,
311 ) -> QueryResult<ty::GenericPredicates> {
312 self.inner
313 .queries
314 .lower_predicates_of(self, def_id.into_query_param())
315 }
316
317 pub fn lower_type_of(
318 self,
319 def_id: impl IntoQueryParam<DefId>,
320 ) -> QueryResult<ty::EarlyBinder<ty::Ty>> {
321 self.inner
322 .queries
323 .lower_type_of(self, def_id.into_query_param())
324 }
325
326 pub fn lower_fn_sig(
327 self,
328 def_id: impl Into<DefId>,
329 ) -> QueryResult<ty::EarlyBinder<ty::PolyFnSig>> {
330 self.inner.queries.lower_fn_sig(self, def_id.into())
331 }
332
333 pub fn adt_def(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::AdtDef> {
334 self.inner.queries.adt_def(self, def_id.into_query_param())
335 }
336
337 pub fn constant_info(
338 self,
339 def_id: impl IntoQueryParam<DefId>,
340 ) -> QueryResult<rty::ConstantInfo> {
341 self.inner
342 .queries
343 .constant_info(self, def_id.into_query_param())
344 }
345
346 pub fn static_info(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::StaticInfo> {
347 self.inner
348 .queries
349 .static_info(self, def_id.into_query_param())
350 }
351
352 pub fn adt_sort_def_of(
353 self,
354 def_id: impl IntoQueryParam<DefId>,
355 ) -> QueryResult<rty::AdtSortDef> {
356 self.inner
357 .queries
358 .adt_sort_def_of(self, def_id.into_query_param())
359 }
360
361 pub fn sort_decl_param_count(self, def_id: impl IntoQueryParam<FluxDefId>) -> usize {
362 self.inner
363 .queries
364 .sort_decl_param_count(self, def_id.into_query_param())
365 }
366
367 pub fn check_wf(self, def_id: LocalDefId) -> QueryResult<Rc<rty::WfckResults>> {
368 self.inner.queries.check_wf(self, def_id)
369 }
370
371 pub fn impl_trait_ref(self, impl_id: DefId) -> QueryResult<rty::EarlyBinder<rty::TraitRef>> {
372 let trait_ref = self.tcx().impl_trait_ref(impl_id);
373 let trait_ref = trait_ref.skip_binder();
374 let trait_ref = trait_ref
375 .lower(self.tcx())
376 .map_err(|err| QueryErr::unsupported(impl_id, err.into_err()))?
377 .refine(&Refiner::default_for_item(self, impl_id)?)?;
378 Ok(rty::EarlyBinder(trait_ref))
379 }
380
381 pub fn generics_of(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::Generics> {
382 self.inner
383 .queries
384 .generics_of(self, def_id.into_query_param())
385 }
386
387 pub fn refinement_generics_of(
388 self,
389 def_id: impl IntoQueryParam<DefId>,
390 ) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
391 self.inner
392 .queries
393 .refinement_generics_of(self, def_id.into_query_param())
394 }
395
396 pub fn predicates_of(
397 self,
398 def_id: impl IntoQueryParam<DefId>,
399 ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
400 self.inner
401 .queries
402 .predicates_of(self, def_id.into_query_param())
403 }
404
405 pub fn assoc_refinements_of(
406 self,
407 def_id: impl IntoQueryParam<DefId>,
408 ) -> QueryResult<rty::AssocRefinements> {
409 self.inner
410 .queries
411 .assoc_refinements_of(self, def_id.into_query_param())
412 }
413
414 pub fn assoc_refinement(self, assoc_id: FluxDefId) -> QueryResult<rty::AssocReft> {
415 Ok(self.assoc_refinements_of(assoc_id.parent())?.get(assoc_id))
416 }
417
418 pub fn assoc_refinement_body_for_impl(
426 self,
427 trait_assoc_id: FluxDefId,
428 impl_id: DefId,
429 ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
430 let impl_assoc_refts = self.assoc_refinements_of(impl_id)?;
432 if let Some(impl_assoc_reft) = impl_assoc_refts.find(trait_assoc_id.name()) {
433 return self.assoc_refinement_body(impl_assoc_reft.def_id());
434 }
435
436 if let Some(body) = self.default_assoc_refinement_body(trait_assoc_id)? {
438 let impl_trait_ref = self.impl_trait_ref(impl_id)?.instantiate_identity();
439 return Ok(rty::EarlyBinder(body.instantiate(self.tcx(), &impl_trait_ref.args, &[])));
440 }
441
442 Err(QueryErr::MissingAssocReft {
443 impl_id,
444 trait_id: trait_assoc_id.parent(),
445 name: trait_assoc_id.name(),
446 })
447 }
448
449 pub fn default_assoc_refinement_body(
450 self,
451 trait_assoc_id: FluxDefId,
452 ) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
453 self.inner
454 .queries
455 .default_assoc_refinement_body(self, trait_assoc_id)
456 }
457
458 pub fn assoc_refinement_body(
459 self,
460 impl_assoc_id: FluxDefId,
461 ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
462 self.inner
463 .queries
464 .assoc_refinement_body(self, impl_assoc_id)
465 }
466
467 pub fn sort_of_assoc_reft(
468 self,
469 assoc_id: FluxDefId,
470 ) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
471 self.inner.queries.sort_of_assoc_reft(self, assoc_id)
472 }
473
474 pub fn item_bounds(
475 self,
476 def_id: impl IntoQueryParam<DefId>,
477 ) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>> {
478 self.inner
479 .queries
480 .item_bounds(self, def_id.into_query_param())
481 }
482
483 pub fn type_of(
484 self,
485 def_id: impl IntoQueryParam<DefId>,
486 ) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
487 self.inner.queries.type_of(self, def_id.into_query_param())
488 }
489
490 pub fn fn_sig(
491 self,
492 def_id: impl IntoQueryParam<DefId>,
493 ) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
494 self.inner.queries.fn_sig(self, def_id.into_query_param())
495 }
496
497 pub fn feed_weak_kvars(self, def_id: DefId, wk: WeakKvarMap) {
498 self.inner
499 .weak_kvars
500 .borrow_mut()
501 .insert(def_id, Rc::new(wk));
502 }
503
504 pub fn weak_kvars_for(self, def_id: DefId) -> Option<Rc<WeakKvarMap>> {
505 self.inner.weak_kvars.borrow().get(&def_id).cloned()
506 }
507
508 pub fn variants_of(
509 self,
510 def_id: impl IntoQueryParam<DefId>,
511 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
512 self.inner
513 .queries
514 .variants_of(self, def_id.into_query_param())
515 }
516
517 pub fn variant_sig(
518 self,
519 def_id: DefId,
520 variant_idx: VariantIdx,
521 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariant>>> {
522 Ok(self
523 .variants_of(def_id)?
524 .map(|variants| variants.map(|variants| variants[variant_idx.as_usize()].clone())))
525 }
526
527 pub fn cstore_has_crate(self, krate: CrateNum) -> bool {
529 self.cstore().has_crate(krate)
530 }
531
532 pub fn no_panic(self, def_id: impl IntoQueryParam<DefId>) -> bool {
534 self.inner.queries.no_panic(self, def_id.into_query_param())
535 }
536
537 pub fn assume_parametric_params(self, def_id: impl IntoQueryParam<DefId>) -> UnordSet<u32> {
538 self.inner
539 .queries
540 .assume_parametric_params(self, def_id.into_query_param())
541 }
542
543 pub fn is_box(&self, res: fhir::Res) -> bool {
544 res.is_box(self.tcx())
545 }
546
547 pub fn def_id_to_param_index(&self, def_id: DefId) -> u32 {
548 let parent = self.tcx().parent(def_id);
549 let generics = self.tcx().generics_of(parent);
550 generics.param_def_id_to_index(self.tcx(), def_id).unwrap()
551 }
552
553 pub(crate) fn cstore(self) -> &'genv CrateStoreDyn<'tcx> {
554 &*self.inner.cstore
555 }
556
557 pub fn has_trusted_impl(&self, def_id: DefId) -> bool {
558 if let Some(did) = self
559 .resolve_id(def_id)
560 .as_maybe_extern()
561 .map(|id| id.local_id())
562 {
563 self.trusted_impl(did)
564 } else {
565 false
566 }
567 }
568
569 pub fn is_fn_output(&self, def_id: DefId) -> bool {
573 let def_span = self.tcx().def_span(def_id);
574 self.tcx()
575 .require_lang_item(LangItem::FnOnceOutput, def_span)
576 == def_id
577 }
578
579 pub fn is_fn_call(&self, def_id: DefId) -> bool {
583 let methods_and_names = [
584 (LangItem::Fn, sym::call),
585 (LangItem::FnMut, sym::call_mut),
586 (LangItem::FnOnce, sym::call_once),
587 ];
588 let tcx = self.tcx();
589 let Some(assoc_item) = tcx.opt_associated_item(def_id) else { return false };
590 let Some(trait_id) = assoc_item.trait_container(tcx) else { return false };
591
592 methods_and_names.iter().any(|(lang_item, method_name)| {
593 assoc_item.name() == *method_name && tcx.is_lang_item(trait_id, *lang_item)
594 })
595 }
596
597 pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + use<'tcx, 'genv> {
599 self.tcx().iter_local_def_id().filter(move |&local_def_id| {
600 self.maybe_extern_id(local_def_id).is_local() && !self.is_dummy(local_def_id)
601 })
602 }
603
604 pub fn iter_extern_def_id(self) -> impl Iterator<Item = DefId> + use<'tcx, 'genv> {
605 self.tcx()
606 .iter_local_def_id()
607 .filter_map(move |local_def_id| self.maybe_extern_id(local_def_id).as_extern())
608 }
609
610 pub fn maybe_extern_id(self, local_id: LocalDefId) -> MaybeExternId {
611 self.collect_specs()
612 .local_id_to_extern_id
613 .get(&local_id)
614 .map_or_else(
615 || MaybeExternId::Local(local_id),
616 |def_id| MaybeExternId::Extern(local_id, *def_id),
617 )
618 }
619
620 #[expect(clippy::disallowed_methods)]
621 pub fn resolve_id(self, def_id: DefId) -> ResolvedDefId {
622 let maybe_extern_spec = self
623 .collect_specs()
624 .extern_id_to_local_id
625 .get(&def_id)
626 .copied();
627 if let Some(local_id) = maybe_extern_spec {
628 ResolvedDefId::ExternSpec(local_id, def_id)
629 } else if let Some(local_id) = def_id.as_local() {
630 debug_assert!(
631 self.maybe_extern_id(local_id).is_local(),
632 "def id points to dummy local item `{def_id:?}`"
633 );
634 ResolvedDefId::Local(local_id)
635 } else {
636 ResolvedDefId::Extern(def_id)
637 }
638 }
639
640 pub fn infer_opts(self, def_id: LocalDefId) -> config::InferOpts {
641 let mut opts = config::PartialInferOpts::default();
642 self.traverse_parents(def_id, |did| {
643 if let Some(o) = self.fhir_attr_map(did).infer_opts() {
644 opts.merge(&o);
645 }
646 None::<!>
647 });
648 opts.into()
649 }
650
651 fn matches_file_path<F>(&self, def_id: MaybeExternId, matcher: F) -> bool
652 where
653 F: Fn(&Path) -> bool,
654 {
655 let def_id = def_id.local_id();
656 let tcx = self.tcx();
657 let span = tcx.def_span(def_id);
658 let sm = tcx.sess.source_map();
659 let FileName::Real(file_name) = sm.span_to_filename(span) else { return true };
660 let Some(mut file_path) = file_name.local_path() else { return true };
661
662 if file_path.is_absolute() {
664 let Some(working_dir) = sm.working_dir().local_path() else { return true };
665 let Ok(p) = file_path.strip_prefix(working_dir) else { return true };
666 file_path = p;
667 }
668
669 matcher(file_path)
670 }
671
672 fn matches_def(&self, def_id: MaybeExternId, def: &str) -> bool {
673 let def_path = self.tcx().def_path_str(def_id.local_id());
675 def_path.contains(def)
676 }
677
678 fn matches_pos(&self, def_id: MaybeExternId, line: usize, col: usize) -> bool {
679 let def_id = def_id.local_id();
680 let tcx = self.tcx();
681 let hir_id = tcx.local_def_id_to_hir_id(def_id);
682 let body_span = tcx.hir_span_with_body(hir_id);
683 let source_map = tcx.sess.source_map();
684 let lo_pos = source_map.lookup_char_pos(body_span.lo());
685 let start_line = lo_pos.line;
686 let start_col = lo_pos.col_display;
687 let hi_pos = source_map.lookup_char_pos(body_span.hi());
688 let end_line = hi_pos.line;
689 let end_col = hi_pos.col_display;
690
691 if start_line < end_line {
693 start_line <= line && line <= end_line
695 } else {
696 start_line == line && start_col <= col && col <= end_col
698 }
699 }
700
701 fn matches_pattern(&self, def_id: MaybeExternId, pattern: &IncludePattern) -> bool {
705 if self.matches_file_path(def_id, |path| pattern.glob.is_match(path)) {
706 return true;
707 }
708 if pattern.defs.iter().any(|def| self.matches_def(def_id, def)) {
709 return true;
710 }
711 if pattern.spans.iter().any(|pos| {
712 self.matches_file_path(def_id, |path| path.ends_with(&pos.file))
713 && self.matches_pos(def_id, pos.line, pos.column)
714 }) {
715 return true;
716 }
717 false
718 }
719
720 fn matches_trusted_pattern(&self, def_id: MaybeExternId) -> bool {
724 let Some(pattern) = config::trusted_pattern() else { return false };
725 self.matches_pattern(def_id, pattern)
726 }
727
728 fn matches_trusted_impl_pattern(&self, def_id: MaybeExternId) -> bool {
732 let Some(pattern) = config::trusted_impl_pattern() else { return false };
733 self.matches_pattern(def_id, pattern)
734 }
735
736 fn matches_included_pattern(&self, def_id: MaybeExternId) -> bool {
740 let Some(pattern) = config::include_pattern() else { return true };
741 self.matches_pattern(def_id, pattern)
742 }
743
744 pub fn included(&self, def_id: MaybeExternId) -> bool {
745 self.matches_included_pattern(def_id) || self.matches_trusted_pattern(def_id)
746 }
747
748 pub fn trusted(self, def_id: LocalDefId) -> bool {
752 let annotation = self
753 .traverse_parents(def_id, |did| self.fhir_attr_map(did).trusted())
754 .map(|trusted| trusted.to_bool())
755 .unwrap_or_else(config::trusted_default);
756 annotation || self.matches_trusted_pattern(MaybeExternId::Local(def_id))
757 }
758
759 pub fn trusted_impl(self, def_id: LocalDefId) -> bool {
760 let annotation = self
761 .traverse_parents(def_id, |did| self.fhir_attr_map(did).trusted_impl())
762 .map(|trusted| trusted.to_bool())
763 .unwrap_or(false);
764 annotation || self.matches_trusted_impl_pattern(MaybeExternId::Local(def_id))
765 }
766
767 pub fn no_suggestions(self, def_id: LocalDefId) -> bool {
769 self.traverse_parents(def_id, |did| {
770 if self.fhir_attr_map(did).no_suggestions() {
772 Some(true)
773 } else {
775 None
776 }
777 })
778 .unwrap_or_else(config::no_suggestions_default)
779 }
780
781 pub fn is_dummy(self, def_id: LocalDefId) -> bool {
785 self.traverse_parents(def_id, |did| {
786 self.collect_specs()
787 .dummy_extern
788 .contains(&did)
789 .then_some(())
790 })
791 .is_some()
792 }
793
794 pub fn ignored(self, def_id: LocalDefId) -> bool {
798 self.traverse_parents(def_id, |did| self.fhir_attr_map(did).ignored())
799 .map(|ignored| ignored.to_bool())
800 .unwrap_or_else(config::ignore_default)
801 }
802
803 pub fn should_fail(self, def_id: LocalDefId) -> bool {
805 self.fhir_attr_map(def_id).should_fail()
806 }
807
808 pub fn proven_externally(self, def_id: LocalDefId) -> Option<Span> {
810 self.fhir_attr_map(def_id).proven_externally()
811 }
812
813 pub fn spec_attr_span(self, def_id: DefId) -> Option<Span> {
815 self.collect_specs().get_spec_attr_span(def_id)
816 }
817
818 fn traverse_parents<T>(
820 self,
821 mut def_id: LocalDefId,
822 mut f: impl FnMut(LocalDefId) -> Option<T>,
823 ) -> Option<T> {
824 loop {
825 if let Some(v) = f(def_id) {
826 break Some(v);
827 }
828
829 if let Some(parent) = self.tcx().opt_local_parent(def_id) {
830 def_id = parent;
831 } else {
832 break None;
833 }
834 }
835 }
836}
837
838impl<'genv, 'tcx> GlobalEnv<'genv, 'tcx> {
839 pub fn fhir_iter_flux_items(
840 self,
841 ) -> impl Iterator<Item = (FluxLocalDefId, fhir::FluxItem<'genv>)> {
842 self.fhir_crate()
843 .items
844 .iter()
845 .map(|(id, item)| (*id, *item))
846 }
847
848 pub fn fhir_sort_decl(&self, def_id: FluxLocalDefId) -> Option<&fhir::SortDecl> {
849 self.fhir_crate().items.get(&def_id).and_then(|item| {
850 if let fhir::FluxItem::SortDecl(sort_decl) = item { Some(*sort_decl) } else { None }
851 })
852 }
853
854 pub fn fhir_spec_func_body(
855 &self,
856 def_id: FluxLocalDefId,
857 ) -> Option<&'genv fhir::SpecFunc<'genv>> {
858 self.fhir_crate()
859 .items
860 .get(&def_id)
861 .and_then(|item| if let fhir::FluxItem::Func(defn) = item { Some(*defn) } else { None })
862 }
863
864 pub fn fhir_qualifiers(self) -> impl Iterator<Item = &'genv fhir::Qualifier<'genv>> {
865 self.fhir_crate().items.values().filter_map(|item| {
866 if let fhir::FluxItem::Qualifier(qual) = item { Some(*qual) } else { None }
867 })
868 }
869
870 pub fn fhir_primop_props(self) -> impl Iterator<Item = &'genv fhir::PrimOpProp<'genv>> {
871 self.fhir_crate().items.values().filter_map(|item| {
872 if let fhir::FluxItem::PrimOpProp(prop) = item { Some(*prop) } else { None }
873 })
874 }
875
876 pub fn fhir_get_generics(
877 self,
878 def_id: LocalDefId,
879 ) -> QueryResult<Option<&'genv fhir::Generics<'genv>>> {
880 if matches!(self.def_kind(def_id), DefKind::Closure) {
882 Ok(None)
883 } else {
884 Ok(Some(self.fhir_expect_owner_node(def_id)?.generics()))
885 }
886 }
887
888 pub fn fhir_expect_refinement_kind(
889 self,
890 def_id: LocalDefId,
891 ) -> QueryResult<&'genv fhir::RefinementKind<'genv>> {
892 let kind = match &self.fhir_expect_item(def_id)?.kind {
893 fhir::ItemKind::Enum(enum_def) => &enum_def.refinement,
894 fhir::ItemKind::Struct(struct_def) => &struct_def.refinement,
895 _ => bug!("expected struct, enum or type alias"),
896 };
897 Ok(kind)
898 }
899
900 pub fn fhir_expect_item(self, def_id: LocalDefId) -> QueryResult<&'genv fhir::Item<'genv>> {
901 if let fhir::Node::Item(item) = self.fhir_node(def_id)? {
902 Ok(item)
903 } else {
904 Err(query_bug!(def_id, "expected item: `{def_id:?}`"))
905 }
906 }
907
908 pub fn fhir_expect_owner_node(self, def_id: LocalDefId) -> QueryResult<fhir::OwnerNode<'genv>> {
909 let Some(owner) = self.fhir_node(def_id)?.as_owner() else {
910 return Err(query_bug!(def_id, "cannot find owner node"));
911 };
912 Ok(owner)
913 }
914
915 pub fn fhir_node(self, def_id: LocalDefId) -> QueryResult<fhir::Node<'genv>> {
916 self.desugar(def_id)
917 }
918}
919
920#[macro_export]
921macro_rules! try_alloc_slice {
922 ($genv:expr, $slice:expr, $map:expr $(,)?) => {{
923 let slice = $slice;
924 $crate::try_alloc_slice!($genv, cap: slice.len(), slice.into_iter().map($map))
925 }};
926 ($genv:expr, cap: $cap:expr, $it:expr $(,)?) => {{
927 let mut err = None;
928 let slice = $genv.alloc_slice_with_capacity($cap, $it.into_iter().collect_errors(&mut err));
929 err.map_or(Ok(slice), Err)
930 }};
931}
932
933impl ErrorEmitter for GlobalEnv<'_, '_> {
934 fn emit<'a>(&'a self, err: impl rustc_errors::Diagnostic<'a>) -> rustc_span::ErrorGuaranteed {
935 self.sess().emit(err)
936 }
937}
938
939fn lean_parent_dir(tcx: TyCtxt) -> PathBuf {
940 tcx.sess
941 .source_map()
942 .working_dir()
943 .local_path()
944 .unwrap()
945 .join(config::lean_dir())
946}