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::ImplExprAtom;
193
194 let trait_ref = match &impl_source.r#impl {
195 ImplExprAtom::Concrete(item) => {
196 let impl_ref = self.translate_trait_impl_ref(span, item)?;
197 TraitRef {
198 kind: TraitRefKind::TraitImpl(impl_ref),
199 trait_decl_ref,
200 }
201 }
202 ImplExprAtom::SelfImpl {
203 r#trait: trait_ref,
204 path,
205 }
206 | ImplExprAtom::LocalBound {
207 r#trait: trait_ref,
208 path,
209 ..
210 } => {
211 trace!(
212 "impl source (self or clause): param:\n- trait_ref: {:?}\n- path: {:?}",
213 trait_ref,
214 path,
215 );
216 let mut trait_id = match &impl_source.r#impl {
218 ImplExprAtom::SelfImpl { .. } => match self.self_clause_id {
219 None => TraitRefKind::SelfId,
220 Some(id) => TraitRefKind::Clause(DeBruijnVar::bound(
223 self.binding_levels.depth(),
224 id,
225 )),
226 },
227 ImplExprAtom::LocalBound { index, .. } => {
228 let var = self.lookup_clause_var(span, *index)?;
229 TraitRefKind::Clause(var)
230 }
231 _ => unreachable!(),
232 };
233
234 let mut current_trait_decl_id =
235 self.register_trait_decl_id(span, &trait_ref.hax_skip_binder_ref().def_id);
236
237 for path_elem in path {
239 use hax::ImplExprPathChunk::*;
240 match path_elem {
241 AssocItem {
242 item,
243 predicate,
244 index,
245 ..
246 } => {
247 let name = self.t_ctx.translate_trait_item_name(&item.def_id)?;
248 if !item.generic_args.is_empty() {
249 raise_error!(
250 self,
251 span,
252 "Found unsupported GAT `{}` when resolving trait `{}`",
253 name,
254 trait_decl_ref.with_ctx(&self.into_fmt())
255 )
256 }
257 trait_id = TraitRefKind::ItemClause(
258 Box::new(trait_id),
259 current_trait_decl_id,
260 name,
261 TraitClauseId::new(*index),
262 );
263 current_trait_decl_id = self.register_trait_decl_id(
264 span,
265 &predicate.hax_skip_binder_ref().trait_ref.def_id,
266 );
267 }
268 Parent {
269 predicate, index, ..
270 } => {
271 trait_id = TraitRefKind::ParentClause(
272 Box::new(trait_id),
273 current_trait_decl_id,
274 TraitClauseId::new(*index),
275 );
276 current_trait_decl_id = self.register_trait_decl_id(
277 span,
278 &predicate.hax_skip_binder_ref().trait_ref.def_id,
279 );
280 }
281 }
282 }
283
284 TraitRef {
287 kind: trait_id,
288 trait_decl_ref,
289 }
290 }
291 ImplExprAtom::Dyn => TraitRef {
292 kind: TraitRefKind::Dyn(trait_decl_ref.clone()),
293 trait_decl_ref,
294 },
295 ImplExprAtom::Builtin {
296 impl_exprs, types, ..
297 } => {
298 let trait_def_id = &impl_source.r#trait.hax_skip_binder_ref().def_id;
299 let trait_def = self.hax_def(trait_def_id)?;
300 let closure_kind = trait_def.lang_item.as_deref().and_then(|lang| match lang {
301 "fn_once" => Some(ClosureKind::FnOnce),
302 "fn_mut" => Some(ClosureKind::FnMut),
303 "r#fn" => Some(ClosureKind::Fn),
304 _ => None,
305 });
306
307 let kind = if let Some(closure_kind) = closure_kind
308 && let Some(hax::GenericArg::Type(closure_ty)) = impl_source
309 .r#trait
310 .hax_skip_binder_ref()
311 .generic_args
312 .first()
313 && let hax::TyKind::Closure(closure_args) = closure_ty.kind()
314 {
315 let binder =
316 self.translate_region_binder(span, &impl_source.r#trait, |ctx, _tref| {
317 ctx.translate_closure_impl_ref(span, closure_args, closure_kind)
318 })?;
319 TraitRefKind::TraitImpl(binder.erase())
320 } else if let hax::FullDefKind::TraitAlias { .. } = trait_def.kind() {
321 let impl_id = self.register_trait_impl_id(span, trait_def_id);
323 let mut generics = trait_decl_ref.clone().erase().generics;
324 assert!(
325 generics.trait_refs.is_empty(),
326 "found trait alias with non-empty required predicates"
327 );
328 generics.trait_refs = self.translate_trait_impl_exprs(span, &impl_exprs)?;
329 TraitRefKind::TraitImpl(TraitImplRef {
330 id: impl_id,
331 generics,
332 })
333 } else {
334 let parent_trait_refs = self.translate_trait_impl_exprs(span, &impl_exprs)?;
335 let types = types
336 .iter()
337 .map(|(def_id, ty)| {
338 let name = self.t_ctx.translate_trait_item_name(def_id)?;
339 let ty = self.translate_ty(span, ty)?;
340 Ok((name, ty))
341 })
342 .try_collect()?;
343 TraitRefKind::BuiltinOrAuto {
344 trait_decl_ref: trait_decl_ref.clone(),
345 parent_trait_refs,
346 types,
347 }
348 };
349 TraitRef {
350 kind,
351 trait_decl_ref,
352 }
353 }
354 ImplExprAtom::Error(msg) => {
355 let trait_ref = TraitRef {
356 kind: TraitRefKind::Unknown(msg.clone()),
357 trait_decl_ref,
358 };
359 if self.error_on_impl_expr_error {
360 register_error!(self, span, "Error during trait resolution: {}", msg);
361 }
362 trait_ref
363 }
364 ImplExprAtom::Drop(..) => {
365 raise_error!(self, span, "Unsupported predicate: drop glue")
366 }
367 };
368 Ok(trait_ref)
369 }
370}