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 var_id = self.params.types.push_with(|index| TypeParam {
115 index,
116 name: name.to_string(),
117 });
118 self.type_vars_map.insert(rid, var_id);
119 var_id
120 }
121
122 pub(crate) fn push_const_generic_var(&mut self, rid: u32, ty: Ty, name: hax::Symbol) {
123 let var_id = self
124 .params
125 .const_generics
126 .push_with(|index| ConstGenericParam {
127 index,
128 name: name.to_string(),
129 ty,
130 });
131 self.const_generic_vars_map.insert(rid, var_id);
132 }
133
134 pub(crate) fn push_params_from_binder(&mut self, binder: hax::Binder<()>) -> Result<(), Error> {
136 assert!(
137 self.bound_region_vars.is_empty(),
138 "Trying to use two binders at the same binding level"
139 );
140 use hax::BoundVariableKind::*;
141 for p in binder.bound_vars {
142 match p {
143 Region(region) => {
144 self.push_bound_region(region);
145 }
146 Ty(_) => {
147 panic!("Unexpected locally bound type variable");
148 }
149 Const => {
150 panic!("Unexpected locally bound const generic variable");
151 }
152 }
153 }
154 Ok(())
155 }
156}
157
158impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
159 pub(crate) fn the_only_binder(&self) -> &BindingLevel {
161 assert_eq!(self.binding_levels.len(), 1);
162 self.innermost_binder()
163 }
164 pub(crate) fn the_only_binder_mut(&mut self) -> &mut BindingLevel {
166 assert_eq!(self.binding_levels.len(), 1);
167 self.innermost_binder_mut()
168 }
169
170 pub(crate) fn outermost_binder(&self) -> &BindingLevel {
171 self.binding_levels.outermost()
172 }
173 pub(crate) fn outermost_binder_mut(&mut self) -> &mut BindingLevel {
174 self.binding_levels.outermost_mut()
175 }
176 pub(crate) fn innermost_binder(&self) -> &BindingLevel {
177 self.binding_levels.innermost()
178 }
179 pub(crate) fn innermost_binder_mut(&mut self) -> &mut BindingLevel {
180 self.binding_levels.innermost_mut()
181 }
182
183 pub(crate) fn outermost_generics(&self) -> &GenericParams {
184 &self.outermost_binder().params
185 }
186 #[expect(dead_code)]
187 pub(crate) fn outermost_generics_mut(&mut self) -> &mut GenericParams {
188 &mut self.outermost_binder_mut().params
189 }
190 pub(crate) fn innermost_generics(&self) -> &GenericParams {
191 &self.innermost_binder().params
192 }
193 pub(crate) fn innermost_generics_mut(&mut self) -> &mut GenericParams {
194 &mut self.innermost_binder_mut().params
195 }
196
197 pub(crate) fn lookup_bound_region(
198 &mut self,
199 span: Span,
200 dbid: hax::DebruijnIndex,
201 var: hax::BoundVar,
202 ) -> Result<RegionDbVar, Error> {
203 let dbid = DeBruijnId::new(dbid);
204 if let Some(rid) = self
205 .binding_levels
206 .get(dbid)
207 .and_then(|bl| bl.bound_region_vars.get(var))
208 {
209 Ok(DeBruijnVar::bound(dbid, *rid))
210 } else {
211 raise_error!(
212 self,
213 span,
214 "Unexpected error: could not find region '{dbid}_{var}"
215 )
216 }
217 }
218
219 pub(crate) fn lookup_param<Id: Copy>(
220 &mut self,
221 span: Span,
222 f: impl for<'a> Fn(&'a BindingLevel) -> Option<Id>,
223 mk_err: impl FnOnce() -> String,
224 ) -> Result<DeBruijnVar<Id>, Error> {
225 for (dbid, bl) in self.binding_levels.iter_enumerated() {
226 if let Some(id) = f(bl) {
227 return Ok(DeBruijnVar::bound(dbid, id));
228 }
229 }
230 let err = mk_err();
231 raise_error!(self, span, "Unexpected error: could not find {}", err)
232 }
233
234 pub(crate) fn lookup_early_region(
235 &mut self,
236 span: Span,
237 region: &hax::EarlyParamRegion,
238 ) -> Result<RegionDbVar, Error> {
239 self.lookup_param(
240 span,
241 |bl| bl.early_region_vars.get(region).copied(),
242 || format!("the region variable {region:?}"),
243 )
244 }
245
246 pub(crate) fn lookup_type_var(
247 &mut self,
248 span: Span,
249 param: &hax::ParamTy,
250 ) -> Result<TypeDbVar, Error> {
251 self.lookup_param(
252 span,
253 |bl| bl.type_vars_map.get(¶m.index).copied(),
254 || format!("the type variable {}", param.name),
255 )
256 }
257
258 pub(crate) fn lookup_const_generic_var(
259 &mut self,
260 span: Span,
261 param: &hax::ParamConst,
262 ) -> Result<ConstGenericDbVar, Error> {
263 self.lookup_param(
264 span,
265 |bl| bl.const_generic_vars_map.get(¶m.index).copied(),
266 || format!("the const generic variable {}", param.name),
267 )
268 }
269
270 pub(crate) fn lookup_clause_var(
271 &mut self,
272 span: Span,
273 mut id: usize,
274 ) -> Result<ClauseDbVar, Error> {
275 let innermost_item_binder_id = self
280 .binding_levels
281 .iter_enumerated()
282 .find(|(_, bl)| bl.is_item_binder)
283 .unwrap()
284 .0;
285 for (dbid, bl) in self.binding_levels.iter_enumerated().rev() {
287 let num_clauses_bound_at_this_level = bl.params.trait_clauses.elem_count();
288 if id < num_clauses_bound_at_this_level || dbid == innermost_item_binder_id {
289 let id = TraitClauseId::from_usize(id);
290 return Ok(DeBruijnVar::bound(dbid, id));
291 } else {
292 id -= num_clauses_bound_at_this_level
293 }
294 }
295 raise_error!(
297 self,
298 span,
299 "Unexpected error: could not find clause variable {}",
300 id
301 )
302 }
303
304 pub(crate) fn push_generic_params(&mut self, generics: &hax::TyGenerics) -> Result<(), Error> {
305 for param in &generics.params {
306 self.push_generic_param(param)?;
307 }
308 Ok(())
309 }
310
311 pub(crate) fn push_generic_param(&mut self, param: &hax::GenericParamDef) -> Result<(), Error> {
312 match ¶m.kind {
313 hax::GenericParamDefKind::Lifetime => {
314 let region = hax::EarlyParamRegion {
315 index: param.index,
316 name: param.name.clone(),
317 };
318 let _ = self.innermost_binder_mut().push_early_region(region);
319 }
320 hax::GenericParamDefKind::Type { .. } => {
321 let _ = self
322 .innermost_binder_mut()
323 .push_type_var(param.index, param.name);
324 }
325 hax::GenericParamDefKind::Const { ty, .. } => {
326 let span = self.def_span(¶m.def_id);
327 let ty = self.translate_ty(span, ty)?;
330 self.innermost_binder_mut()
331 .push_const_generic_var(param.index, ty, param.name);
332 }
333 }
334
335 Ok(())
336 }
337
338 fn push_late_bound_generics_for_def(
347 &mut self,
348 _span: Span,
349 def: &hax::FullDef,
350 ) -> Result<(), Error> {
351 if let hax::FullDefKind::Fn { sig, .. } | hax::FullDefKind::AssocFn { sig, .. } = def.kind()
352 {
353 let innermost_binder = self.innermost_binder_mut();
354 assert!(innermost_binder.bound_region_vars.is_empty());
355 innermost_binder.push_params_from_binder(sig.rebind(()))?;
356 }
357 Ok(())
358 }
359
360 #[tracing::instrument(skip(self, span))]
362 fn push_generics_for_def(&mut self, span: Span, def: &hax::FullDef) -> Result<(), Error> {
363 if let Some(parent_item) = def.typing_parent(self.hax_state()) {
366 let parent_def = self.hax_def(&parent_item)?;
367 self.push_generics_for_def(span, &parent_def)?;
368 }
369 self.push_generics_for_def_without_parents(span, def)?;
370 Ok(())
371 }
372
373 fn push_generics_for_def_without_parents(
376 &mut self,
377 _span: Span,
378 def: &hax::FullDef,
379 ) -> Result<(), Error> {
380 use hax::FullDefKind;
381 if let Some(param_env) = def.param_env() {
382 self.push_generic_params(¶m_env.generics)?;
384 let origin = match &def.kind {
386 FullDefKind::Adt { .. }
387 | FullDefKind::TyAlias { .. }
388 | FullDefKind::AssocTy { .. } => PredicateOrigin::WhereClauseOnType,
389 FullDefKind::Fn { .. }
390 | FullDefKind::AssocFn { .. }
391 | FullDefKind::Closure { .. }
392 | FullDefKind::Const { .. }
393 | FullDefKind::AssocConst { .. }
394 | FullDefKind::Static { .. } => PredicateOrigin::WhereClauseOnFn,
395 FullDefKind::TraitImpl { .. } | FullDefKind::InherentImpl { .. } => {
396 PredicateOrigin::WhereClauseOnImpl
397 }
398 FullDefKind::Trait { .. } | FullDefKind::TraitAlias { .. } => {
399 PredicateOrigin::WhereClauseOnTrait
400 }
401 _ => panic!("Unexpected def: {:?}", def.def_id().kind),
402 };
403 self.register_predicates(¶m_env.predicates, origin.clone())?;
404 }
405
406 Ok(())
407 }
408
409 pub fn translate_item_generics(
417 &mut self,
418 span: Span,
419 def: &hax::FullDef,
420 kind: &TransItemSourceKind,
421 ) -> Result<(), Error> {
422 assert!(self.binding_levels.len() == 0);
423 self.binding_levels.push(BindingLevel::new(true));
424 self.push_generics_for_def(span, def)?;
425 self.push_late_bound_generics_for_def(span, def)?;
426
427 if let hax::FullDefKind::Closure { args, .. } = def.kind() {
428 let closure_upvar_tys = self.translate_closure_upvar_tys(span, args)?;
431 self.the_only_binder_mut().closure_upvar_tys = Some(closure_upvar_tys);
432 if let TransItemSourceKind::TraitImpl(TraitImplSource::Closure(..))
434 | TransItemSourceKind::ClosureMethod(..)
435 | TransItemSourceKind::ClosureAsFnCast = kind
436 {
437 self.the_only_binder_mut()
438 .push_params_from_binder(args.fn_sig.rebind(()))?;
439 }
440 if let TransItemSourceKind::ClosureMethod(ClosureKind::Fn | ClosureKind::FnMut) = kind {
441 let rid = self
443 .the_only_binder_mut()
444 .params
445 .regions
446 .push_with(|index| RegionParam { index, name: None });
447 self.the_only_binder_mut().closure_call_method_region = Some(rid);
448 }
449 }
450
451 self.innermost_binder_mut().params.check_consistency();
452 Ok(())
453 }
454
455 pub(crate) fn inside_binder<F, U>(
457 &mut self,
458 kind: BinderKind,
459 is_item_binder: bool,
460 f: F,
461 ) -> Result<Binder<U>, Error>
462 where
463 F: FnOnce(&mut Self) -> Result<U, Error>,
464 {
465 assert!(!self.binding_levels.is_empty());
466 self.binding_levels.push(BindingLevel::new(is_item_binder));
467
468 let res = f(self);
470
471 let params = self.binding_levels.pop().unwrap().params;
473
474 res.map(|skip_binder| Binder {
476 kind,
477 params,
478 skip_binder,
479 })
480 }
481
482 pub(crate) fn translate_binder_for_def<F, U>(
485 &mut self,
486 span: Span,
487 kind: BinderKind,
488 def: &hax::FullDef,
489 f: F,
490 ) -> Result<Binder<U>, Error>
491 where
492 F: FnOnce(&mut Self) -> Result<U, Error>,
493 {
494 self.inside_binder(kind, true, |this| {
495 this.push_generics_for_def_without_parents(span, def)?;
496 this.push_late_bound_generics_for_def(span, def)?;
497 this.innermost_binder().params.check_consistency();
498 f(this)
499 })
500 }
501
502 pub(crate) fn translate_region_binder<F, T, U>(
506 &mut self,
507 _span: Span,
508 binder: &hax::Binder<T>,
509 f: F,
510 ) -> Result<RegionBinder<U>, Error>
511 where
512 F: FnOnce(&mut Self, &T) -> Result<U, Error>,
513 {
514 let binder = self.inside_binder(BinderKind::Other, false, |this| {
515 this.innermost_binder_mut()
516 .push_params_from_binder(binder.rebind(()))?;
517 f(this, binder.hax_skip_binder_ref())
518 })?;
519 Ok(RegionBinder {
521 regions: binder.params.regions,
522 skip_binder: binder.skip_binder,
523 })
524 }
525
526 pub(crate) fn into_generics(mut self) -> GenericParams {
527 assert!(self.binding_levels.len() == 1);
528 self.binding_levels.pop().unwrap().params
529 }
530}