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 pub(crate) fn outermost_generics(&self) -> &GenericParams {
172 &self.outermost_binder().params
173 }
174 #[expect(dead_code)]
175 pub(crate) fn outermost_generics_mut(&mut self) -> &mut GenericParams {
176 &mut self.outermost_binder_mut().params
177 }
178 pub(crate) fn innermost_generics(&self) -> &GenericParams {
179 &self.innermost_binder().params
180 }
181 pub(crate) fn innermost_generics_mut(&mut self) -> &mut GenericParams {
182 &mut self.innermost_binder_mut().params
183 }
184
185 pub(crate) fn lookup_bound_region(
186 &mut self,
187 span: Span,
188 dbid: hax::DebruijnIndex,
189 var: hax::BoundVar,
190 ) -> Result<RegionDbVar, Error> {
191 let dbid = DeBruijnId::new(dbid);
192 if let Some(rid) = self
193 .binding_levels
194 .get(dbid)
195 .and_then(|bl| bl.bound_region_vars.get(var))
196 {
197 Ok(DeBruijnVar::bound(dbid, *rid))
198 } else {
199 raise_error!(
200 self,
201 span,
202 "Unexpected error: could not find region '{dbid}_{var}"
203 )
204 }
205 }
206
207 pub(crate) fn lookup_param<Id: Copy>(
208 &mut self,
209 span: Span,
210 f: impl for<'a> Fn(&'a BindingLevel) -> Option<Id>,
211 mk_err: impl FnOnce() -> String,
212 ) -> Result<DeBruijnVar<Id>, Error> {
213 for (dbid, bl) in self.binding_levels.iter_enumerated() {
214 if let Some(id) = f(bl) {
215 return Ok(DeBruijnVar::bound(dbid, id));
216 }
217 }
218 let err = mk_err();
219 raise_error!(self, span, "Unexpected error: could not find {}", err)
220 }
221
222 pub(crate) fn lookup_early_region(
223 &mut self,
224 span: Span,
225 region: &hax::EarlyParamRegion,
226 ) -> Result<RegionDbVar, Error> {
227 self.lookup_param(
228 span,
229 |bl| bl.early_region_vars.get(region).copied(),
230 || format!("the region variable {region:?}"),
231 )
232 }
233
234 pub(crate) fn lookup_type_var(
235 &mut self,
236 span: Span,
237 param: &hax::ParamTy,
238 ) -> Result<TypeDbVar, Error> {
239 self.lookup_param(
240 span,
241 |bl| bl.type_vars_map.get(¶m.index).copied(),
242 || format!("the type variable {}", param.name),
243 )
244 }
245
246 pub(crate) fn lookup_const_generic_var(
247 &mut self,
248 span: Span,
249 param: &hax::ParamConst,
250 ) -> Result<ConstGenericDbVar, Error> {
251 self.lookup_param(
252 span,
253 |bl| bl.const_generic_vars_map.get(¶m.index).copied(),
254 || format!("the const generic variable {}", param.name),
255 )
256 }
257
258 pub(crate) fn lookup_clause_var(
259 &mut self,
260 span: Span,
261 mut id: usize,
262 ) -> Result<ClauseDbVar, Error> {
263 let innermost_item_binder_id = self
268 .binding_levels
269 .iter_enumerated()
270 .find(|(_, bl)| bl.is_item_binder)
271 .unwrap()
272 .0;
273 for (dbid, bl) in self.binding_levels.iter_enumerated().rev() {
275 let num_clauses_bound_at_this_level = bl.params.trait_clauses.elem_count();
276 if id < num_clauses_bound_at_this_level || dbid == innermost_item_binder_id {
277 let id = TraitClauseId::from_usize(id);
278 return Ok(DeBruijnVar::bound(dbid, id));
279 } else {
280 id -= num_clauses_bound_at_this_level
281 }
282 }
283 raise_error!(
285 self,
286 span,
287 "Unexpected error: could not find clause variable {}",
288 id
289 )
290 }
291
292 pub(crate) fn push_generic_params(&mut self, generics: &hax::TyGenerics) -> Result<(), Error> {
293 for param in &generics.params {
294 self.push_generic_param(param)?;
295 }
296 Ok(())
297 }
298
299 pub(crate) fn push_generic_param(&mut self, param: &hax::GenericParamDef) -> Result<(), Error> {
300 match ¶m.kind {
301 hax::GenericParamDefKind::Lifetime => {
302 let region = hax::EarlyParamRegion {
303 index: param.index,
304 name: param.name.clone(),
305 };
306 let _ = self.innermost_binder_mut().push_early_region(region);
307 }
308 hax::GenericParamDefKind::Type { .. } => {
309 let _ = self
310 .innermost_binder_mut()
311 .push_type_var(param.index, param.name.clone());
312 }
313 hax::GenericParamDefKind::Const { ty, .. } => {
314 let span = self.def_span(¶m.def_id);
315 let ty = self.translate_ty(span, ty)?;
318 match ty.kind().as_literal() {
319 Some(ty) => self.innermost_binder_mut().push_const_generic_var(
320 param.index,
321 *ty,
322 param.name.clone(),
323 ),
324 None => raise_error!(
325 self,
326 span,
327 "Constant parameters of non-literal type are not supported"
328 ),
329 }
330 }
331 }
332
333 Ok(())
334 }
335
336 #[tracing::instrument(skip(self, span))]
338 fn push_generics_for_def(
339 &mut self,
340 span: Span,
341 def: &hax::FullDef,
342 is_parent: bool,
343 ) -> Result<(), Error> {
344 if let Some(parent_item) = def.typing_parent(self.hax_state()) {
347 let parent_def = self.hax_def(&parent_item)?;
348 self.push_generics_for_def(span, &parent_def, true)?;
349 }
350 self.push_generics_for_def_without_parents(span, def, !is_parent)?;
351 Ok(())
352 }
353
354 fn push_generics_for_def_without_parents(
357 &mut self,
358 _span: Span,
359 def: &hax::FullDef,
360 include_late_bound: bool,
361 ) -> Result<(), Error> {
362 use hax::FullDefKind;
363 if let Some(param_env) = def.param_env() {
364 self.push_generic_params(¶m_env.generics)?;
366 let origin = match &def.kind {
368 FullDefKind::Adt { .. }
369 | FullDefKind::TyAlias { .. }
370 | FullDefKind::AssocTy { .. } => PredicateOrigin::WhereClauseOnType,
371 FullDefKind::Fn { .. }
372 | FullDefKind::AssocFn { .. }
373 | FullDefKind::Const { .. }
374 | FullDefKind::AssocConst { .. }
375 | FullDefKind::Static { .. } => PredicateOrigin::WhereClauseOnFn,
376 FullDefKind::TraitImpl { .. } | FullDefKind::InherentImpl { .. } => {
377 PredicateOrigin::WhereClauseOnImpl
378 }
379 FullDefKind::Trait { .. } | FullDefKind::TraitAlias { .. } => {
380 PredicateOrigin::WhereClauseOnTrait
381 }
382 _ => panic!("Unexpected def: {def:?}"),
383 };
384 self.register_predicates(¶m_env.predicates, origin.clone())?;
385 }
386
387 if let hax::FullDefKind::Closure { args, .. } = def.kind()
388 && include_late_bound
389 {
390 args.upvar_tys.iter().for_each(|ty| {
392 if matches!(
393 ty.kind(),
394 hax::TyKind::Ref(
395 hax::Region {
396 kind: hax::RegionKind::ReErased
397 },
398 ..
399 )
400 ) {
401 self.the_only_binder_mut().push_upvar_region();
402 }
403 });
404 }
405
406 let signature = match &def.kind {
415 hax::FullDefKind::Fn { sig, .. } => Some(sig),
416 hax::FullDefKind::AssocFn { sig, .. } => Some(sig),
417 _ => None,
418 };
419 if let Some(signature) = signature
420 && include_late_bound
421 {
422 let innermost_binder = self.innermost_binder_mut();
423 assert!(innermost_binder.bound_region_vars.is_empty());
424 innermost_binder.push_params_from_binder(signature.rebind(()))?;
425 }
426
427 Ok(())
428 }
429
430 pub(crate) fn translate_def_generics(
435 &mut self,
436 span: Span,
437 def: &hax::FullDef,
438 ) -> Result<(), Error> {
439 assert!(self.binding_levels.len() == 0);
440 self.binding_levels.push(BindingLevel::new(true));
441 self.push_generics_for_def(span, def, false)?;
442 self.innermost_binder_mut().params.check_consistency();
443 Ok(())
444 }
445
446 pub(crate) fn translate_def_generics_without_parents(
448 &mut self,
449 span: Span,
450 def: &hax::FullDef,
451 ) -> Result<(), Error> {
452 self.binding_levels.push(BindingLevel::new(true));
453 self.push_generics_for_def_without_parents(span, def, true)?;
454 self.innermost_binder().params.check_consistency();
455 Ok(())
456 }
457
458 pub(crate) fn translate_binder_for_def<F, U>(
461 &mut self,
462 span: Span,
463 kind: BinderKind,
464 def: &hax::FullDef,
465 f: F,
466 ) -> Result<Binder<U>, Error>
467 where
468 F: FnOnce(&mut Self) -> Result<U, Error>,
469 {
470 assert!(!self.binding_levels.is_empty());
471
472 self.translate_def_generics_without_parents(span, def)?;
474
475 let res = f(self);
477
478 let params = self.binding_levels.pop().unwrap().params;
480
481 res.map(|skip_binder| Binder {
483 kind,
484 params,
485 skip_binder,
486 })
487 }
488
489 pub(crate) fn translate_region_binder<F, T, U>(
493 &mut self,
494 _span: Span,
495 binder: &hax::Binder<T>,
496 f: F,
497 ) -> Result<RegionBinder<U>, Error>
498 where
499 F: FnOnce(&mut Self, &T) -> Result<U, Error>,
500 {
501 assert!(!self.binding_levels.is_empty());
502
503 let mut binding_level = BindingLevel::new(false);
505 binding_level.push_params_from_binder(binder.rebind(()))?;
506 self.binding_levels.push(binding_level);
507
508 let res = f(self, binder.hax_skip_binder_ref());
510
511 let regions = self.binding_levels.pop().unwrap().params.regions;
513
514 res.map(|skip_binder| RegionBinder {
516 regions,
517 skip_binder,
518 })
519 }
520
521 pub(crate) fn into_generics(mut self) -> GenericParams {
522 assert!(self.binding_levels.len() == 1);
523 self.binding_levels.pop().unwrap().params
524 }
525}