1use crate::translate::translate_ctx::TraitImplSource;
2
3use super::translate_ctx::{ItemTransCtx, TransItemSourceKind};
4use charon_lib::ast::*;
5use std::collections::HashMap;
6use std::fmt::Debug;
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 closure_call_method_region: Option<RegionId>,
40 pub type_vars_map: HashMap<u32, TypeVarId>,
42 pub const_generic_vars_map: HashMap<u32, ConstGenericVarId>,
44 pub type_trans_cache: HashMap<hax::Ty, Ty>,
48}
49
50fn translate_region_name(s: String) -> Option<String> {
52 if s == "'_" { None } else { Some(s) }
53}
54
55impl BindingLevel {
56 pub(crate) fn new(is_item_binder: bool) -> Self {
57 Self {
58 is_item_binder,
59 ..Default::default()
60 }
61 }
62
63 pub(crate) fn push_early_region(&mut self, region: hax::EarlyParamRegion) -> RegionId {
65 let name = translate_region_name(region.name.clone());
66 assert!(
68 self.bound_region_vars.is_empty(),
69 "Early regions must be translated before late ones"
70 );
71 let rid = self
72 .params
73 .regions
74 .push_with(|index| RegionParam { index, name });
75 self.early_region_vars.insert(region, rid);
76 rid
77 }
78
79 pub(crate) fn push_bound_region(&mut self, region: hax::BoundRegionKind) -> RegionId {
81 use hax::BoundRegionKind::*;
82 let name = match region {
83 Anon => None,
84 NamedAnon(symbol) | Named(_, symbol) => translate_region_name(symbol.clone()),
85 ClosureEnv => Some("@env".to_owned()),
86 };
87 let rid = self
88 .params
89 .regions
90 .push_with(|index| RegionParam { index, name });
91 self.bound_region_vars.push(rid);
92 rid
93 }
94
95 pub fn push_upvar_region(&mut self) -> RegionId {
97 let region_id = self
100 .params
101 .regions
102 .push_with(|index| RegionParam { index, name: None });
103 self.by_ref_upvar_regions.push(region_id);
104 region_id
105 }
106
107 pub(crate) fn push_type_var(&mut self, rid: u32, name: String) -> TypeVarId {
108 let var_id = self
109 .params
110 .types
111 .push_with(|index| TypeParam { index, name });
112 self.type_vars_map.insert(rid, var_id);
113 var_id
114 }
115
116 pub(crate) fn push_const_generic_var(&mut self, rid: u32, ty: LiteralTy, name: String) {
117 let var_id = self
118 .params
119 .const_generics
120 .push_with(|index| ConstGenericParam { index, name, ty });
121 self.const_generic_vars_map.insert(rid, var_id);
122 }
123
124 pub(crate) fn push_params_from_binder(&mut self, binder: hax::Binder<()>) -> Result<(), Error> {
126 assert!(
127 self.bound_region_vars.is_empty(),
128 "Trying to use two binders at the same binding level"
129 );
130 use hax::BoundVariableKind::*;
131 for p in binder.bound_vars {
132 match p {
133 Region(region) => {
134 self.push_bound_region(region);
135 }
136 Ty(_) => {
137 panic!("Unexpected locally bound type variable");
138 }
139 Const => {
140 panic!("Unexpected locally bound const generic variable");
141 }
142 }
143 }
144 Ok(())
145 }
146}
147
148impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
149 pub(crate) fn the_only_binder(&self) -> &BindingLevel {
151 assert_eq!(self.binding_levels.len(), 1);
152 self.innermost_binder()
153 }
154 pub(crate) fn the_only_binder_mut(&mut self) -> &mut BindingLevel {
156 assert_eq!(self.binding_levels.len(), 1);
157 self.innermost_binder_mut()
158 }
159
160 pub(crate) fn outermost_binder(&self) -> &BindingLevel {
161 self.binding_levels.outermost()
162 }
163 pub(crate) fn outermost_binder_mut(&mut self) -> &mut BindingLevel {
164 self.binding_levels.outermost_mut()
165 }
166 pub(crate) fn innermost_binder(&self) -> &BindingLevel {
167 self.binding_levels.innermost()
168 }
169 pub(crate) fn innermost_binder_mut(&mut self) -> &mut BindingLevel {
170 self.binding_levels.innermost_mut()
171 }
172
173 pub(crate) fn outermost_generics(&self) -> &GenericParams {
174 &self.outermost_binder().params
175 }
176 #[expect(dead_code)]
177 pub(crate) fn outermost_generics_mut(&mut self) -> &mut GenericParams {
178 &mut self.outermost_binder_mut().params
179 }
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 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 args.iter_upvar_borrows().for_each(|_| {
430 self.the_only_binder_mut().push_upvar_region();
431 });
432 if let TransItemSourceKind::TraitImpl(TraitImplSource::Closure(..))
434 | TransItemSourceKind::ClosureMethod(..)
435 | TransItemSourceKind::ClosureAsFnCast = kind
436 {
437 self.innermost_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 .innermost_generics_mut()
444 .regions
445 .push_with(|index| RegionParam { index, name: None });
446 self.innermost_binder_mut().closure_call_method_region = Some(rid);
447 }
448 }
449
450 self.innermost_binder_mut().params.check_consistency();
451 Ok(())
452 }
453
454 pub(crate) fn translate_binder_for_def<F, U>(
457 &mut self,
458 span: Span,
459 kind: BinderKind,
460 def: &hax::FullDef,
461 f: F,
462 ) -> Result<Binder<U>, Error>
463 where
464 F: FnOnce(&mut Self) -> Result<U, Error>,
465 {
466 assert!(!self.binding_levels.is_empty());
467 self.binding_levels.push(BindingLevel::new(true));
468
469 self.push_generics_for_def_without_parents(span, def)?;
471 self.push_late_bound_generics_for_def(span, def)?;
472 self.innermost_binder().params.check_consistency();
473
474 let res = f(self);
476
477 let params = self.binding_levels.pop().unwrap().params;
479
480 res.map(|skip_binder| Binder {
482 kind,
483 params,
484 skip_binder,
485 })
486 }
487
488 pub(crate) fn translate_region_binder<F, T, U>(
492 &mut self,
493 _span: Span,
494 binder: &hax::Binder<T>,
495 f: F,
496 ) -> Result<RegionBinder<U>, Error>
497 where
498 F: FnOnce(&mut Self, &T) -> Result<U, Error>,
499 {
500 assert!(!self.binding_levels.is_empty());
501
502 let mut binding_level = BindingLevel::new(false);
504 binding_level.push_params_from_binder(binder.rebind(()))?;
505 self.binding_levels.push(binding_level);
506
507 let res = f(self, binder.hax_skip_binder_ref());
509
510 let regions = self.binding_levels.pop().unwrap().params.regions;
512
513 res.map(|skip_binder| RegionBinder {
515 regions,
516 skip_binder,
517 })
518 }
519
520 pub(crate) fn into_generics(mut self) -> GenericParams {
521 assert!(self.binding_levels.len() == 1);
522 self.binding_levels.pop().unwrap().params
523 }
524}