1use super::translate_ctx::ItemTransCtx;
2use charon_lib::ast::*;
3use charon_lib::common::hash_by_addr::HashByAddr;
4use std::collections::HashMap;
5use std::fmt::Debug;
6use std::sync::Arc;
7
8#[derive(Debug, Default)]
20pub(crate) struct BindingLevel {
21 pub params: GenericParams,
23 pub is_item_binder: bool,
27 pub early_region_vars: std::collections::BTreeMap<hax::EarlyParamRegion, RegionId>,
34 pub bound_region_vars: Vec<RegionId>,
36 pub by_ref_upvar_regions: Vec<RegionId>,
38 pub type_vars_map: HashMap<u32, TypeVarId>,
40 pub const_generic_vars_map: HashMap<u32, ConstGenericVarId>,
42 pub type_trans_cache: HashMap<HashByAddr<Arc<hax::TyKind>>, Ty>,
46}
47
48fn translate_region_name(s: String) -> Option<String> {
50 if s == "'_" { None } else { Some(s) }
51}
52
53impl BindingLevel {
54 pub(crate) fn new(is_item_binder: bool) -> Self {
55 Self {
56 is_item_binder,
57 ..Default::default()
58 }
59 }
60
61 pub(crate) fn push_early_region(&mut self, region: hax::EarlyParamRegion) -> RegionId {
63 let name = translate_region_name(region.name.clone());
64 assert!(
66 self.bound_region_vars.is_empty(),
67 "Early regions must be translated before late ones"
68 );
69 let rid = self
70 .params
71 .regions
72 .push_with(|index| RegionParam { index, name });
73 self.early_region_vars.insert(region, rid);
74 rid
75 }
76
77 pub(crate) fn push_bound_region(&mut self, region: hax::BoundRegionKind) -> RegionId {
79 use hax::BoundRegionKind::*;
80 let name = match region {
81 Anon => None,
82 NamedAnon(symbol) | Named(_, symbol) => translate_region_name(symbol.clone()),
83 ClosureEnv => Some("@env".to_owned()),
84 };
85 let rid = self
86 .params
87 .regions
88 .push_with(|index| RegionParam { index, name });
89 self.bound_region_vars.push(rid);
90 rid
91 }
92
93 pub fn push_upvar_region(&mut self) -> RegionId {
95 let region_id = self
98 .params
99 .regions
100 .push_with(|index| RegionParam { index, name: None });
101 self.by_ref_upvar_regions.push(region_id);
102 region_id
103 }
104
105 pub(crate) fn push_type_var(&mut self, rid: u32, name: String) -> TypeVarId {
106 let var_id = self
107 .params
108 .types
109 .push_with(|index| TypeParam { index, name });
110 self.type_vars_map.insert(rid, var_id);
111 var_id
112 }
113
114 pub(crate) fn push_const_generic_var(&mut self, rid: u32, ty: LiteralTy, name: String) {
115 let var_id = self
116 .params
117 .const_generics
118 .push_with(|index| ConstGenericParam { index, name, ty });
119 self.const_generic_vars_map.insert(rid, var_id);
120 }
121
122 pub(crate) fn push_params_from_binder(&mut self, binder: hax::Binder<()>) -> Result<(), Error> {
124 assert!(
125 self.bound_region_vars.is_empty(),
126 "Trying to use two binders at the same binding level"
127 );
128 use hax::BoundVariableKind::*;
129 for p in binder.bound_vars {
130 match p {
131 Region(region) => {
132 self.push_bound_region(region);
133 }
134 Ty(_) => {
135 panic!("Unexpected locally bound type variable");
136 }
137 Const => {
138 panic!("Unexpected locally bound const generic variable");
139 }
140 }
141 }
142 Ok(())
143 }
144}
145
146impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
147 pub(crate) fn the_only_binder(&self) -> &BindingLevel {
149 assert_eq!(self.binding_levels.len(), 1);
150 self.innermost_binder()
151 }
152 pub(crate) fn the_only_binder_mut(&mut self) -> &mut BindingLevel {
154 assert_eq!(self.binding_levels.len(), 1);
155 self.innermost_binder_mut()
156 }
157
158 pub(crate) fn outermost_binder(&self) -> &BindingLevel {
159 self.binding_levels.outermost()
160 }
161 pub(crate) fn outermost_binder_mut(&mut self) -> &mut BindingLevel {
162 self.binding_levels.outermost_mut()
163 }
164 pub(crate) fn innermost_binder(&self) -> &BindingLevel {
165 self.binding_levels.innermost()
166 }
167 pub(crate) fn innermost_binder_mut(&mut self) -> &mut BindingLevel {
168 self.binding_levels.innermost_mut()
169 }
170
171 #[expect(dead_code)]
172 pub(crate) fn outermost_generics(&self) -> &GenericParams {
173 &self.outermost_binder().params
174 }
175 #[expect(dead_code)]
176 pub(crate) fn outermost_generics_mut(&mut self) -> &mut GenericParams {
177 &mut self.outermost_binder_mut().params
178 }
179 #[expect(dead_code)]
180 pub(crate) fn innermost_generics(&self) -> &GenericParams {
181 &self.innermost_binder().params
182 }
183 pub(crate) fn innermost_generics_mut(&mut self) -> &mut GenericParams {
184 &mut self.innermost_binder_mut().params
185 }
186
187 pub(crate) fn lookup_bound_region(
188 &mut self,
189 span: Span,
190 dbid: hax::DebruijnIndex,
191 var: hax::BoundVar,
192 ) -> Result<RegionDbVar, Error> {
193 let dbid = DeBruijnId::new(dbid);
194 if let Some(rid) = self
195 .binding_levels
196 .get(dbid)
197 .and_then(|bl| bl.bound_region_vars.get(var))
198 {
199 Ok(DeBruijnVar::bound(dbid, *rid))
200 } else {
201 raise_error!(
202 self,
203 span,
204 "Unexpected error: could not find region '{dbid}_{var}"
205 )
206 }
207 }
208
209 pub(crate) fn lookup_param<Id: Copy>(
210 &mut self,
211 span: Span,
212 f: impl for<'a> Fn(&'a BindingLevel) -> Option<Id>,
213 mk_err: impl FnOnce() -> String,
214 ) -> Result<DeBruijnVar<Id>, Error> {
215 for (dbid, bl) in self.binding_levels.iter_enumerated() {
216 if let Some(id) = f(bl) {
217 return Ok(DeBruijnVar::bound(dbid, id));
218 }
219 }
220 let err = mk_err();
221 raise_error!(self, span, "Unexpected error: could not find {}", err)
222 }
223
224 pub(crate) fn lookup_early_region(
225 &mut self,
226 span: Span,
227 region: &hax::EarlyParamRegion,
228 ) -> Result<RegionDbVar, Error> {
229 self.lookup_param(
230 span,
231 |bl| bl.early_region_vars.get(region).copied(),
232 || format!("the region variable {region:?}"),
233 )
234 }
235
236 pub(crate) fn lookup_type_var(
237 &mut self,
238 span: Span,
239 param: &hax::ParamTy,
240 ) -> Result<TypeDbVar, Error> {
241 self.lookup_param(
242 span,
243 |bl| bl.type_vars_map.get(¶m.index).copied(),
244 || format!("the type variable {}", param.name),
245 )
246 }
247
248 pub(crate) fn lookup_const_generic_var(
249 &mut self,
250 span: Span,
251 param: &hax::ParamConst,
252 ) -> Result<ConstGenericDbVar, Error> {
253 self.lookup_param(
254 span,
255 |bl| bl.const_generic_vars_map.get(¶m.index).copied(),
256 || format!("the const generic variable {}", param.name),
257 )
258 }
259
260 pub(crate) fn lookup_clause_var(
261 &mut self,
262 span: Span,
263 mut id: usize,
264 ) -> Result<ClauseDbVar, Error> {
265 let innermost_item_binder_id = self
270 .binding_levels
271 .iter_enumerated()
272 .find(|(_, bl)| bl.is_item_binder)
273 .unwrap()
274 .0;
275 for (dbid, bl) in self.binding_levels.iter_enumerated().rev() {
277 let num_clauses_bound_at_this_level = bl.params.trait_clauses.elem_count();
278 if id < num_clauses_bound_at_this_level || dbid == innermost_item_binder_id {
279 let id = TraitClauseId::from_usize(id);
280 return Ok(DeBruijnVar::bound(dbid, id));
281 } else {
282 id -= num_clauses_bound_at_this_level
283 }
284 }
285 raise_error!(
287 self,
288 span,
289 "Unexpected error: could not find clause variable {}",
290 id
291 )
292 }
293
294 pub(crate) fn push_generic_params(&mut self, generics: &hax::TyGenerics) -> Result<(), Error> {
295 for param in &generics.params {
296 self.push_generic_param(param)?;
297 }
298 Ok(())
299 }
300
301 pub(crate) fn push_generic_param(&mut self, param: &hax::GenericParamDef) -> Result<(), Error> {
302 match ¶m.kind {
303 hax::GenericParamDefKind::Lifetime => {
304 let region = hax::EarlyParamRegion {
305 index: param.index,
306 name: param.name.clone(),
307 };
308 let _ = self.innermost_binder_mut().push_early_region(region);
309 }
310 hax::GenericParamDefKind::Type { .. } => {
311 let _ = self
312 .innermost_binder_mut()
313 .push_type_var(param.index, param.name.clone());
314 }
315 hax::GenericParamDefKind::Const { ty, .. } => {
316 let span = self.def_span(¶m.def_id);
317 let ty = self.translate_ty(span, ty)?;
320 match ty.kind().as_literal() {
321 Some(ty) => self.innermost_binder_mut().push_const_generic_var(
322 param.index,
323 *ty,
324 param.name.clone(),
325 ),
326 None => raise_error!(
327 self,
328 span,
329 "Constant parameters of non-literal type are not supported"
330 ),
331 }
332 }
333 }
334
335 Ok(())
336 }
337
338 #[tracing::instrument(skip(self, span))]
340 fn push_generics_for_def(
341 &mut self,
342 span: Span,
343 def: &hax::FullDef,
344 is_parent: bool,
345 ) -> Result<(), Error> {
346 if let Some(parent_item) = def.typing_parent(self.hax_state()) {
349 let parent_def = self.hax_def(&parent_item)?;
350 self.push_generics_for_def(span, &parent_def, true)?;
351 }
352 self.push_generics_for_def_without_parents(span, def, !is_parent)?;
353 Ok(())
354 }
355
356 fn push_generics_for_def_without_parents(
359 &mut self,
360 _span: Span,
361 def: &hax::FullDef,
362 include_late_bound: bool,
363 ) -> Result<(), Error> {
364 use hax::FullDefKind;
365 if let Some(param_env) = def.param_env() {
366 self.push_generic_params(¶m_env.generics)?;
368 let origin = match &def.kind {
370 FullDefKind::Adt { .. }
371 | FullDefKind::TyAlias { .. }
372 | FullDefKind::AssocTy { .. } => PredicateOrigin::WhereClauseOnType,
373 FullDefKind::Fn { .. }
374 | FullDefKind::AssocFn { .. }
375 | FullDefKind::Const { .. }
376 | FullDefKind::AssocConst { .. }
377 | FullDefKind::Static { .. } => PredicateOrigin::WhereClauseOnFn,
378 FullDefKind::TraitImpl { .. } | FullDefKind::InherentImpl { .. } => {
379 PredicateOrigin::WhereClauseOnImpl
380 }
381 FullDefKind::Trait { .. } | FullDefKind::TraitAlias { .. } => {
382 PredicateOrigin::WhereClauseOnTrait
383 }
384 _ => panic!("Unexpected def: {def:?}"),
385 };
386 self.register_predicates(¶m_env.predicates, origin.clone())?;
387 }
388
389 if let hax::FullDefKind::Closure { args, .. } = def.kind()
390 && include_late_bound
391 {
392 args.upvar_tys.iter().for_each(|ty| {
394 if matches!(
395 ty.kind(),
396 hax::TyKind::Ref(
397 hax::Region {
398 kind: hax::RegionKind::ReErased
399 },
400 ..
401 )
402 ) {
403 self.the_only_binder_mut().push_upvar_region();
404 }
405 });
406 }
407
408 let signature = match &def.kind {
417 hax::FullDefKind::Fn { sig, .. } => Some(sig),
418 hax::FullDefKind::AssocFn { sig, .. } => Some(sig),
419 _ => None,
420 };
421 if let Some(signature) = signature
422 && include_late_bound
423 {
424 let innermost_binder = self.innermost_binder_mut();
425 assert!(innermost_binder.bound_region_vars.is_empty());
426 innermost_binder.push_params_from_binder(signature.rebind(()))?;
427 }
428
429 Ok(())
430 }
431
432 pub(crate) fn translate_def_generics(
437 &mut self,
438 span: Span,
439 def: &hax::FullDef,
440 ) -> Result<(), Error> {
441 assert!(self.binding_levels.len() == 0);
442 self.binding_levels.push(BindingLevel::new(true));
443 self.push_generics_for_def(span, def, false)?;
444 self.innermost_binder_mut().params.check_consistency();
445 Ok(())
446 }
447
448 pub(crate) fn translate_def_generics_without_parents(
450 &mut self,
451 span: Span,
452 def: &hax::FullDef,
453 ) -> Result<(), Error> {
454 self.binding_levels.push(BindingLevel::new(true));
455 self.push_generics_for_def_without_parents(span, def, true)?;
456 self.innermost_binder().params.check_consistency();
457 Ok(())
458 }
459
460 pub(crate) fn translate_binder_for_def<F, U>(
463 &mut self,
464 span: Span,
465 kind: BinderKind,
466 def: &hax::FullDef,
467 f: F,
468 ) -> Result<Binder<U>, Error>
469 where
470 F: FnOnce(&mut Self) -> Result<U, Error>,
471 {
472 assert!(!self.binding_levels.is_empty());
473
474 self.translate_def_generics_without_parents(span, def)?;
476
477 let res = f(self);
479
480 let params = self.binding_levels.pop().unwrap().params;
482
483 res.map(|skip_binder| Binder {
485 kind,
486 params,
487 skip_binder,
488 })
489 }
490
491 pub(crate) fn translate_region_binder<F, T, U>(
495 &mut self,
496 _span: Span,
497 binder: &hax::Binder<T>,
498 f: F,
499 ) -> Result<RegionBinder<U>, Error>
500 where
501 F: FnOnce(&mut Self, &T) -> Result<U, Error>,
502 {
503 assert!(!self.binding_levels.is_empty());
504
505 let mut binding_level = BindingLevel::new(false);
507 binding_level.push_params_from_binder(binder.rebind(()))?;
508 self.binding_levels.push(binding_level);
509
510 let res = f(self, binder.hax_skip_binder_ref());
512
513 let regions = self.binding_levels.pop().unwrap().params.regions;
515
516 res.map(|skip_binder| RegionBinder {
518 regions,
519 skip_binder,
520 })
521 }
522
523 pub(crate) fn into_generics(mut self) -> GenericParams {
524 assert!(self.binding_levels.len() == 1);
525 self.binding_levels.pop().unwrap().params
526 }
527}