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