1use crate::translate::translate_ctx::TraitImplSource;
2
3use super::translate_ctx::{ItemTransCtx, TransItemSourceKind};
4use charon_lib::ast::*;
5use charon_lib::ids::IndexVec;
6use std::collections::HashMap;
7use std::fmt::Debug;
8
9#[derive(Debug, Default)]
21pub(crate) struct BindingLevel {
22 pub params: GenericParams,
24 pub is_item_binder: bool,
28 pub early_region_vars: HashMap<hax::EarlyParamRegion, RegionId>,
35 pub bound_region_vars: Vec<RegionId>,
37 pub closure_call_method_region: Option<RegionId>,
39 pub type_vars_map: HashMap<u32, TypeVarId>,
41 pub const_generic_vars_map: HashMap<u32, ConstGenericVarId>,
43 pub closure_upvar_tys: Option<IndexVec<FieldId, Ty>>,
47 pub closure_upvar_regions: Vec<RegionId>,
49 pub type_trans_cache: HashMap<hax::Ty, Ty>,
53}
54
55fn translate_region_name(s: hax::Symbol) -> Option<String> {
57 let s = s.to_string();
58 if s == "'_" { None } else { Some(s) }
59}
60
61impl BindingLevel {
62 pub(crate) fn new(is_item_binder: bool) -> Self {
63 Self {
64 is_item_binder,
65 ..Default::default()
66 }
67 }
68
69 pub(crate) fn push_early_region(&mut self, region: hax::EarlyParamRegion) -> RegionId {
71 let name = translate_region_name(region.name);
72 assert!(
74 self.bound_region_vars.is_empty(),
75 "Early regions must be translated before late ones"
76 );
77 let rid = self
78 .params
79 .regions
80 .push_with(|index| RegionParam { index, name });
81 self.early_region_vars.insert(region, rid);
82 rid
83 }
84
85 pub(crate) fn push_bound_region(&mut self, region: hax::BoundRegionKind) -> RegionId {
87 use hax::BoundRegionKind::*;
88 let name = match region {
89 Anon => None,
90 NamedAnon(symbol) | Named(_, symbol) => translate_region_name(symbol),
91 ClosureEnv => Some("@env".to_owned()),
92 };
93 let rid = self
94 .params
95 .regions
96 .push_with(|index| RegionParam { index, name });
97 self.bound_region_vars.push(rid);
98 rid
99 }
100
101 pub fn push_upvar_region(&mut self) -> RegionId {
103 let region_id = self
106 .params
107 .regions
108 .push_with(|index| RegionParam { index, name: None });
109 self.closure_upvar_regions.push(region_id);
110 region_id
111 }
112
113 pub(crate) fn push_type_var(&mut self, rid: u32, name: hax::Symbol) -> TypeVarId {
114 let mut name = name.to_string();
117 if name
118 .chars()
119 .any(|c| !(c.is_ascii_alphanumeric() || c == '_'))
120 {
121 name = format!("T{rid}")
122 }
123 let var_id = self
124 .params
125 .types
126 .push_with(|index| TypeParam { index, name });
127 self.type_vars_map.insert(rid, var_id);
128 var_id
129 }
130
131 pub(crate) fn push_const_generic_var(&mut self, rid: u32, ty: Ty, name: hax::Symbol) {
132 let var_id = self
133 .params
134 .const_generics
135 .push_with(|index| ConstGenericParam {
136 index,
137 name: name.to_string(),
138 ty,
139 });
140 self.const_generic_vars_map.insert(rid, var_id);
141 }
142
143 pub(crate) fn push_params_from_binder(&mut self, binder: hax::Binder<()>) -> Result<(), Error> {
145 assert!(
146 self.bound_region_vars.is_empty(),
147 "Trying to use two binders at the same binding level"
148 );
149 use hax::BoundVariableKind::*;
150 for p in binder.bound_vars {
151 match p {
152 Region(region) => {
153 self.push_bound_region(region);
154 }
155 Ty(_) => {
156 panic!("Unexpected locally bound type variable");
157 }
158 Const => {
159 panic!("Unexpected locally bound const generic variable");
160 }
161 }
162 }
163 Ok(())
164 }
165}
166
167impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
168 pub(crate) fn the_only_binder(&self) -> &BindingLevel {
170 assert_eq!(self.binding_levels.len(), 1);
171 self.innermost_binder()
172 }
173 pub(crate) fn the_only_binder_mut(&mut self) -> &mut BindingLevel {
175 assert_eq!(self.binding_levels.len(), 1);
176 self.innermost_binder_mut()
177 }
178
179 pub(crate) fn outermost_binder(&self) -> &BindingLevel {
180 self.binding_levels.outermost()
181 }
182 pub(crate) fn outermost_binder_mut(&mut self) -> &mut BindingLevel {
183 self.binding_levels.outermost_mut()
184 }
185 pub(crate) fn innermost_binder(&self) -> &BindingLevel {
186 self.binding_levels.innermost()
187 }
188 pub(crate) fn innermost_binder_mut(&mut self) -> &mut BindingLevel {
189 self.binding_levels.innermost_mut()
190 }
191
192 pub(crate) fn outermost_generics(&self) -> &GenericParams {
193 &self.outermost_binder().params
194 }
195 #[expect(dead_code)]
196 pub(crate) fn outermost_generics_mut(&mut self) -> &mut GenericParams {
197 &mut self.outermost_binder_mut().params
198 }
199 pub(crate) fn innermost_generics(&self) -> &GenericParams {
200 &self.innermost_binder().params
201 }
202 pub(crate) fn innermost_generics_mut(&mut self) -> &mut GenericParams {
203 &mut self.innermost_binder_mut().params
204 }
205
206 pub(crate) fn lookup_bound_region(
207 &mut self,
208 span: Span,
209 dbid: hax::DebruijnIndex,
210 var: hax::BoundVar,
211 ) -> Result<RegionDbVar, Error> {
212 let dbid = DeBruijnId::new(dbid);
213 if let Some(rid) = self
214 .binding_levels
215 .get(dbid)
216 .and_then(|bl| bl.bound_region_vars.get(var))
217 {
218 Ok(DeBruijnVar::bound(dbid, *rid))
219 } else {
220 raise_error!(
221 self,
222 span,
223 "Unexpected error: could not find region '{dbid}_{var}"
224 )
225 }
226 }
227
228 pub(crate) fn lookup_param<Id: Copy>(
229 &mut self,
230 span: Span,
231 f: impl for<'a> Fn(&'a BindingLevel) -> Option<Id>,
232 mk_err: impl FnOnce() -> String,
233 ) -> Result<DeBruijnVar<Id>, Error> {
234 for (dbid, bl) in self.binding_levels.iter_enumerated() {
235 if let Some(id) = f(bl) {
236 return Ok(DeBruijnVar::bound(dbid, id));
237 }
238 }
239 let err = mk_err();
240 raise_error!(self, span, "Unexpected error: could not find {}", err)
241 }
242
243 pub(crate) fn lookup_early_region(
244 &mut self,
245 span: Span,
246 region: &hax::EarlyParamRegion,
247 ) -> Result<RegionDbVar, Error> {
248 self.lookup_param(
249 span,
250 |bl| bl.early_region_vars.get(region).copied(),
251 || format!("the region variable {region:?}"),
252 )
253 }
254
255 pub(crate) fn lookup_type_var(
256 &mut self,
257 span: Span,
258 param: &hax::ParamTy,
259 ) -> Result<TypeDbVar, Error> {
260 self.lookup_param(
261 span,
262 |bl| bl.type_vars_map.get(¶m.index).copied(),
263 || format!("the type variable {}", param.name),
264 )
265 }
266
267 pub(crate) fn lookup_const_generic_var(
268 &mut self,
269 span: Span,
270 param: &hax::ParamConst,
271 ) -> Result<ConstGenericDbVar, Error> {
272 self.lookup_param(
273 span,
274 |bl| bl.const_generic_vars_map.get(¶m.index).copied(),
275 || format!("the const generic variable {}", param.name),
276 )
277 }
278
279 pub(crate) fn lookup_clause_var(
280 &mut self,
281 span: Span,
282 mut id: usize,
283 ) -> Result<ClauseDbVar, Error> {
284 let innermost_item_binder_id = self
289 .binding_levels
290 .iter_enumerated()
291 .find(|(_, bl)| bl.is_item_binder)
292 .unwrap()
293 .0;
294 for (dbid, bl) in self.binding_levels.iter_enumerated().rev() {
296 let num_clauses_bound_at_this_level = bl.params.trait_clauses.elem_count();
297 if id < num_clauses_bound_at_this_level || dbid == innermost_item_binder_id {
298 let id = TraitClauseId::from_usize(id);
299 return Ok(DeBruijnVar::bound(dbid, id));
300 } else {
301 id -= num_clauses_bound_at_this_level
302 }
303 }
304 raise_error!(
306 self,
307 span,
308 "Unexpected error: could not find clause variable {}",
309 id
310 )
311 }
312
313 pub(crate) fn push_generic_params(&mut self, generics: &hax::TyGenerics) -> Result<(), Error> {
314 for param in &generics.params {
315 self.push_generic_param(param)?;
316 }
317 Ok(())
318 }
319
320 pub(crate) fn push_generic_param(&mut self, param: &hax::GenericParamDef) -> Result<(), Error> {
321 match ¶m.kind {
322 hax::GenericParamDefKind::Lifetime => {
323 let region = hax::EarlyParamRegion {
324 index: param.index,
325 name: param.name.clone(),
326 };
327 let _ = self.innermost_binder_mut().push_early_region(region);
328 }
329 hax::GenericParamDefKind::Type { .. } => {
330 let _ = self
331 .innermost_binder_mut()
332 .push_type_var(param.index, param.name);
333 }
334 hax::GenericParamDefKind::Const { ty, .. } => {
335 let span = self.def_span(¶m.def_id);
336 let ty = self.translate_ty(span, ty)?;
339 self.innermost_binder_mut()
340 .push_const_generic_var(param.index, ty, param.name);
341 }
342 }
343
344 Ok(())
345 }
346
347 fn push_late_bound_generics_for_def(
356 &mut self,
357 _span: Span,
358 def: &hax::FullDef,
359 ) -> Result<(), Error> {
360 if let hax::FullDefKind::Fn { sig, .. } | hax::FullDefKind::AssocFn { sig, .. } = def.kind()
361 {
362 let innermost_binder = self.innermost_binder_mut();
363 assert!(innermost_binder.bound_region_vars.is_empty());
364 innermost_binder.push_params_from_binder(sig.rebind(()))?;
365 }
366 Ok(())
367 }
368
369 #[tracing::instrument(skip(self, span, def))]
371 fn push_generics_for_def(&mut self, span: Span, def: &hax::FullDef) -> Result<(), Error> {
372 trace!("{:?}", def.param_env());
373 if let Some(parent_item) = def.typing_parent(self.hax_state()) {
376 let parent_def = self.hax_def(&parent_item)?;
377 self.push_generics_for_def(span, &parent_def)?;
378 }
379 self.push_generics_for_def_without_parents(span, def)?;
380 Ok(())
381 }
382
383 fn push_generics_for_def_without_parents(
386 &mut self,
387 _span: Span,
388 def: &hax::FullDef,
389 ) -> Result<(), Error> {
390 use hax::FullDefKind;
391 if let Some(param_env) = def.param_env() {
392 self.push_generic_params(¶m_env.generics)?;
394 let origin = match &def.kind {
396 FullDefKind::Adt { .. }
397 | FullDefKind::TyAlias { .. }
398 | FullDefKind::AssocTy { .. } => PredicateOrigin::WhereClauseOnType,
399 FullDefKind::Fn { .. }
400 | FullDefKind::AssocFn { .. }
401 | FullDefKind::Closure { .. }
402 | FullDefKind::Const { .. }
403 | FullDefKind::AssocConst { .. }
404 | FullDefKind::Static { .. } => PredicateOrigin::WhereClauseOnFn,
405 FullDefKind::TraitImpl { .. } | FullDefKind::InherentImpl { .. } => {
406 PredicateOrigin::WhereClauseOnImpl
407 }
408 FullDefKind::Trait { .. } | FullDefKind::TraitAlias { .. } => {
409 PredicateOrigin::WhereClauseOnTrait
410 }
411 _ => panic!("Unexpected def: {:?}", def.def_id().kind),
412 };
413 self.register_predicates(¶m_env.predicates, origin.clone())?;
414 }
415
416 Ok(())
417 }
418
419 pub fn translate_item_generics(
427 &mut self,
428 span: Span,
429 def: &hax::FullDef,
430 kind: &TransItemSourceKind,
431 ) -> Result<(), Error> {
432 assert!(self.binding_levels.len() == 0);
433 self.binding_levels.push(BindingLevel::new(true));
434 self.push_generics_for_def(span, def)?;
435 self.push_late_bound_generics_for_def(span, def)?;
436
437 if let hax::FullDefKind::Closure { args, .. } = def.kind() {
438 let upvar_tys = self.translate_closure_upvar_tys(span, args)?;
441 let upvar_tys = upvar_tys.replace_erased_regions(|| {
443 let region_id = self.the_only_binder_mut().push_upvar_region();
444 Region::Var(DeBruijnVar::new_at_zero(region_id))
445 });
446 self.the_only_binder_mut().closure_upvar_tys = Some(upvar_tys);
447
448 if let TransItemSourceKind::TraitImpl(TraitImplSource::Closure(..))
450 | TransItemSourceKind::ClosureMethod(..)
451 | TransItemSourceKind::ClosureAsFnCast = kind
452 {
453 self.the_only_binder_mut()
454 .push_params_from_binder(args.fn_sig.rebind(()))?;
455 }
456 if let TransItemSourceKind::ClosureMethod(ClosureKind::Fn | ClosureKind::FnMut) = kind {
457 let rid = self
459 .the_only_binder_mut()
460 .params
461 .regions
462 .push_with(|index| RegionParam { index, name: None });
463 self.the_only_binder_mut().closure_call_method_region = Some(rid);
464 }
465 }
466
467 self.innermost_binder_mut().params.check_consistency();
468 Ok(())
469 }
470
471 pub(crate) fn inside_binder<F, U>(
473 &mut self,
474 kind: BinderKind,
475 is_item_binder: bool,
476 f: F,
477 ) -> Result<Binder<U>, Error>
478 where
479 F: FnOnce(&mut Self) -> Result<U, Error>,
480 {
481 assert!(!self.binding_levels.is_empty());
482 self.binding_levels.push(BindingLevel::new(is_item_binder));
483
484 let res = f(self);
486
487 let params = self.binding_levels.pop().unwrap().params;
489
490 res.map(|skip_binder| Binder {
492 kind,
493 params,
494 skip_binder,
495 })
496 }
497
498 pub(crate) fn translate_binder_for_def<F, U>(
501 &mut self,
502 span: Span,
503 kind: BinderKind,
504 def: &hax::FullDef,
505 f: F,
506 ) -> Result<Binder<U>, Error>
507 where
508 F: FnOnce(&mut Self) -> Result<U, Error>,
509 {
510 self.inside_binder(kind, true, |this| {
511 this.push_generics_for_def_without_parents(span, def)?;
512 this.push_late_bound_generics_for_def(span, def)?;
513 this.innermost_binder().params.check_consistency();
514 f(this)
515 })
516 }
517
518 pub(crate) fn translate_region_binder<F, T, U>(
522 &mut self,
523 _span: Span,
524 binder: &hax::Binder<T>,
525 f: F,
526 ) -> Result<RegionBinder<U>, Error>
527 where
528 F: FnOnce(&mut Self, &T) -> Result<U, Error>,
529 {
530 let binder = self.inside_binder(BinderKind::Other, false, |this| {
531 this.innermost_binder_mut()
532 .push_params_from_binder(binder.rebind(()))?;
533 f(this, binder.hax_skip_binder_ref())
534 })?;
535 Ok(RegionBinder {
537 regions: binder.params.regions,
538 skip_binder: binder.skip_binder,
539 })
540 }
541
542 pub(crate) fn into_generics(mut self) -> GenericParams {
543 assert!(self.binding_levels.len() == 1);
544 self.binding_levels.pop().unwrap().params
545 }
546}