1use crate::translate::translate_predicates::PredicateLocation;
2
3use super::translate_ctx::ItemTransCtx;
4use charon_lib::ast::*;
5use charon_lib::common::hash_by_addr::HashByAddr;
6use hax_frontend_exporter as hax;
7use std::collections::HashMap;
8use std::fmt::Debug;
9use std::sync::Arc;
10
11#[derive(Debug, Default)]
23pub(crate) struct BindingLevel {
24 pub params: GenericParams,
26 pub is_item_binder: bool,
30 pub early_region_vars: std::collections::BTreeMap<hax::EarlyParamRegion, RegionId>,
37 pub bound_region_vars: Vec<RegionId>,
39 pub by_ref_upvar_regions: Vec<RegionId>,
41 pub type_vars_map: HashMap<u32, TypeVarId>,
43 pub const_generic_vars_map: HashMap<u32, ConstGenericVarId>,
45 pub type_trans_cache: HashMap<HashByAddr<Arc<hax::TyKind>>, Ty>,
49}
50
51fn translate_region_name(s: String) -> Option<String> {
53 if s == "'_" { None } else { Some(s) }
54}
55
56impl BindingLevel {
57 pub(crate) fn new(is_item_binder: bool) -> Self {
58 Self {
59 is_item_binder,
60 ..Default::default()
61 }
62 }
63
64 pub(crate) fn push_early_region(&mut self, region: hax::EarlyParamRegion) -> RegionId {
66 let name = translate_region_name(region.name.clone());
67 assert!(
69 self.bound_region_vars.is_empty(),
70 "Early regions must be translated before late ones"
71 );
72 let rid = self
73 .params
74 .regions
75 .push_with(|index| RegionVar { index, name });
76 self.early_region_vars.insert(region, rid);
77 rid
78 }
79
80 pub(crate) fn push_bound_region(&mut self, region: hax::BoundRegionKind) -> RegionId {
82 use hax::BoundRegionKind::*;
83 let name = match region {
84 Anon => None,
85 NamedAnon(symbol) | Named(_, symbol) => translate_region_name(symbol.clone()),
86 ClosureEnv => Some("@env".to_owned()),
87 };
88 let rid = self
89 .params
90 .regions
91 .push_with(|index| RegionVar { index, name });
92 self.bound_region_vars.push(rid);
93 rid
94 }
95
96 pub fn push_upvar_region(&mut self) -> RegionId {
98 let region_id = self
101 .params
102 .regions
103 .push_with(|index| RegionVar { index, name: None });
104 self.by_ref_upvar_regions.push(region_id);
105 region_id
106 }
107
108 pub(crate) fn push_type_var(&mut self, rid: u32, name: String) -> TypeVarId {
109 let var_id = self.params.types.push_with(|index| TypeVar { 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| ConstGenericVar { 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
153 pub(crate) fn the_only_binder_mut(&mut self) -> &mut BindingLevel {
155 assert_eq!(self.binding_levels.len(), 1);
156 self.innermost_binder_mut()
157 }
158
159 pub(crate) fn outermost_binder(&self) -> &BindingLevel {
160 self.binding_levels.outermost()
161 }
162
163 pub(crate) fn innermost_binder(&self) -> &BindingLevel {
164 self.binding_levels.innermost()
165 }
166
167 pub(crate) fn innermost_binder_mut(&mut self) -> &mut BindingLevel {
168 self.binding_levels.innermost_mut()
169 }
170
171 pub(crate) fn innermost_generics_mut(&mut self) -> &mut GenericParams {
172 &mut self.innermost_binder_mut().params
173 }
174
175 pub(crate) fn lookup_bound_region(
176 &mut self,
177 span: Span,
178 dbid: hax::DebruijnIndex,
179 var: hax::BoundVar,
180 ) -> Result<RegionDbVar, Error> {
181 let dbid = DeBruijnId::new(dbid);
182 if let Some(rid) = self
183 .binding_levels
184 .get(dbid)
185 .and_then(|bl| bl.bound_region_vars.get(var))
186 {
187 Ok(DeBruijnVar::bound(dbid, *rid))
188 } else {
189 raise_error!(
190 self,
191 span,
192 "Unexpected error: could not find region '{dbid}_{var}"
193 )
194 }
195 }
196
197 pub(crate) fn lookup_param<Id: Copy>(
198 &mut self,
199 span: Span,
200 f: impl for<'a> Fn(&'a BindingLevel) -> Option<Id>,
201 mk_err: impl FnOnce() -> String,
202 ) -> Result<DeBruijnVar<Id>, Error> {
203 for (dbid, bl) in self.binding_levels.iter_enumerated() {
204 if let Some(id) = f(bl) {
205 return Ok(DeBruijnVar::bound(dbid, id));
206 }
207 }
208 let err = mk_err();
209 raise_error!(self, span, "Unexpected error: could not find {}", err)
210 }
211
212 pub(crate) fn lookup_early_region(
213 &mut self,
214 span: Span,
215 region: &hax::EarlyParamRegion,
216 ) -> Result<RegionDbVar, Error> {
217 self.lookup_param(
218 span,
219 |bl| bl.early_region_vars.get(region).copied(),
220 || format!("the region variable {region:?}"),
221 )
222 }
223
224 pub(crate) fn lookup_type_var(
225 &mut self,
226 span: Span,
227 param: &hax::ParamTy,
228 ) -> Result<TypeDbVar, Error> {
229 self.lookup_param(
230 span,
231 |bl| bl.type_vars_map.get(¶m.index).copied(),
232 || format!("the type variable {}", param.name),
233 )
234 }
235
236 pub(crate) fn lookup_const_generic_var(
237 &mut self,
238 span: Span,
239 param: &hax::ParamConst,
240 ) -> Result<ConstGenericDbVar, Error> {
241 self.lookup_param(
242 span,
243 |bl| bl.const_generic_vars_map.get(¶m.index).copied(),
244 || format!("the const generic variable {}", param.name),
245 )
246 }
247
248 pub(crate) fn lookup_clause_var(
249 &mut self,
250 span: Span,
251 mut id: usize,
252 ) -> Result<ClauseDbVar, Error> {
253 let innermost_item_binder_id = self
258 .binding_levels
259 .iter_enumerated()
260 .find(|(_, bl)| bl.is_item_binder)
261 .unwrap()
262 .0;
263 for (dbid, bl) in self.binding_levels.iter_enumerated().rev() {
265 let num_clauses_bound_at_this_level = bl.params.trait_clauses.elem_count();
266 if id < num_clauses_bound_at_this_level || dbid == innermost_item_binder_id {
267 let id = TraitClauseId::from_usize(id);
268 return Ok(DeBruijnVar::bound(dbid, id));
269 } else {
270 id -= num_clauses_bound_at_this_level
271 }
272 }
273 raise_error!(
275 self,
276 span,
277 "Unexpected error: could not find clause variable {}",
278 id
279 )
280 }
281
282 pub(crate) fn push_generic_params(&mut self, generics: &hax::TyGenerics) -> Result<(), Error> {
283 for param in &generics.params {
284 self.push_generic_param(param)?;
285 }
286 Ok(())
287 }
288
289 pub(crate) fn push_generic_param(&mut self, param: &hax::GenericParamDef) -> Result<(), Error> {
290 match ¶m.kind {
291 hax::GenericParamDefKind::Lifetime => {
292 let region = hax::EarlyParamRegion {
293 index: param.index,
294 name: param.name.clone(),
295 };
296 let _ = self.innermost_binder_mut().push_early_region(region);
297 }
298 hax::GenericParamDefKind::Type { .. } => {
299 let _ = self
300 .innermost_binder_mut()
301 .push_type_var(param.index, param.name.clone());
302 }
303 hax::GenericParamDefKind::Const { ty, .. } => {
304 let span = self.def_span(¶m.def_id);
305 let ty = self.translate_ty(span, ty)?;
308 match ty.kind().as_literal() {
309 Some(ty) => self.innermost_binder_mut().push_const_generic_var(
310 param.index,
311 *ty,
312 param.name.clone(),
313 ),
314 None => raise_error!(
315 self,
316 span,
317 "Constant parameters of non-literal type are not supported"
318 ),
319 }
320 }
321 }
322
323 Ok(())
324 }
325
326 #[tracing::instrument(skip(self, span))]
328 fn push_generics_for_def(
329 &mut self,
330 span: Span,
331 def: &hax::FullDef,
332 is_parent: bool,
333 ) -> Result<(), Error> {
334 if let Some(parent_item) = def.typing_parent(self.hax_state()) {
337 let parent_def = self.hax_def(&parent_item)?;
338 self.push_generics_for_def(span, &parent_def, true)?;
339 }
340 self.push_generics_for_def_without_parents(span, def, !is_parent, !is_parent)?;
341 Ok(())
342 }
343
344 fn push_generics_for_def_without_parents(
347 &mut self,
348 _span: Span,
349 def: &hax::FullDef,
350 include_late_bound: bool,
351 include_assoc_ty_clauses: bool,
352 ) -> Result<(), Error> {
353 use hax::FullDefKind;
354 if let Some(param_env) = def.param_env() {
355 self.push_generic_params(¶m_env.generics)?;
357 let origin = match &def.kind {
359 FullDefKind::Adt { .. }
360 | FullDefKind::TyAlias { .. }
361 | FullDefKind::AssocTy { .. } => PredicateOrigin::WhereClauseOnType,
362 FullDefKind::Fn { .. }
363 | FullDefKind::AssocFn { .. }
364 | FullDefKind::Const { .. }
365 | FullDefKind::AssocConst { .. }
366 | FullDefKind::Static { .. } => PredicateOrigin::WhereClauseOnFn,
367 FullDefKind::TraitImpl { .. } | FullDefKind::InherentImpl { .. } => {
368 PredicateOrigin::WhereClauseOnImpl
369 }
370 FullDefKind::Trait { .. } | FullDefKind::TraitAlias { .. } => {
371 PredicateOrigin::WhereClauseOnTrait
372 }
373 _ => panic!("Unexpected def: {def:?}"),
374 };
375 self.register_predicates(
376 ¶m_env.predicates,
377 origin.clone(),
378 &PredicateLocation::Base,
379 )?;
380 if let FullDefKind::Trait {
382 implied_predicates, ..
383 }
384 | FullDefKind::TraitAlias {
385 implied_predicates, ..
386 }
387 | FullDefKind::AssocTy {
388 implied_predicates, ..
389 } = &def.kind
390 {
391 self.register_predicates(implied_predicates, origin, &PredicateLocation::Parent)?;
392 }
393
394 if let hax::FullDefKind::Trait { items, .. } = &def.kind
395 && include_assoc_ty_clauses
396 && !self.monomorphize()
397 {
398 for assoc in items {
402 let item_def = self.poly_hax_def(&assoc.def_id)?;
403 if let hax::FullDefKind::AssocTy {
404 param_env,
405 implied_predicates,
406 ..
407 } = item_def.kind()
408 && param_env.generics.params.is_empty()
409 {
410 let name = self.t_ctx.translate_trait_item_name(item_def.def_id())?;
411 self.register_predicates(
412 &implied_predicates,
413 PredicateOrigin::TraitItem(name.clone()),
414 &PredicateLocation::Item(name),
415 )?;
416 }
417 }
418 }
419 }
420
421 if let hax::FullDefKind::Closure { args, .. } = def.kind()
422 && include_late_bound
423 {
424 args.upvar_tys.iter().for_each(|ty| {
426 if matches!(
427 ty.kind(),
428 hax::TyKind::Ref(
429 hax::Region {
430 kind: hax::RegionKind::ReErased
431 },
432 ..
433 )
434 ) {
435 self.the_only_binder_mut().push_upvar_region();
436 }
437 });
438 }
439
440 let signature = match &def.kind {
449 hax::FullDefKind::Fn { sig, .. } => Some(sig),
450 hax::FullDefKind::AssocFn { sig, .. } => Some(sig),
451 _ => None,
452 };
453 if let Some(signature) = signature
454 && include_late_bound
455 {
456 let innermost_binder = self.innermost_binder_mut();
457 assert!(innermost_binder.bound_region_vars.is_empty());
458 innermost_binder.push_params_from_binder(signature.rebind(()))?;
459 }
460
461 Ok(())
462 }
463
464 pub(crate) fn translate_def_generics(
469 &mut self,
470 span: Span,
471 def: &hax::FullDef,
472 ) -> Result<(), Error> {
473 assert!(self.binding_levels.len() == 0);
474 self.binding_levels.push(BindingLevel::new(true));
475 self.push_generics_for_def(span, def, false)?;
476 self.innermost_binder_mut().params.check_consistency();
477 Ok(())
478 }
479
480 pub(crate) fn translate_def_generics_without_parents(
482 &mut self,
483 span: Span,
484 def: &hax::FullDef,
485 ) -> Result<(), Error> {
486 self.binding_levels.push(BindingLevel::new(true));
487 self.push_generics_for_def_without_parents(span, def, true, true)?;
488 self.innermost_binder().params.check_consistency();
489 Ok(())
490 }
491
492 pub(crate) fn translate_binder_for_def<F, U>(
495 &mut self,
496 span: Span,
497 kind: BinderKind,
498 def: &hax::FullDef,
499 f: F,
500 ) -> Result<Binder<U>, Error>
501 where
502 F: FnOnce(&mut Self) -> Result<U, Error>,
503 {
504 assert!(!self.binding_levels.is_empty());
505
506 self.translate_def_generics_without_parents(span, def)?;
508
509 let res = f(self);
511
512 let params = self.binding_levels.pop().unwrap().params;
514
515 res.map(|skip_binder| Binder {
517 kind,
518 params,
519 skip_binder,
520 })
521 }
522
523 pub(crate) fn translate_region_binder<F, T, U>(
527 &mut self,
528 _span: Span,
529 binder: &hax::Binder<T>,
530 f: F,
531 ) -> Result<RegionBinder<U>, Error>
532 where
533 F: FnOnce(&mut Self, &T) -> Result<U, Error>,
534 {
535 assert!(!self.binding_levels.is_empty());
536
537 let mut binding_level = BindingLevel::new(false);
539 binding_level.push_params_from_binder(binder.rebind(()))?;
540 self.binding_levels.push(binding_level);
541
542 let res = f(self, binder.hax_skip_binder_ref());
544
545 let regions = self.binding_levels.pop().unwrap().params.regions;
547
548 res.map(|skip_binder| RegionBinder {
550 regions,
551 skip_binder,
552 })
553 }
554
555 pub(crate) fn into_generics(mut self) -> GenericParams {
556 assert!(self.binding_levels.len() == 1);
557 self.binding_levels.pop().unwrap().params
558 }
559}