1use std::collections::{HashMap, HashSet};
2use std::fmt::Debug;
3use std::mem;
4
5use crate::hax;
6use crate::hax::{BaseState, Symbol};
7use rustc_middle::ty;
8
9use super::translate_ctx::{ItemTransCtx, TransImplSource, TransItemSourceKind};
10use charon_lib::ast::*;
11use charon_lib::ids::IndexVec;
12use charon_lib::utils::CycleDetector;
13
14#[derive(Debug, Default)]
26pub(crate) struct BindingLevel {
27 pub params: GenericParams,
29 pub early_region_vars: HashMap<hax::EarlyParamRegion, RegionId>,
36 pub region_vars_by_def_id: HashMap<hax::DefId, RegionId>,
38 pub bound_region_vars: Vec<RegionId>,
40 pub closure_call_method_region: Option<RegionId>,
42 pub drop_glue_region: Option<RegionId>,
44 pub type_vars_map: HashMap<u32, TypeVarId>,
46 pub const_generic_vars_map: HashMap<u32, ConstGenericVarId>,
48 pub trait_preds: HashMap<hax::GenericPredicateId, TraitClauseId>,
50 pub closure_upvar_tys: Option<IndexVec<FieldId, Ty>>,
54 pub closure_upvar_regions: Vec<RegionId>,
56 pub used_region_names: HashSet<Symbol>,
59 pub type_trans_cache: HashMap<hax::Ty, Ty>,
63}
64
65fn translate_region_name(s: hax::Symbol) -> Option<String> {
67 let s = s.to_string();
68 if s == "'_" { None } else { Some(s) }
69}
70
71fn translate_variance(variance: Option<&hax::Variance>) -> Variance {
72 match variance {
73 Some(hax::Variance::Covariant) => Variance::Covariant,
74 Some(hax::Variance::Invariant) => Variance::Invariant,
75 Some(hax::Variance::Contravariant) => Variance::Contravariant,
76 Some(hax::Variance::Bivariant) => Variance::Bivariant,
77 None => Variance::Unknown,
78 }
79}
80
81impl BindingLevel {
82 pub(crate) fn new() -> Self {
83 Self {
84 ..Default::default()
85 }
86 }
87
88 pub(crate) fn push_early_region(
90 &mut self,
91 region: hax::EarlyParamRegion,
92 def_id: hax::DefId,
93 variance: Variance,
94 mutability: LifetimeMutability,
95 ) -> RegionId {
96 let name = if self.used_region_names.insert(region.name) {
97 translate_region_name(region.name)
98 } else {
99 None
100 };
101 assert!(
103 self.bound_region_vars.is_empty(),
104 "Early regions must be translated before late ones"
105 );
106 let rid = self.params.regions.push_with(|index| RegionParam {
107 index,
108 name,
109 variance,
110 mutability,
111 });
112 self.early_region_vars.insert(region, rid);
113 self.region_vars_by_def_id.insert(def_id, rid);
114 rid
115 }
116
117 pub(crate) fn push_bound_region(
119 &mut self,
120 region: hax::BoundRegionKind,
121 variance: Variance,
122 ) -> RegionId {
123 use crate::hax::BoundRegionKind::*;
124 let (name, def_id) = match region {
125 Anon => (None, None),
126 NamedForPrinting(symbol) => (translate_region_name(symbol), None),
127 Named(def_id, symbol) => (translate_region_name(symbol), Some(def_id)),
128 ClosureEnv => (Some("@env".to_owned()), None),
129 };
130 let rid = self
131 .params
132 .regions
133 .push_with(|index| RegionParam::new(index, name, variance));
134 self.bound_region_vars.push(rid);
135 if let Some(def_id) = def_id {
136 self.region_vars_by_def_id.insert(def_id, rid);
137 }
138 rid
139 }
140
141 pub fn push_upvar_region(&mut self) -> RegionId {
143 let region_id = self
146 .params
147 .regions
148 .push_with(|index| RegionParam::new(index, None, Variance::Unknown));
149 self.closure_upvar_regions.push(region_id);
150 region_id
151 }
152
153 pub fn push_drop_glue_region(&mut self) -> RegionId {
154 let region_id = self
155 .params
156 .regions
157 .push_with(|index| RegionParam::new(index, None, Variance::Covariant));
158 self.drop_glue_region = Some(region_id);
159 region_id
160 }
161
162 pub(crate) fn push_type_var(
163 &mut self,
164 rid: u32,
165 name: hax::Symbol,
166 variance: Variance,
167 ) -> TypeVarId {
168 let mut name = name.to_string();
171 if name
172 .chars()
173 .any(|c| !(c.is_ascii_alphanumeric() || c == '_'))
174 {
175 name = format!("T{rid}")
176 }
177 let var_id = self.params.types.push_with(|index| TypeParam {
178 index,
179 name,
180 variance,
181 });
182 self.type_vars_map.insert(rid, var_id);
183 var_id
184 }
185
186 pub(crate) fn push_const_generic_var(&mut self, rid: u32, ty: Ty, name: hax::Symbol) {
187 let var_id = self
188 .params
189 .const_generics
190 .push_with(|index| ConstGenericParam {
191 index,
192 name: name.to_string(),
193 ty,
194 });
195 self.const_generic_vars_map.insert(rid, var_id);
196 }
197
198 pub(crate) fn push_params_from_binder(&mut self, binder: hax::Binder<()>) -> Result<(), Error> {
200 assert!(
201 self.bound_region_vars.is_empty(),
202 "Trying to use two binders at the same binding level"
203 );
204 use crate::hax::BoundVariableKind::*;
205 for p in binder.bound_vars {
206 match p {
207 Region(region, variance) => {
208 let variance = translate_variance(variance.as_ref());
209 self.push_bound_region(region, variance);
210 }
211 Ty(_) => {
212 panic!("Unexpected locally bound type variable");
213 }
214 Const => {
215 panic!("Unexpected locally bound const generic variable");
216 }
217 }
218 }
219 Ok(())
220 }
221}
222
223impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
224 pub(crate) fn the_only_binder(&self) -> &BindingLevel {
226 assert_eq!(self.binding_levels.len(), 1);
227 self.innermost_binder()
228 }
229 pub(crate) fn the_only_binder_mut(&mut self) -> &mut BindingLevel {
231 assert_eq!(self.binding_levels.len(), 1);
232 self.innermost_binder_mut()
233 }
234
235 pub(crate) fn outermost_binder(&self) -> &BindingLevel {
236 self.binding_levels.outermost()
237 }
238 pub(crate) fn outermost_binder_mut(&mut self) -> &mut BindingLevel {
239 self.binding_levels.outermost_mut()
240 }
241 pub(crate) fn innermost_binder(&self) -> &BindingLevel {
242 self.binding_levels.innermost()
243 }
244 pub(crate) fn innermost_binder_mut(&mut self) -> &mut BindingLevel {
245 self.binding_levels.innermost_mut()
246 }
247
248 pub(crate) fn outermost_generics(&self) -> &GenericParams {
249 &self.outermost_binder().params
250 }
251 #[expect(dead_code)]
252 pub(crate) fn outermost_generics_mut(&mut self) -> &mut GenericParams {
253 &mut self.outermost_binder_mut().params
254 }
255 #[expect(dead_code)]
256 pub(crate) fn innermost_generics(&self) -> &GenericParams {
257 &self.innermost_binder().params
258 }
259 pub(crate) fn innermost_generics_mut(&mut self) -> &mut GenericParams {
260 &mut self.innermost_binder_mut().params
261 }
262
263 pub(crate) fn lookup_bound_region(
264 &mut self,
265 span: Span,
266 dbid: hax::DebruijnIndex,
267 var: hax::BoundVar,
268 ) -> Result<RegionDbVar, Error> {
269 let dbid = DeBruijnId::new(dbid);
270 if let Some(rid) = self
271 .binding_levels
272 .get(dbid)
273 .and_then(|bl| bl.bound_region_vars.get(var))
274 {
275 Ok(DeBruijnVar::bound(dbid, *rid))
276 } else {
277 raise_error!(
278 self,
279 span,
280 "Unexpected error: could not find region '{dbid}_{var}"
281 )
282 }
283 }
284
285 pub(crate) fn lookup_param<Id: Copy>(
286 &mut self,
287 span: Span,
288 f: impl for<'a> Fn(&'a BindingLevel) -> Option<Id>,
289 mk_err: impl FnOnce() -> String,
290 ) -> Result<DeBruijnVar<Id>, Error> {
291 for (dbid, bl) in self.binding_levels.iter_enumerated() {
292 if let Some(id) = f(bl) {
293 return Ok(DeBruijnVar::bound(dbid, id));
294 }
295 }
296 let err = mk_err();
297 raise_error!(self, span, "Unexpected error: could not find {}", err)
298 }
299
300 pub(crate) fn lookup_early_region(
301 &mut self,
302 span: Span,
303 region: &hax::EarlyParamRegion,
304 ) -> Result<RegionDbVar, Error> {
305 self.lookup_param(
306 span,
307 |bl| bl.early_region_vars.get(region).copied(),
308 || format!("the region variable {region:?}"),
309 )
310 }
311
312 pub(crate) fn lookup_late_param_region(
313 &mut self,
314 span: Span,
315 region: &hax::LateParamRegion,
316 ) -> Result<RegionDbVar, Error> {
317 let hax::LateParamRegionKind::Named(def_id, _) = ®ion.kind else {
318 raise_error!(self, span, "Unexpected late-bound region: {region:?}")
319 };
320 self.lookup_param(
321 span,
322 |bl| bl.region_vars_by_def_id.get(def_id).copied(),
323 || format!("the late-bound region variable {region:?}"),
324 )
325 }
326
327 pub(crate) fn lookup_type_var(
328 &mut self,
329 span: Span,
330 param: &hax::ParamTy,
331 ) -> Result<TypeDbVar, Error> {
332 self.lookup_param(
333 span,
334 |bl| bl.type_vars_map.get(¶m.index).copied(),
335 || format!("the type variable {}", param.name),
336 )
337 }
338
339 pub(crate) fn lookup_const_generic_var(
340 &mut self,
341 span: Span,
342 param: &hax::ParamConst,
343 ) -> Result<ConstGenericDbVar, Error> {
344 self.lookup_param(
345 span,
346 |bl| bl.const_generic_vars_map.get(¶m.index).copied(),
347 || format!("the const generic variable {}", param.name),
348 )
349 }
350
351 pub(crate) fn lookup_clause_var(
352 &mut self,
353 span: Span,
354 id: &hax::GenericPredicateId,
355 ) -> Result<ClauseDbVar, Error> {
356 self.lookup_param(
357 span,
358 |bl| bl.trait_preds.get(id).copied(),
359 || format!("the trait clause variable {id:?}"),
360 )
361 }
362
363 pub(crate) fn push_generic_params(&mut self, generics: &hax::TyGenerics) -> Result<(), Error> {
364 for param in &generics.params {
365 self.push_generic_param(param)?;
366 }
367 Ok(())
368 }
369
370 pub(crate) fn push_generic_param(&mut self, param: &hax::GenericParamDef) -> Result<(), Error> {
371 let variance = translate_variance(param.variance.as_ref());
372 match ¶m.kind {
373 hax::GenericParamDefKind::Lifetime => {
374 let region = hax::EarlyParamRegion {
375 index: param.index,
376 name: param.name,
377 };
378 let mutability = self
379 .t_ctx
380 .lt_mutability_computer
381 .compute_lifetime_mutability(
382 &self.hax_state,
383 self.item_src.def_id(),
384 param.index,
385 );
386 let _ = self.innermost_binder_mut().push_early_region(
387 region,
388 param.def_id.clone(),
389 variance,
390 mutability,
391 );
392 }
393 hax::GenericParamDefKind::Type { .. } => {
394 let _ =
395 self.innermost_binder_mut()
396 .push_type_var(param.index, param.name, variance);
397 }
398 hax::GenericParamDefKind::Const { ty, .. } => {
399 let span = self.def_span(¶m.def_id);
400 let ty = self.translate_ty(span, ty)?;
403 self.innermost_binder_mut()
404 .push_const_generic_var(param.index, ty, param.name);
405 }
406 }
407
408 Ok(())
409 }
410
411 fn push_late_bound_generics_for_def(
420 &mut self,
421 _span: Span,
422 def: &hax::FullDef<'tcx>,
423 ) -> Result<(), Error> {
424 if let hax::FullDefKind::Fn { sig, .. } | hax::FullDefKind::AssocFn { sig, .. } = def.kind()
425 {
426 let innermost_binder = self.innermost_binder_mut();
427 assert!(innermost_binder.bound_region_vars.is_empty());
428 innermost_binder.push_params_from_binder(sig.rebind(()))?;
429 }
430 Ok(())
431 }
432
433 #[tracing::instrument(skip(self, span, def))]
435 fn push_generics_for_def(&mut self, span: Span, def: &hax::FullDef<'tcx>) -> Result<(), Error> {
436 trace!("{:?}", def.param_env());
437 if let Some(parent_item) = def.typing_parent(self.hax_state()) {
440 let parent_def = self.hax_def(&parent_item)?;
441 self.push_generics_for_def(span, &parent_def)?;
442 }
443 self.push_generics_for_def_without_parents(span, def)?;
444 Ok(())
445 }
446
447 fn push_generics_for_def_without_parents(
450 &mut self,
451 _span: Span,
452 def: &hax::FullDef<'tcx>,
453 ) -> Result<(), Error> {
454 if let Some(param_env) = def.param_env() {
455 let origin = Self::predicate_origin_for_def(def);
456 self.push_param_env_without_parents(param_env, origin)?;
457 }
458
459 Ok(())
460 }
461
462 fn predicate_origin_for_def(def: &hax::FullDef<'tcx>) -> PredicateOrigin {
463 use crate::hax::FullDefKind;
464 match &def.kind {
465 FullDefKind::Adt { .. } | FullDefKind::TyAlias { .. } | FullDefKind::AssocTy { .. } => {
466 PredicateOrigin::WhereClauseOnType
467 }
468 FullDefKind::Fn { .. }
469 | FullDefKind::AssocFn { .. }
470 | FullDefKind::Closure { .. }
471 | FullDefKind::Const { .. }
472 | FullDefKind::AssocConst { .. }
473 | FullDefKind::Static { .. } => PredicateOrigin::WhereClauseOnFn,
474 FullDefKind::TraitImpl { .. } | FullDefKind::InherentImpl { .. } => {
475 PredicateOrigin::WhereClauseOnImpl
476 }
477 FullDefKind::Trait { .. } | FullDefKind::TraitAlias { .. } => {
478 PredicateOrigin::WhereClauseOnTrait
479 }
480 _ => panic!("Unexpected def: {:?}", def.def_id().kind),
481 }
482 }
483
484 fn push_param_env_without_parents(
485 &mut self,
486 param_env: &hax::ParamEnv,
487 origin: PredicateOrigin,
488 ) -> Result<(), Error> {
489 self.push_generic_params(¶m_env.generics)?;
490 self.register_predicates(¶m_env.predicates, origin)?;
491 Ok(())
492 }
493
494 pub fn translate_item_generics(
502 &mut self,
503 span: Span,
504 def: &hax::FullDef<'tcx>,
505 kind: &TransItemSourceKind,
506 ) -> Result<(), Error> {
507 assert!(self.binding_levels.is_empty());
508 self.binding_levels.push(BindingLevel::new());
509 self.push_generics_for_def(span, def)?;
510 self.push_late_bound_generics_for_def(span, def)?;
511
512 if let hax::FullDefKind::Closure { args, .. } = def.kind() {
513 let upvar_tys = self.translate_closure_upvar_tys(span, args)?;
516 let upvar_tys = upvar_tys.replace_erased_regions(|| {
518 let region_id = self.the_only_binder_mut().push_upvar_region();
519 Region::Var(DeBruijnVar::new_at_zero(region_id))
520 });
521 self.the_only_binder_mut().closure_upvar_tys = Some(upvar_tys);
522
523 if let TransItemSourceKind::TraitImpl(TransImplSource::Callable(..))
525 | TransItemSourceKind::CallableMethod(..)
526 | TransItemSourceKind::ClosureAsFnCast = kind
527 {
528 self.the_only_binder_mut()
529 .push_params_from_binder(args.fn_sig.rebind(()))?;
530 }
531 }
532
533 if let hax::FullDefKind::Fn { .. }
534 | hax::FullDefKind::AssocFn { .. }
535 | hax::FullDefKind::Closure { .. } = def.kind()
536 && let TransItemSourceKind::CallableMethod(ClosureKind::Fn | ClosureKind::FnMut) = kind
537 {
538 let rid = self
540 .the_only_binder_mut()
541 .params
542 .regions
543 .push_with(|index| RegionParam::new(index, None, Variance::Covariant));
544 self.the_only_binder_mut().closure_call_method_region = Some(rid);
545 }
546
547 if matches!(
548 kind,
549 TransItemSourceKind::DropGlueMethod(..) | TransItemSourceKind::VTableDropShim
550 ) {
551 self.the_only_binder_mut().push_drop_glue_region();
552 }
553
554 self.innermost_binder_mut().params.check_consistency();
555 Ok(())
556 }
557
558 pub(crate) fn inside_binder<F, U>(&mut self, kind: BinderKind, f: F) -> Result<Binder<U>, Error>
560 where
561 F: FnOnce(&mut Self) -> Result<U, Error>,
562 {
563 self.binding_levels.push(BindingLevel::new());
564
565 let res = f(self);
567
568 let params = self.binding_levels.pop().unwrap().params;
570
571 res.map(|skip_binder| Binder {
573 kind,
574 params,
575 skip_binder,
576 })
577 }
578
579 pub(crate) fn translate_binder_for_def<F, U>(
582 &mut self,
583 span: Span,
584 kind: BinderKind,
585 def: &hax::FullDef<'tcx>,
586 f: F,
587 ) -> Result<Binder<U>, Error>
588 where
589 F: FnOnce(&mut Self) -> Result<U, Error>,
590 {
591 let inner_hax_state = self.t_ctx.hax_state.clone().with_hax_owner(def.def_id());
592 let outer_hax_state = mem::replace(&mut self.hax_state, inner_hax_state);
593 let ret = self.inside_binder(kind, |this| {
594 this.push_generics_for_def_without_parents(span, def)?;
595 this.push_late_bound_generics_for_def(span, def)?;
596 this.innermost_binder().params.check_consistency();
597 f(this)
598 });
599 self.hax_state = outer_hax_state;
600 ret
601 }
602
603 pub(crate) fn translate_item_binder<F, T, U>(
606 &mut self,
607 _span: Span,
608 kind: BinderKind,
609 binder: &hax::TraitItemBinder<T>,
610 predicate_origin: PredicateOrigin,
611 f: F,
612 ) -> Result<Binder<U>, Error>
613 where
614 F: FnOnce(&mut Self, &T) -> Result<U, Error>,
615 {
616 let inner_hax_state = self.t_ctx.hax_state.clone().with_hax_owner(&binder.def_id);
617 let outer_hax_state = mem::replace(&mut self.hax_state, inner_hax_state);
618 let ret = self.inside_binder(kind, |this| {
619 this.push_param_env_without_parents(&binder.param_env, predicate_origin)?;
620 this.innermost_binder_mut()
621 .push_params_from_binder(binder.late_bound.clone())?;
622 this.innermost_binder().params.check_consistency();
623 f(this, &binder.skip_binder)
624 });
625 self.hax_state = outer_hax_state;
626 ret
627 }
628
629 pub(crate) fn translate_region_binder<F, T, U>(
633 &mut self,
634 _span: Span,
635 binder: &hax::Binder<T>,
636 f: F,
637 ) -> Result<RegionBinder<U>, Error>
638 where
639 F: FnOnce(&mut Self, &T) -> Result<U, Error>,
640 {
641 let binder = self.inside_binder(BinderKind::Other, |this| {
642 this.innermost_binder_mut()
643 .push_params_from_binder(binder.rebind(()))?;
644 f(this, binder.hax_skip_binder_ref())
645 })?;
646 Ok(RegionBinder {
648 regions: binder.params.regions,
649 skip_binder: binder.skip_binder,
650 })
651 }
652
653 pub(crate) fn into_generics(mut self) -> GenericParams {
654 assert!(self.binding_levels.len() == 1);
655 self.binding_levels.pop().unwrap().params
656 }
657}
658
659#[derive(Default)]
661pub struct LifetimeMutabilityComputer {
662 lt_mutability: HashMap<hax::DefId, CycleDetector<HashSet<u32>>>,
663}
664
665impl LifetimeMutabilityComputer {
666 pub(crate) fn compute_lifetime_mutability<'tcx>(
668 &mut self,
669 s: &impl BaseState<'tcx>,
670 item: &hax::DefId,
671 index: u32,
672 ) -> LifetimeMutability {
673 match self.compute_lifetime_mutabilities(s, item) {
674 Some(set) => {
675 if set.contains(&index) {
676 LifetimeMutability::Mutable
677 } else {
678 LifetimeMutability::Shared
679 }
680 }
681 None => LifetimeMutability::Unknown,
682 }
683 }
684
685 fn compute_lifetime_mutabilities<'tcx>(
688 &mut self,
689 s: &impl BaseState<'tcx>,
690 item: &hax::DefId,
691 ) -> Option<&HashSet<u32>> {
692 if !matches!(
693 item.kind,
694 hax::DefKind::Struct | hax::DefKind::Enum | hax::DefKind::Union
695 ) {
696 return None;
697 }
698 if self
699 .lt_mutability
700 .entry(item.clone())
701 .or_default()
702 .start_processing()
703 {
704 use crate::hax::SInto;
705 use ty::{TypeSuperVisitable, TypeVisitable};
706
707 struct LtMutabilityVisitor<'a, S> {
708 s: &'a S,
709 computer: &'a mut LifetimeMutabilityComputer,
710 set: HashSet<u32>,
711 }
712 impl<'tcx, S: BaseState<'tcx>> ty::TypeVisitor<ty::TyCtxt<'tcx>> for LtMutabilityVisitor<'_, S> {
713 fn visit_ty(&mut self, ty: ty::Ty<'tcx>) {
714 match ty.kind() {
715 ty::Ref(r, _, ty::Mutability::Mut)
716 if let ty::RegionKind::ReEarlyParam(r) = r.kind() =>
717 {
718 self.set.insert(r.index);
719 }
720 ty::Adt(adt, args) => {
721 let item = adt.did().sinto(self.s);
722 if let Some(mutabilities) =
723 self.computer.compute_lifetime_mutabilities(self.s, &item)
724 {
725 for arg in args.iter() {
726 if let Some(r) = arg.as_region()
727 && let ty::RegionKind::ReEarlyParam(r) = r.kind()
728 && mutabilities.contains(&r.index)
729 {
730 self.set.insert(r.index);
731 }
732 }
733 }
734 }
735 _ => {}
736 }
737 ty.super_visit_with(self)
738 }
739 }
740 let mut visitor = LtMutabilityVisitor {
741 s,
742 computer: self,
743 set: HashSet::new(),
744 };
745
746 let tcx = s.base().tcx;
747 let def_id = item.real_rust_def_id();
748 let adt_def = tcx.adt_def(def_id);
749 let generics = item.identity_args(s);
750 for variant in adt_def.variants() {
751 for field in &variant.fields {
752 field.ty(tcx, generics).visit_with(&mut visitor);
753 }
754 }
755 let set = visitor.set;
756
757 self.lt_mutability
758 .get_mut(item)
759 .unwrap()
760 .done_processing(set);
761 }
762 self.lt_mutability.get(item)?.as_processed()
763 }
764}