1use super::translate_ctx::*;
2use charon_lib::ast::*;
3use charon_lib::formatter::IntoFormatter;
4use charon_lib::ids::Vector;
5use charon_lib::pretty::FmtWithCtx;
6use hax_frontend_exporter as hax;
7
8pub(crate) enum PredicateLocation {
11 Parent,
13 Item(TraitItemName),
15 Base,
17}
18
19impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
20 pub(crate) fn register_predicates(
23 &mut self,
24 preds: &hax::GenericPredicates,
25 origin: PredicateOrigin,
26 location: &PredicateLocation,
27 ) -> Result<(), Error> {
28 for (clause, span) in &preds.predicates {
32 if matches!(clause.kind.value, hax::ClauseKind::Trait(_)) {
33 self.register_predicate(clause, span, origin.clone(), location)?;
34 }
35 }
36 for (clause, span) in &preds.predicates {
37 if !matches!(clause.kind.value, hax::ClauseKind::Trait(_)) {
38 self.register_predicate(clause, span, origin.clone(), location)?;
39 }
40 }
41 Ok(())
42 }
43
44 pub(crate) fn translate_poly_trait_ref(
45 &mut self,
46 span: Span,
47 bound_trait_ref: &hax::Binder<hax::TraitRef>,
48 ) -> Result<PolyTraitDeclRef, Error> {
49 self.translate_region_binder(span, bound_trait_ref, move |ctx, trait_ref| {
50 ctx.translate_trait_ref(span, trait_ref)
51 })
52 }
53
54 pub(crate) fn translate_trait_predicate(
55 &mut self,
56 span: Span,
57 trait_pred: &hax::TraitPredicate,
58 ) -> Result<TraitDeclRef, Error> {
59 assert!(trait_pred.is_positive);
61 self.translate_trait_ref(span, &trait_pred.trait_ref)
62 }
63
64 pub(crate) fn translate_trait_ref(
65 &mut self,
66 span: Span,
67 trait_ref: &hax::TraitRef,
68 ) -> Result<TraitDeclRef, Error> {
69 self.translate_trait_decl_ref(span, trait_ref)
70 }
71
72 pub(crate) fn register_predicate(
73 &mut self,
74 clause: &hax::Clause,
75 hspan: &hax::Span,
76 origin: PredicateOrigin,
77 location: &PredicateLocation,
78 ) -> Result<(), Error> {
79 use hax::ClauseKind;
80 trace!("{:?}", clause);
81 let span = self.translate_span_from_hax(hspan);
82 match clause.kind.hax_skip_binder_ref() {
83 ClauseKind::Trait(trait_pred) => {
84 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
85 ctx.translate_trait_predicate(span, trait_pred)
86 })?;
87 let location = match location {
88 PredicateLocation::Base => &mut self.innermost_generics_mut().trait_clauses,
89 PredicateLocation::Parent => &mut self.parent_trait_clauses,
90 PredicateLocation::Item(item_name) => self
91 .item_trait_clauses
92 .entry(item_name.clone())
93 .or_default(),
94 };
95 location.push_with(|clause_id| TraitClause {
96 clause_id,
97 origin,
98 span: Some(span),
99 trait_: pred,
100 });
101 }
102 ClauseKind::RegionOutlives(p) => {
103 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
104 let r0 = ctx.translate_region(span, &p.lhs)?;
105 let r1 = ctx.translate_region(span, &p.rhs)?;
106 Ok(OutlivesPred(r0, r1))
107 })?;
108 self.innermost_generics_mut().regions_outlive.push(pred);
109 }
110 ClauseKind::TypeOutlives(p) => {
111 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
112 let ty = ctx.translate_ty(span, &p.lhs)?;
113 let r = ctx.translate_region(span, &p.rhs)?;
114 Ok(OutlivesPred(ty, r))
115 })?;
116 self.innermost_generics_mut().types_outlive.push(pred);
117 }
118 ClauseKind::Projection(p) => {
119 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
126 let trait_ref = ctx.translate_trait_impl_expr(span, &p.impl_expr)?;
127 let ty = ctx.translate_ty(span, &p.ty)?;
128 let type_name = ctx.t_ctx.translate_trait_item_name(&p.assoc_item.def_id)?;
129 Ok(TraitTypeConstraint {
130 trait_ref,
131 type_name,
132 ty,
133 })
134 })?;
135 self.innermost_generics_mut()
136 .trait_type_constraints
137 .push(pred);
138 }
139 ClauseKind::ConstArgHasType(..) => {
140 }
144 ClauseKind::WellFormed(_) => {
145 raise_error!(self, span, "Well-formedness clauses are unsupported")
146 }
147 kind => {
148 raise_error!(self, span, "Unsupported clause: {:?}", kind)
149 }
150 }
151 Ok(())
152 }
153
154 pub(crate) fn translate_trait_impl_exprs(
155 &mut self,
156 span: Span,
157 impl_sources: &[hax::ImplExpr],
158 ) -> Result<Vector<TraitClauseId, TraitRef>, Error> {
159 impl_sources
160 .iter()
161 .map(|x| self.translate_trait_impl_expr(span, x))
162 .try_collect()
163 }
164
165 #[tracing::instrument(skip(self, span, impl_expr))]
166 pub(crate) fn translate_trait_impl_expr(
167 &mut self,
168 span: Span,
169 impl_expr: &hax::ImplExpr,
170 ) -> Result<TraitRef, Error> {
171 let trait_decl_ref = self.translate_poly_trait_ref(span, &impl_expr.r#trait)?;
172
173 match self.translate_trait_impl_expr_aux(span, impl_expr, trait_decl_ref.clone()) {
174 Ok(res) => Ok(res),
175 Err(err) => {
176 register_error!(self, span, "Error during trait resolution: {}", &err.msg);
177 Ok(TraitRef {
178 kind: TraitRefKind::Unknown(err.msg),
179 trait_decl_ref,
180 })
181 }
182 }
183 }
184
185 pub(crate) fn translate_trait_impl_expr_aux(
186 &mut self,
187 span: Span,
188 impl_source: &hax::ImplExpr,
189 trait_decl_ref: PolyTraitDeclRef,
190 ) -> Result<TraitRef, Error> {
191 trace!("impl_expr: {:#?}", impl_source);
192 use hax::DropData;
193 use hax::ImplExprAtom;
194
195 let trait_ref = match &impl_source.r#impl {
196 ImplExprAtom::Concrete(item) => {
197 let impl_ref = self.translate_trait_impl_ref(span, item)?;
198 TraitRef {
199 kind: TraitRefKind::TraitImpl(impl_ref),
200 trait_decl_ref,
201 }
202 }
203 ImplExprAtom::SelfImpl {
204 r#trait: trait_ref,
205 path,
206 }
207 | ImplExprAtom::LocalBound {
208 r#trait: trait_ref,
209 path,
210 ..
211 } => {
212 trace!(
213 "impl source (self or clause): param:\n- trait_ref: {:?}\n- path: {:?}",
214 trait_ref, path,
215 );
216 let mut trait_id = match &impl_source.r#impl {
218 ImplExprAtom::SelfImpl { .. } => TraitRefKind::SelfId,
219 ImplExprAtom::LocalBound { index, .. } => {
220 let var = self.lookup_clause_var(span, *index)?;
221 TraitRefKind::Clause(var)
222 }
223 _ => unreachable!(),
224 };
225
226 let mut current_trait_decl_id =
227 self.register_trait_decl_id(span, &trait_ref.hax_skip_binder_ref().def_id);
228
229 for path_elem in path {
231 use hax::ImplExprPathChunk::*;
232 match path_elem {
233 AssocItem {
234 item,
235 predicate,
236 index,
237 ..
238 } => {
239 let name = self.t_ctx.translate_trait_item_name(&item.def_id)?;
240 if !item.generic_args.is_empty() {
241 raise_error!(
242 self,
243 span,
244 "Found unsupported GAT `{}` when resolving trait `{}`",
245 name,
246 trait_decl_ref.with_ctx(&self.into_fmt())
247 )
248 }
249 trait_id = TraitRefKind::ItemClause(
250 Box::new(trait_id),
251 current_trait_decl_id,
252 name,
253 TraitClauseId::new(*index),
254 );
255 current_trait_decl_id = self.register_trait_decl_id(
256 span,
257 &predicate.hax_skip_binder_ref().trait_ref.def_id,
258 );
259 }
260 Parent {
261 predicate, index, ..
262 } => {
263 trait_id = TraitRefKind::ParentClause(
264 Box::new(trait_id),
265 current_trait_decl_id,
266 TraitClauseId::new(*index),
267 );
268 current_trait_decl_id = self.register_trait_decl_id(
269 span,
270 &predicate.hax_skip_binder_ref().trait_ref.def_id,
271 );
272 }
273 }
274 }
275
276 TraitRef {
279 kind: trait_id,
280 trait_decl_ref,
281 }
282 }
283 ImplExprAtom::Dyn => TraitRef {
284 kind: TraitRefKind::Dyn(trait_decl_ref.clone()),
285 trait_decl_ref,
286 },
287 ImplExprAtom::Builtin {
288 impl_exprs, types, ..
289 } => {
290 let trait_def_id = &impl_source.r#trait.hax_skip_binder_ref().def_id;
291 let trait_def = self.hax_def(trait_def_id)?;
292 let closure_kind = trait_def.lang_item.as_deref().and_then(|lang| match lang {
293 "fn_once" => Some(ClosureKind::FnOnce),
294 "fn_mut" => Some(ClosureKind::FnMut),
295 "r#fn" => Some(ClosureKind::Fn),
296 _ => None,
297 });
298
299 let kind = if let Some(closure_kind) = closure_kind
302 && let Some(hax::GenericArg::Type(closure_ty)) = impl_source
303 .r#trait
304 .hax_skip_binder_ref()
305 .generic_args
306 .first()
307 && let hax::TyKind::Closure(closure_args) = closure_ty.kind()
308 {
309 let binder =
310 self.translate_region_binder(span, &impl_source.r#trait, |ctx, _tref| {
311 ctx.translate_closure_impl_ref(span, closure_args, closure_kind)
312 })?;
313 TraitRefKind::TraitImpl(binder.erase())
314 } else if let hax::FullDefKind::TraitAlias { .. } = trait_def.kind() {
315 let impl_id = self.register_trait_impl_id(span, trait_def_id);
317 let mut generics = trait_decl_ref.clone().erase().generics;
318 assert!(
319 generics.trait_refs.is_empty(),
320 "found trait alias with non-empty required predicates"
321 );
322 generics.trait_refs = self.translate_trait_impl_exprs(span, &impl_exprs)?;
323 TraitRefKind::TraitImpl(TraitImplRef {
324 id: impl_id,
325 generics,
326 })
327 } else {
328 let parent_trait_refs = self.translate_trait_impl_exprs(span, &impl_exprs)?;
329 let types = types
330 .iter()
331 .map(|(def_id, ty, impl_exprs)| {
332 let name = self.t_ctx.translate_trait_item_name(def_id)?;
333 let ty = self.translate_ty(span, ty)?;
334 let trait_refs = self.translate_trait_impl_exprs(span, impl_exprs)?;
335 Ok((name, ty, trait_refs))
336 })
337 .try_collect()?;
338 TraitRefKind::BuiltinOrAuto {
339 trait_decl_ref: trait_decl_ref.clone(),
340 parent_trait_refs,
341 types,
342 }
343 };
344 TraitRef {
345 kind,
346 trait_decl_ref,
347 }
348 }
349 ImplExprAtom::Drop(DropData::Glue { ty, .. })
350 if let hax::TyKind::Adt(item) = ty.kind() =>
351 {
352 let impl_ref = self.translate_drop_trait_impl_ref(span, item)?;
353 TraitRef {
354 kind: TraitRefKind::TraitImpl(impl_ref),
355 trait_decl_ref,
356 }
357 }
358 ImplExprAtom::Drop(..) => {
359 let meta_sized_trait = self.get_lang_item(rustc_hir::LangItem::MetaSized);
360 let meta_sized_trait = self.register_trait_decl_id(span, &meta_sized_trait);
361 let self_ty = trait_decl_ref.clone().erase().generics.types[0].clone();
362 TraitRef {
363 kind: TraitRefKind::BuiltinOrAuto {
364 trait_decl_ref: trait_decl_ref.clone(),
365 parent_trait_refs: [TraitRef::new_builtin(
366 meta_sized_trait,
367 self_ty,
368 Default::default(),
369 )]
370 .into(),
371 types: vec![],
372 },
373 trait_decl_ref,
374 }
375 }
376 ImplExprAtom::Error(msg) => {
377 let trait_ref = TraitRef {
378 kind: TraitRefKind::Unknown(msg.clone()),
379 trait_decl_ref,
380 };
381 if self.error_on_impl_expr_error {
382 register_error!(self, span, "Error during trait resolution: {}", msg);
383 }
384 trait_ref
385 }
386 };
387 Ok(trait_ref)
388 }
389}