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, TraitImplSource, TransItemSourceKind};
10use charon_lib::ast::*;
11use charon_lib::common::CycleDetector;
12use charon_lib::ids::IndexVec;
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(TraitImplSource::Closure(..))
525 | TransItemSourceKind::ClosureMethod(..)
526 | TransItemSourceKind::ClosureAsFnCast = kind
527 {
528 self.the_only_binder_mut()
529 .push_params_from_binder(args.fn_sig.rebind(()))?;
530 }
531 if let TransItemSourceKind::ClosureMethod(ClosureKind::Fn | ClosureKind::FnMut) = kind {
532 let rid = self
534 .the_only_binder_mut()
535 .params
536 .regions
537 .push_with(|index| RegionParam::new(index, None, Variance::Covariant));
538 self.the_only_binder_mut().closure_call_method_region = Some(rid);
539 }
540 }
541
542 if matches!(
543 kind,
544 TransItemSourceKind::DropGlueMethod(..) | TransItemSourceKind::VTableDropShim
545 ) {
546 self.the_only_binder_mut().push_drop_glue_region();
547 }
548
549 self.innermost_binder_mut().params.check_consistency();
550 Ok(())
551 }
552
553 pub(crate) fn inside_binder<F, U>(&mut self, kind: BinderKind, f: F) -> Result<Binder<U>, Error>
555 where
556 F: FnOnce(&mut Self) -> Result<U, Error>,
557 {
558 self.binding_levels.push(BindingLevel::new());
559
560 let res = f(self);
562
563 let params = self.binding_levels.pop().unwrap().params;
565
566 res.map(|skip_binder| Binder {
568 kind,
569 params,
570 skip_binder,
571 })
572 }
573
574 pub(crate) fn translate_binder_for_def<F, U>(
577 &mut self,
578 span: Span,
579 kind: BinderKind,
580 def: &hax::FullDef<'tcx>,
581 f: F,
582 ) -> Result<Binder<U>, Error>
583 where
584 F: FnOnce(&mut Self) -> Result<U, Error>,
585 {
586 let inner_hax_state = self.t_ctx.hax_state.clone().with_hax_owner(def.def_id());
587 let outer_hax_state = mem::replace(&mut self.hax_state, inner_hax_state);
588 let ret = self.inside_binder(kind, |this| {
589 this.push_generics_for_def_without_parents(span, def)?;
590 this.push_late_bound_generics_for_def(span, def)?;
591 this.innermost_binder().params.check_consistency();
592 f(this)
593 });
594 self.hax_state = outer_hax_state;
595 ret
596 }
597
598 pub(crate) fn translate_item_binder<F, T, U>(
601 &mut self,
602 _span: Span,
603 kind: BinderKind,
604 binder: &hax::TraitItemBinder<T>,
605 predicate_origin: PredicateOrigin,
606 f: F,
607 ) -> Result<Binder<U>, Error>
608 where
609 F: FnOnce(&mut Self, &T) -> Result<U, Error>,
610 {
611 let inner_hax_state = self.t_ctx.hax_state.clone().with_hax_owner(&binder.def_id);
612 let outer_hax_state = mem::replace(&mut self.hax_state, inner_hax_state);
613 let ret = self.inside_binder(kind, |this| {
614 this.push_param_env_without_parents(&binder.param_env, predicate_origin)?;
615 this.innermost_binder_mut()
616 .push_params_from_binder(binder.late_bound.clone())?;
617 this.innermost_binder().params.check_consistency();
618 f(this, &binder.skip_binder)
619 });
620 self.hax_state = outer_hax_state;
621 ret
622 }
623
624 pub(crate) fn translate_region_binder<F, T, U>(
628 &mut self,
629 _span: Span,
630 binder: &hax::Binder<T>,
631 f: F,
632 ) -> Result<RegionBinder<U>, Error>
633 where
634 F: FnOnce(&mut Self, &T) -> Result<U, Error>,
635 {
636 let binder = self.inside_binder(BinderKind::Other, |this| {
637 this.innermost_binder_mut()
638 .push_params_from_binder(binder.rebind(()))?;
639 f(this, binder.hax_skip_binder_ref())
640 })?;
641 Ok(RegionBinder {
643 regions: binder.params.regions,
644 skip_binder: binder.skip_binder,
645 })
646 }
647
648 pub(crate) fn into_generics(mut self) -> GenericParams {
649 assert!(self.binding_levels.len() == 1);
650 self.binding_levels.pop().unwrap().params
651 }
652}
653
654#[derive(Default)]
656pub struct LifetimeMutabilityComputer {
657 lt_mutability: HashMap<hax::DefId, CycleDetector<HashSet<u32>>>,
658}
659
660impl LifetimeMutabilityComputer {
661 pub(crate) fn compute_lifetime_mutability<'tcx>(
663 &mut self,
664 s: &impl BaseState<'tcx>,
665 item: &hax::DefId,
666 index: u32,
667 ) -> LifetimeMutability {
668 match self.compute_lifetime_mutabilities(s, item) {
669 Some(set) => {
670 if set.contains(&index) {
671 LifetimeMutability::Mutable
672 } else {
673 LifetimeMutability::Shared
674 }
675 }
676 None => LifetimeMutability::Unknown,
677 }
678 }
679
680 fn compute_lifetime_mutabilities<'tcx>(
683 &mut self,
684 s: &impl BaseState<'tcx>,
685 item: &hax::DefId,
686 ) -> Option<&HashSet<u32>> {
687 if !matches!(
688 item.kind,
689 hax::DefKind::Struct | hax::DefKind::Enum | hax::DefKind::Union
690 ) {
691 return None;
692 }
693 if self
694 .lt_mutability
695 .entry(item.clone())
696 .or_default()
697 .start_processing()
698 {
699 use crate::hax::SInto;
700 use ty::{TypeSuperVisitable, TypeVisitable};
701
702 struct LtMutabilityVisitor<'a, S> {
703 s: &'a S,
704 computer: &'a mut LifetimeMutabilityComputer,
705 set: HashSet<u32>,
706 }
707 impl<'tcx, S: BaseState<'tcx>> ty::TypeVisitor<ty::TyCtxt<'tcx>> for LtMutabilityVisitor<'_, S> {
708 fn visit_ty(&mut self, ty: ty::Ty<'tcx>) {
709 match ty.kind() {
710 ty::Ref(r, _, ty::Mutability::Mut)
711 if let ty::RegionKind::ReEarlyParam(r) = r.kind() =>
712 {
713 self.set.insert(r.index);
714 }
715 ty::Adt(adt, args) => {
716 let item = adt.did().sinto(self.s);
717 if let Some(mutabilities) =
718 self.computer.compute_lifetime_mutabilities(self.s, &item)
719 {
720 for arg in args.iter() {
721 if let Some(r) = arg.as_region()
722 && let ty::RegionKind::ReEarlyParam(r) = r.kind()
723 && mutabilities.contains(&r.index)
724 {
725 self.set.insert(r.index);
726 }
727 }
728 }
729 }
730 _ => {}
731 }
732 ty.super_visit_with(self)
733 }
734 }
735 let mut visitor = LtMutabilityVisitor {
736 s,
737 computer: self,
738 set: HashSet::new(),
739 };
740
741 let tcx = s.base().tcx;
742 let def_id = item.real_rust_def_id();
743 let adt_def = tcx.adt_def(def_id);
744 let generics = item.identity_args(s);
745 for variant in adt_def.variants() {
746 for field in &variant.fields {
747 field.ty(tcx, generics).visit_with(&mut visitor);
748 }
749 }
750 let set = visitor.set;
751
752 self.lt_mutability
753 .get_mut(item)
754 .unwrap()
755 .done_processing(set);
756 }
757 self.lt_mutability.get(item)?.as_processed()
758 }
759}