1use std::{alloc, path::PathBuf, ptr, rc::Rc, slice};
2
3use flux_arc_interner::List;
4use flux_common::{bug, result::ErrorEmitter};
5use flux_config as config;
6use flux_errors::FluxSession;
7use flux_rustc_bridge::{self, lowering::Lower, mir, ty};
8use flux_syntax::symbols::sym;
9use rustc_data_structures::unord::UnordSet;
10use rustc_hir::{
11 LangItem,
12 def::DefKind,
13 def_id::{CrateNum, DefId, LocalDefId},
14};
15use rustc_middle::{
16 query::IntoQueryParam,
17 ty::{TyCtxt, Variance},
18};
19use rustc_span::Span;
20pub use rustc_span::{Symbol, symbol::Ident};
21use tempfile::TempDir;
22
23use crate::{
24 cstore::CrateStoreDyn,
25 def_id::{FluxDefId, FluxLocalDefId, MaybeExternId, ResolvedDefId},
26 fhir::{self, VariantIdx},
27 queries::{Providers, Queries, QueryErr, QueryResult},
28 query_bug,
29 rty::{
30 self, QualifierKind,
31 refining::{Refine as _, Refiner},
32 },
33};
34
35#[derive(Clone, Copy)]
36pub struct GlobalEnv<'genv, 'tcx> {
37 inner: &'genv GlobalEnvInner<'genv, 'tcx>,
38}
39
40struct GlobalEnvInner<'genv, 'tcx> {
41 tcx: TyCtxt<'tcx>,
42 sess: &'genv FluxSession,
43 arena: &'genv fhir::Arena,
44 cstore: Box<CrateStoreDyn>,
45 queries: Queries<'genv, 'tcx>,
46 tempdir: TempDir,
47}
48
49impl<'tcx> GlobalEnv<'_, 'tcx> {
50 pub fn enter<'a, R>(
51 tcx: TyCtxt<'tcx>,
52 sess: &'a FluxSession,
53 cstore: Box<CrateStoreDyn>,
54 arena: &'a fhir::Arena,
55 providers: Providers,
56 f: impl for<'genv> FnOnce(GlobalEnv<'genv, 'tcx>) -> R,
57 ) -> R {
58 let tempdir = TempDir::new_in(lean_parent_dir(tcx)).unwrap();
61 let queries = Queries::new(providers);
62 let inner = GlobalEnvInner { tcx, sess, cstore, arena, queries, tempdir };
63 f(GlobalEnv { inner: &inner })
64 }
65}
66
67impl<'genv, 'tcx> GlobalEnv<'genv, 'tcx> {
68 pub fn tcx(self) -> TyCtxt<'tcx> {
69 self.inner.tcx
70 }
71
72 pub fn sess(self) -> &'genv FluxSession {
73 self.inner.sess
74 }
75
76 pub fn collect_specs(self) -> &'genv crate::Specs {
77 self.inner.queries.collect_specs(self)
78 }
79
80 pub fn resolve_crate(self) -> &'genv crate::ResolverOutput {
81 self.inner.queries.resolve_crate(self)
82 }
83
84 pub fn lean_parent_dir(self) -> PathBuf {
86 lean_parent_dir(self.tcx())
87 }
88
89 pub fn temp_dir(self) -> &'genv TempDir {
90 &self.inner.tempdir
91 }
92
93 pub fn desugar(self, def_id: LocalDefId) -> QueryResult<fhir::Node<'genv>> {
94 self.inner.queries.desugar(self, def_id)
95 }
96
97 pub fn fhir_attr_map(self, def_id: LocalDefId) -> fhir::AttrMap<'genv> {
98 self.inner.queries.fhir_attr_map(self, def_id)
99 }
100
101 pub fn fhir_crate(self) -> &'genv fhir::FluxItems<'genv> {
102 self.inner.queries.fhir_crate(self)
103 }
104
105 pub fn alloc<T>(&self, val: T) -> &'genv T {
106 self.inner.arena.alloc(val)
107 }
108
109 pub fn alloc_slice<T: Copy>(self, slice: &[T]) -> &'genv [T] {
110 self.inner.arena.alloc_slice_copy(slice)
111 }
112
113 pub fn alloc_slice_fill_iter<T, I>(self, it: I) -> &'genv [T]
114 where
115 I: IntoIterator<Item = T>,
116 I::IntoIter: ExactSizeIterator,
117 {
118 self.inner.arena.alloc_slice_fill_iter(it)
119 }
120
121 pub fn def_kind(&self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
122 self.tcx().def_kind(def_id.into_query_param())
123 }
124
125 pub fn alloc_slice_with_capacity<T, I>(self, cap: usize, it: I) -> &'genv [T]
135 where
136 I: IntoIterator<Item = T>,
137 {
138 let layout = alloc::Layout::array::<T>(cap).unwrap_or_else(|_| bug!("out of memory"));
139 let dst = self.inner.arena.alloc_layout(layout).cast::<T>();
140 unsafe {
141 let mut len = 0;
142 for (i, v) in it.into_iter().take(cap).enumerate() {
143 len += 1;
144 ptr::write(dst.as_ptr().add(i), v);
145 }
146
147 slice::from_raw_parts(dst.as_ptr(), len)
148 }
149 }
150
151 pub fn inlined_body(self, did: FluxDefId) -> rty::Binder<rty::Expr> {
152 self.normalized_defns(did.krate()).inlined_body(did)
153 }
154
155 pub fn normalized_info(self, did: FluxDefId) -> rty::FuncInfo {
156 self.normalized_defns(did.krate()).func_info(did).clone()
157 }
158
159 pub fn normalized_defns(self, krate: CrateNum) -> Rc<rty::NormalizedDefns> {
160 self.inner.queries.normalized_defns(self, krate)
161 }
162
163 pub fn prim_rel_for(self, op: &rty::BinOp) -> QueryResult<Option<&'genv rty::PrimRel>> {
164 Ok(self.inner.queries.prim_rel(self)?.get(op))
165 }
166
167 pub fn qualifiers(self) -> QueryResult<&'genv [rty::Qualifier]> {
168 self.inner.queries.qualifiers(self)
169 }
170
171 pub fn qualifiers_for(
173 self,
174 did: LocalDefId,
175 ) -> QueryResult<impl Iterator<Item = &'genv rty::Qualifier>> {
176 let quals = self.fhir_attr_map(did).qualifiers;
177 let names: UnordSet<_> = quals.iter().copied().collect();
178 Ok(self.qualifiers()?.iter().filter(move |qual| {
179 match qual.kind {
180 QualifierKind::Global => true,
181 QualifierKind::Hint => qual.def_id.parent() == did,
182 QualifierKind::Local => names.contains(&qual.def_id),
183 }
184 }))
185 }
186
187 pub fn reveals_for(self, did: LocalDefId) -> &'genv [FluxDefId] {
189 self.fhir_attr_map(did).reveals
190 }
191
192 pub fn func_sort(self, def_id: impl IntoQueryParam<FluxDefId>) -> rty::PolyFuncSort {
193 self.inner
194 .queries
195 .func_sort(self, def_id.into_query_param())
196 }
197
198 pub fn func_span(self, def_id: impl IntoQueryParam<FluxDefId>) -> Span {
199 self.inner
200 .queries
201 .func_span(self, def_id.into_query_param())
202 }
203
204 pub fn should_inline_fun(self, def_id: FluxDefId) -> bool {
205 let is_poly = self.func_sort(def_id).params().len() > 0;
206 is_poly || !flux_config::smt_define_fun()
207 }
208
209 pub fn variances_of(self, did: DefId) -> &'tcx [Variance] {
210 self.tcx().variances_of(did)
211 }
212
213 pub fn mir(self, def_id: LocalDefId) -> QueryResult<Rc<mir::BodyRoot<'tcx>>> {
214 self.inner.queries.mir(self, def_id)
215 }
216
217 pub fn lower_generics_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::Generics<'tcx> {
218 self.inner
219 .queries
220 .lower_generics_of(self, def_id.into_query_param())
221 }
222
223 pub fn lower_predicates_of(
224 self,
225 def_id: impl IntoQueryParam<DefId>,
226 ) -> QueryResult<ty::GenericPredicates> {
227 self.inner
228 .queries
229 .lower_predicates_of(self, def_id.into_query_param())
230 }
231
232 pub fn lower_type_of(
233 self,
234 def_id: impl IntoQueryParam<DefId>,
235 ) -> QueryResult<ty::EarlyBinder<ty::Ty>> {
236 self.inner
237 .queries
238 .lower_type_of(self, def_id.into_query_param())
239 }
240
241 pub fn lower_fn_sig(
242 self,
243 def_id: impl Into<DefId>,
244 ) -> QueryResult<ty::EarlyBinder<ty::PolyFnSig>> {
245 self.inner.queries.lower_fn_sig(self, def_id.into())
246 }
247
248 pub fn adt_def(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::AdtDef> {
249 self.inner.queries.adt_def(self, def_id.into_query_param())
250 }
251
252 pub fn constant_info(
253 self,
254 def_id: impl IntoQueryParam<DefId>,
255 ) -> QueryResult<rty::ConstantInfo> {
256 self.inner
257 .queries
258 .constant_info(self, def_id.into_query_param())
259 }
260
261 pub fn adt_sort_def_of(
262 self,
263 def_id: impl IntoQueryParam<DefId>,
264 ) -> QueryResult<rty::AdtSortDef> {
265 self.inner
266 .queries
267 .adt_sort_def_of(self, def_id.into_query_param())
268 }
269
270 pub fn sort_decl_param_count(self, def_id: impl IntoQueryParam<FluxDefId>) -> usize {
271 self.inner
272 .queries
273 .sort_decl_param_count(self, def_id.into_query_param())
274 }
275
276 pub fn check_wf(self, def_id: LocalDefId) -> QueryResult<Rc<rty::WfckResults>> {
277 self.inner.queries.check_wf(self, def_id)
278 }
279
280 pub fn impl_trait_ref(self, impl_id: DefId) -> QueryResult<rty::EarlyBinder<rty::TraitRef>> {
281 let trait_ref = self.tcx().impl_trait_ref(impl_id);
282 let trait_ref = trait_ref.skip_binder();
283 let trait_ref = trait_ref
284 .lower(self.tcx())
285 .map_err(|err| QueryErr::unsupported(impl_id, err.into_err()))?
286 .refine(&Refiner::default_for_item(self, impl_id)?)?;
287 Ok(rty::EarlyBinder(trait_ref))
288 }
289
290 pub fn generics_of(self, def_id: impl IntoQueryParam<DefId>) -> QueryResult<rty::Generics> {
291 self.inner
292 .queries
293 .generics_of(self, def_id.into_query_param())
294 }
295
296 pub fn refinement_generics_of(
297 self,
298 def_id: impl IntoQueryParam<DefId>,
299 ) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
300 self.inner
301 .queries
302 .refinement_generics_of(self, def_id.into_query_param())
303 }
304
305 pub fn predicates_of(
306 self,
307 def_id: impl IntoQueryParam<DefId>,
308 ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
309 self.inner
310 .queries
311 .predicates_of(self, def_id.into_query_param())
312 }
313
314 pub fn assoc_refinements_of(
315 self,
316 def_id: impl IntoQueryParam<DefId>,
317 ) -> QueryResult<rty::AssocRefinements> {
318 self.inner
319 .queries
320 .assoc_refinements_of(self, def_id.into_query_param())
321 }
322
323 pub fn assoc_refinement(self, assoc_id: FluxDefId) -> QueryResult<rty::AssocReft> {
324 Ok(self.assoc_refinements_of(assoc_id.parent())?.get(assoc_id))
325 }
326
327 pub fn assoc_refinement_body_for_impl(
335 self,
336 trait_assoc_id: FluxDefId,
337 impl_id: DefId,
338 ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
339 let impl_assoc_refts = self.assoc_refinements_of(impl_id)?;
341 if let Some(impl_assoc_reft) = impl_assoc_refts.find(trait_assoc_id.name()) {
342 return self.assoc_refinement_body(impl_assoc_reft.def_id());
343 }
344
345 if let Some(body) = self.default_assoc_refinement_body(trait_assoc_id)? {
347 let impl_trait_ref = self.impl_trait_ref(impl_id)?.instantiate_identity();
348 return Ok(rty::EarlyBinder(body.instantiate(self.tcx(), &impl_trait_ref.args, &[])));
349 }
350
351 Err(QueryErr::MissingAssocReft {
352 impl_id,
353 trait_id: trait_assoc_id.parent(),
354 name: trait_assoc_id.name(),
355 })
356 }
357
358 pub fn default_assoc_refinement_body(
359 self,
360 trait_assoc_id: FluxDefId,
361 ) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
362 self.inner
363 .queries
364 .default_assoc_refinement_body(self, trait_assoc_id)
365 }
366
367 pub fn assoc_refinement_body(
368 self,
369 impl_assoc_id: FluxDefId,
370 ) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
371 self.inner
372 .queries
373 .assoc_refinement_body(self, impl_assoc_id)
374 }
375
376 pub fn sort_of_assoc_reft(
377 self,
378 assoc_id: FluxDefId,
379 ) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
380 self.inner.queries.sort_of_assoc_reft(self, assoc_id)
381 }
382
383 pub fn item_bounds(self, def_id: DefId) -> QueryResult<rty::EarlyBinder<List<rty::Clause>>> {
384 self.inner.queries.item_bounds(self, def_id)
385 }
386
387 pub fn type_of(
388 self,
389 def_id: impl IntoQueryParam<DefId>,
390 ) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
391 self.inner.queries.type_of(self, def_id.into_query_param())
392 }
393
394 pub fn fn_sig(
395 self,
396 def_id: impl IntoQueryParam<DefId>,
397 ) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
398 self.inner.queries.fn_sig(self, def_id.into_query_param())
399 }
400
401 pub fn variants_of(
402 self,
403 def_id: impl IntoQueryParam<DefId>,
404 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
405 self.inner
406 .queries
407 .variants_of(self, def_id.into_query_param())
408 }
409
410 pub fn variant_sig(
411 self,
412 def_id: DefId,
413 variant_idx: VariantIdx,
414 ) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariant>>> {
415 Ok(self
416 .variants_of(def_id)?
417 .map(|variants| variants.map(|variants| variants[variant_idx.as_usize()].clone())))
418 }
419
420 pub fn lower_late_bound_vars(
421 self,
422 def_id: LocalDefId,
423 ) -> QueryResult<List<ty::BoundVariableKind>> {
424 self.inner.queries.lower_late_bound_vars(self, def_id)
425 }
426
427 pub fn no_panic(self, def_id: impl IntoQueryParam<DefId>) -> bool {
429 self.inner.queries.no_panic(self, def_id.into_query_param())
430 }
431
432 pub fn is_box(&self, res: fhir::Res) -> bool {
433 res.is_box(self.tcx())
434 }
435
436 pub fn def_id_to_param_index(&self, def_id: DefId) -> u32 {
437 let parent = self.tcx().parent(def_id);
438 let generics = self.tcx().generics_of(parent);
439 generics.param_def_id_to_index(self.tcx(), def_id).unwrap()
440 }
441
442 pub(crate) fn cstore(self) -> &'genv CrateStoreDyn {
443 &*self.inner.cstore
444 }
445
446 pub fn has_trusted_impl(&self, def_id: DefId) -> bool {
447 if let Some(did) = self
448 .resolve_id(def_id)
449 .as_maybe_extern()
450 .map(|id| id.local_id())
451 {
452 self.trusted_impl(did)
453 } else {
454 false
455 }
456 }
457
458 pub fn is_fn_output(&self, def_id: DefId) -> bool {
462 let def_span = self.tcx().def_span(def_id);
463 self.tcx()
464 .require_lang_item(LangItem::FnOnceOutput, def_span)
465 == def_id
466 }
467
468 pub fn is_fn_call(&self, def_id: DefId) -> bool {
470 let tcx = self.tcx();
471 let Some(assoc_item) = tcx.opt_associated_item(def_id) else { return false };
472 let Some(trait_id) = assoc_item.trait_container(tcx) else { return false };
473 assoc_item.name() == sym::call && tcx.is_lang_item(trait_id, LangItem::Fn)
474 }
475
476 pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + use<'tcx, 'genv> {
478 self.tcx().iter_local_def_id().filter(move |&local_def_id| {
479 self.maybe_extern_id(local_def_id).is_local() && !self.is_dummy(local_def_id)
480 })
481 }
482
483 pub fn iter_extern_def_id(self) -> impl Iterator<Item = DefId> + use<'tcx, 'genv> {
484 self.tcx()
485 .iter_local_def_id()
486 .filter_map(move |local_def_id| self.maybe_extern_id(local_def_id).as_extern())
487 }
488
489 pub fn maybe_extern_id(self, local_id: LocalDefId) -> MaybeExternId {
490 self.collect_specs()
491 .local_id_to_extern_id
492 .get(&local_id)
493 .map_or_else(
494 || MaybeExternId::Local(local_id),
495 |def_id| MaybeExternId::Extern(local_id, *def_id),
496 )
497 }
498
499 #[expect(clippy::disallowed_methods)]
500 pub fn resolve_id(self, def_id: DefId) -> ResolvedDefId {
501 let maybe_extern_spec = self
502 .collect_specs()
503 .extern_id_to_local_id
504 .get(&def_id)
505 .copied();
506 if let Some(local_id) = maybe_extern_spec {
507 ResolvedDefId::ExternSpec(local_id, def_id)
508 } else if let Some(local_id) = def_id.as_local() {
509 debug_assert!(
510 self.maybe_extern_id(local_id).is_local(),
511 "def id points to dummy local item `{def_id:?}`"
512 );
513 ResolvedDefId::Local(local_id)
514 } else {
515 ResolvedDefId::Extern(def_id)
516 }
517 }
518
519 pub fn infer_opts(self, def_id: LocalDefId) -> config::InferOpts {
520 let mut opts = config::PartialInferOpts::default();
521 self.traverse_parents(def_id, |did| {
522 if let Some(o) = self.fhir_attr_map(did).infer_opts() {
523 opts.merge(&o);
524 }
525 None::<!>
526 });
527 opts.into()
528 }
529
530 pub fn trusted(self, def_id: LocalDefId) -> bool {
534 self.traverse_parents(def_id, |did| self.fhir_attr_map(did).trusted())
535 .map(|trusted| trusted.to_bool())
536 .unwrap_or_else(config::trusted_default)
537 }
538
539 pub fn trusted_impl(self, def_id: LocalDefId) -> bool {
540 self.traverse_parents(def_id, |did| self.fhir_attr_map(did).trusted_impl())
541 .map(|trusted| trusted.to_bool())
542 .unwrap_or(false)
543 }
544
545 pub fn is_dummy(self, def_id: LocalDefId) -> bool {
549 self.traverse_parents(def_id, |did| {
550 self.collect_specs()
551 .dummy_extern
552 .contains(&did)
553 .then_some(())
554 })
555 .is_some()
556 }
557
558 pub fn ignored(self, def_id: LocalDefId) -> bool {
562 self.traverse_parents(def_id, |did| self.fhir_attr_map(did).ignored())
563 .map(|ignored| ignored.to_bool())
564 .unwrap_or_else(config::ignore_default)
565 }
566
567 pub fn should_fail(self, def_id: LocalDefId) -> bool {
569 self.fhir_attr_map(def_id).should_fail()
570 }
571
572 pub fn proven_externally(self, def_id: LocalDefId) -> Option<Span> {
574 self.fhir_attr_map(def_id).proven_externally()
575 }
576
577 fn traverse_parents<T>(
579 self,
580 mut def_id: LocalDefId,
581 mut f: impl FnMut(LocalDefId) -> Option<T>,
582 ) -> Option<T> {
583 loop {
584 if let Some(v) = f(def_id) {
585 break Some(v);
586 }
587
588 if let Some(parent) = self.tcx().opt_local_parent(def_id) {
589 def_id = parent;
590 } else {
591 break None;
592 }
593 }
594 }
595}
596
597impl<'genv, 'tcx> GlobalEnv<'genv, 'tcx> {
598 pub fn fhir_iter_flux_items(
599 self,
600 ) -> impl Iterator<Item = (FluxLocalDefId, fhir::FluxItem<'genv>)> {
601 self.fhir_crate()
602 .items
603 .iter()
604 .map(|(id, item)| (*id, *item))
605 }
606
607 pub fn fhir_sort_decl(&self, def_id: FluxLocalDefId) -> Option<&fhir::SortDecl> {
608 self.fhir_crate().items.get(&def_id).and_then(|item| {
609 if let fhir::FluxItem::SortDecl(sort_decl) = item { Some(*sort_decl) } else { None }
610 })
611 }
612
613 pub fn fhir_spec_func_body(
614 &self,
615 def_id: FluxLocalDefId,
616 ) -> Option<&'genv fhir::SpecFunc<'genv>> {
617 self.fhir_crate()
618 .items
619 .get(&def_id)
620 .and_then(|item| if let fhir::FluxItem::Func(defn) = item { Some(*defn) } else { None })
621 }
622
623 pub fn fhir_qualifiers(self) -> impl Iterator<Item = &'genv fhir::Qualifier<'genv>> {
624 self.fhir_crate().items.values().filter_map(|item| {
625 if let fhir::FluxItem::Qualifier(qual) = item { Some(*qual) } else { None }
626 })
627 }
628
629 pub fn fhir_primop_props(self) -> impl Iterator<Item = &'genv fhir::PrimOpProp<'genv>> {
630 self.fhir_crate().items.values().filter_map(|item| {
631 if let fhir::FluxItem::PrimOpProp(prop) = item { Some(*prop) } else { None }
632 })
633 }
634
635 pub fn fhir_get_generics(
636 self,
637 def_id: LocalDefId,
638 ) -> QueryResult<Option<&'genv fhir::Generics<'genv>>> {
639 if matches!(self.def_kind(def_id), DefKind::Closure) {
641 Ok(None)
642 } else {
643 Ok(Some(self.fhir_expect_owner_node(def_id)?.generics()))
644 }
645 }
646
647 pub fn fhir_expect_refinement_kind(
648 self,
649 def_id: LocalDefId,
650 ) -> QueryResult<&'genv fhir::RefinementKind<'genv>> {
651 let kind = match &self.fhir_expect_item(def_id)?.kind {
652 fhir::ItemKind::Enum(enum_def) => &enum_def.refinement,
653 fhir::ItemKind::Struct(struct_def) => &struct_def.refinement,
654 _ => bug!("expected struct, enum or type alias"),
655 };
656 Ok(kind)
657 }
658
659 pub fn fhir_expect_item(self, def_id: LocalDefId) -> QueryResult<&'genv fhir::Item<'genv>> {
660 if let fhir::Node::Item(item) = self.fhir_node(def_id)? {
661 Ok(item)
662 } else {
663 Err(query_bug!(def_id, "expected item: `{def_id:?}`"))
664 }
665 }
666
667 pub fn fhir_expect_owner_node(self, def_id: LocalDefId) -> QueryResult<fhir::OwnerNode<'genv>> {
668 let Some(owner) = self.fhir_node(def_id)?.as_owner() else {
669 return Err(query_bug!(def_id, "cannot find owner node"));
670 };
671 Ok(owner)
672 }
673
674 pub fn fhir_node(self, def_id: LocalDefId) -> QueryResult<fhir::Node<'genv>> {
675 self.desugar(def_id)
676 }
677}
678
679#[macro_export]
680macro_rules! try_alloc_slice {
681 ($genv:expr, $slice:expr, $map:expr $(,)?) => {{
682 let slice = $slice;
683 $crate::try_alloc_slice!($genv, cap: slice.len(), slice.into_iter().map($map))
684 }};
685 ($genv:expr, cap: $cap:expr, $it:expr $(,)?) => {{
686 let mut err = None;
687 let slice = $genv.alloc_slice_with_capacity($cap, $it.into_iter().collect_errors(&mut err));
688 err.map_or(Ok(slice), Err)
689 }};
690}
691
692impl ErrorEmitter for GlobalEnv<'_, '_> {
693 fn emit<'a>(&'a self, err: impl rustc_errors::Diagnostic<'a>) -> rustc_span::ErrorGuaranteed {
694 self.sess().emit(err)
695 }
696}
697
698fn lean_parent_dir(tcx: TyCtxt) -> PathBuf {
699 tcx.sess
700 .opts
701 .working_dir
702 .local_path_if_available()
703 .to_path_buf()
704 .join(config::lean_dir())
705}