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_poly_trait_predicate(
55 &mut self,
56 span: Span,
57 bound_trait_ref: &hax::Binder<hax::TraitPredicate>,
58 ) -> Result<PolyTraitDeclRef, Error> {
59 self.translate_region_binder(span, bound_trait_ref, move |ctx, trait_ref| {
60 ctx.translate_trait_predicate(span, trait_ref)
61 })
62 }
63
64 pub(crate) fn translate_trait_predicate(
65 &mut self,
66 span: Span,
67 trait_pred: &hax::TraitPredicate,
68 ) -> Result<TraitDeclRef, Error> {
69 assert!(trait_pred.is_positive);
71 self.translate_trait_ref(span, &trait_pred.trait_ref)
72 }
73
74 pub(crate) fn translate_trait_ref(
75 &mut self,
76 span: Span,
77 trait_ref: &hax::TraitRef,
78 ) -> Result<TraitDeclRef, Error> {
79 self.translate_trait_decl_ref(span, trait_ref)
80 }
81
82 pub(crate) fn register_predicate(
83 &mut self,
84 clause: &hax::Clause,
85 hspan: &hax::Span,
86 origin: PredicateOrigin,
87 location: &PredicateLocation,
88 ) -> Result<(), Error> {
89 use hax::ClauseKind;
90 trace!("{:?}", clause);
91 let span = self.translate_span_from_hax(hspan);
92 match clause.kind.hax_skip_binder_ref() {
93 ClauseKind::Trait(trait_pred) => {
94 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
95 ctx.translate_trait_predicate(span, trait_pred)
96 })?;
97 let location = match location {
98 PredicateLocation::Base => &mut self.innermost_generics_mut().trait_clauses,
99 PredicateLocation::Parent => &mut self.parent_trait_clauses,
100 PredicateLocation::Item(item_name) => self
101 .item_trait_clauses
102 .entry(item_name.clone())
103 .or_default(),
104 };
105 location.push_with(|clause_id| TraitClause {
106 clause_id,
107 origin,
108 span: Some(span),
109 trait_: pred,
110 });
111 }
112 ClauseKind::RegionOutlives(p) => {
113 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
114 let r0 = ctx.translate_region(span, &p.lhs)?;
115 let r1 = ctx.translate_region(span, &p.rhs)?;
116 Ok(OutlivesPred(r0, r1))
117 })?;
118 self.innermost_generics_mut().regions_outlive.push(pred);
119 }
120 ClauseKind::TypeOutlives(p) => {
121 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
122 let ty = ctx.translate_ty(span, &p.lhs)?;
123 let r = ctx.translate_region(span, &p.rhs)?;
124 Ok(OutlivesPred(ty, r))
125 })?;
126 self.innermost_generics_mut().types_outlive.push(pred);
127 }
128 ClauseKind::Projection(p) => {
129 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
136 let trait_ref = ctx.translate_trait_impl_expr(span, &p.impl_expr)?;
137 let ty = ctx.translate_ty(span, &p.ty)?;
138 let type_name = ctx.t_ctx.translate_trait_item_name(&p.assoc_item.def_id)?;
139 Ok(TraitTypeConstraint {
140 trait_ref,
141 type_name,
142 ty,
143 })
144 })?;
145 self.innermost_generics_mut()
146 .trait_type_constraints
147 .push(pred);
148 }
149 ClauseKind::ConstArgHasType(..) => {
150 }
154 ClauseKind::WellFormed(_) => {
155 raise_error!(self, span, "Well-formedness clauses are unsupported")
156 }
157 kind => {
158 raise_error!(self, span, "Unsupported clause: {:?}", kind)
159 }
160 }
161 Ok(())
162 }
163
164 pub(crate) fn translate_trait_impl_exprs(
165 &mut self,
166 span: Span,
167 impl_sources: &[hax::ImplExpr],
168 ) -> Result<Vector<TraitClauseId, TraitRef>, Error> {
169 impl_sources
170 .iter()
171 .map(|x| self.translate_trait_impl_expr(span, x))
172 .try_collect()
173 }
174
175 #[tracing::instrument(skip(self, span, impl_expr))]
176 pub(crate) fn translate_trait_impl_expr(
177 &mut self,
178 span: Span,
179 impl_expr: &hax::ImplExpr,
180 ) -> Result<TraitRef, Error> {
181 let trait_decl_ref = self.translate_poly_trait_ref(span, &impl_expr.r#trait)?;
182
183 match self.translate_trait_impl_expr_aux(span, impl_expr, trait_decl_ref.clone()) {
184 Ok(res) => Ok(res),
185 Err(err) => {
186 register_error!(self, span, "Error during trait resolution: {}", &err.msg);
187 Ok(TraitRef {
188 kind: TraitRefKind::Unknown(err.msg),
189 trait_decl_ref,
190 })
191 }
192 }
193 }
194
195 pub(crate) fn translate_trait_impl_expr_aux(
196 &mut self,
197 span: Span,
198 impl_source: &hax::ImplExpr,
199 trait_decl_ref: PolyTraitDeclRef,
200 ) -> Result<TraitRef, Error> {
201 trace!("impl_expr: {:#?}", impl_source);
202 use hax::DropData;
203 use hax::ImplExprAtom;
204
205 let trait_ref = match &impl_source.r#impl {
206 ImplExprAtom::Concrete(item) => {
207 let impl_ref =
208 self.translate_trait_impl_ref(span, item, TraitImplSource::Normal)?;
209 TraitRef {
210 kind: TraitRefKind::TraitImpl(impl_ref),
211 trait_decl_ref,
212 }
213 }
214 ImplExprAtom::SelfImpl {
215 r#trait: trait_ref,
216 path,
217 }
218 | ImplExprAtom::LocalBound {
219 r#trait: trait_ref,
220 path,
221 ..
222 } => {
223 trace!(
224 "impl source (self or clause): param:\n- trait_ref: {:?}\n- path: {:?}",
225 trait_ref, path,
226 );
227 let mut tref_kind = match &impl_source.r#impl {
229 ImplExprAtom::SelfImpl { .. } => TraitRefKind::SelfId,
230 ImplExprAtom::LocalBound { index, .. } => {
231 let var = self.lookup_clause_var(span, *index)?;
232 TraitRefKind::Clause(var)
233 }
234 _ => unreachable!(),
235 };
236
237 let mut current_pred = self.translate_poly_trait_ref(span, trait_ref)?;
238
239 for path_elem in path {
241 use hax::ImplExprPathChunk::*;
242 let trait_ref = Box::new(TraitRef {
243 kind: tref_kind,
244 trait_decl_ref: current_pred,
245 });
246 match path_elem {
247 AssocItem {
248 item,
249 predicate,
250 index,
251 ..
252 } => {
253 let name = self.t_ctx.translate_trait_item_name(&item.def_id)?;
254 if !item.generic_args.is_empty() {
255 raise_error!(
256 self,
257 span,
258 "Found unsupported GAT `{}` when resolving trait `{}`",
259 name,
260 trait_decl_ref.with_ctx(&self.into_fmt())
261 )
262 }
263 tref_kind = TraitRefKind::ItemClause(
264 trait_ref,
265 name,
266 TraitClauseId::new(*index),
267 );
268 current_pred = self.translate_poly_trait_predicate(span, predicate)?;
269 }
270 Parent {
271 predicate, index, ..
272 } => {
273 tref_kind =
274 TraitRefKind::ParentClause(trait_ref, TraitClauseId::new(*index));
275 current_pred = self.translate_poly_trait_predicate(span, predicate)?;
276 }
277 }
278 }
279
280 TraitRef {
281 kind: tref_kind,
282 trait_decl_ref,
283 }
284 }
285 ImplExprAtom::Dyn => TraitRef {
286 kind: TraitRefKind::Dyn(trait_decl_ref.clone()),
287 trait_decl_ref,
288 },
289 ImplExprAtom::Builtin {
290 trait_data,
291 impl_exprs,
292 types,
293 ..
294 } => {
295 let tref = &impl_source.r#trait;
296 let trait_def =
297 self.hax_def(&tref.hax_skip_binder_ref().erase(&self.hax_state_with_id()))?;
298 let closure_kind = trait_def.lang_item.as_deref().and_then(|lang| match lang {
299 "fn_once" => Some(ClosureKind::FnOnce),
300 "fn_mut" => Some(ClosureKind::FnMut),
301 "r#fn" => Some(ClosureKind::Fn),
302 _ => None,
303 });
304
305 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_item(
323 span,
324 tref.hax_skip_binder_ref(),
325 TransItemSourceKind::TraitImpl(TraitImplSource::TraitAlias),
326 );
327 let mut generics = trait_decl_ref.clone().erase().generics;
328 assert!(
329 generics.trait_refs.is_empty(),
330 "found trait alias with non-empty required predicates"
331 );
332 generics.trait_refs = self.translate_trait_impl_exprs(span, &impl_exprs)?;
333 TraitRefKind::TraitImpl(TraitImplRef {
334 id: impl_id,
335 generics,
336 })
337 } else if let hax::BuiltinTraitData::Drop(DropData::Glue { ty, .. }) = trait_data
338 && let hax::TyKind::Adt(item) = ty.kind()
339 {
340 let impl_ref =
341 self.translate_trait_impl_ref(span, item, TraitImplSource::DropGlue)?;
342 TraitRefKind::TraitImpl(impl_ref)
343 } else {
344 let parent_trait_refs = self.translate_trait_impl_exprs(span, &impl_exprs)?;
345 let types = types
346 .iter()
347 .map(|(def_id, ty, impl_exprs)| -> Result<_, Error> {
348 let name = self.t_ctx.translate_trait_item_name(def_id)?;
349 let ty = self.translate_ty(span, ty)?;
350 let trait_refs = self.translate_trait_impl_exprs(span, impl_exprs)?;
351 Ok((name, ty, trait_refs))
352 })
353 .try_collect()?;
354 TraitRefKind::BuiltinOrAuto {
355 trait_decl_ref: trait_decl_ref.clone(),
356 parent_trait_refs,
357 types,
358 }
359 };
360 TraitRef {
361 kind,
362 trait_decl_ref,
363 }
364 }
365 ImplExprAtom::Error(msg) => {
366 let trait_ref = TraitRef {
367 kind: TraitRefKind::Unknown(msg.clone()),
368 trait_decl_ref,
369 };
370 if self.error_on_impl_expr_error {
371 register_error!(self, span, "Error during trait resolution: {}", msg);
372 }
373 trait_ref
374 }
375 };
376 Ok(trait_ref)
377 }
378}