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