1use super::translate_ctx::*;
2use charon_lib::ast::*;
3use charon_lib::ids::IndexMap;
4use rustc_span::{kw, sym};
5
6impl<'tcx> TranslateCtx<'tcx> {
7 pub fn recognize_builtin_impl(
8 &self,
9 trait_data: &hax::BuiltinTraitData,
10 trait_def: &hax::FullDef,
11 ) -> Option<BuiltinImplData> {
12 Some(match trait_data {
13 hax::BuiltinTraitData::Destruct(x) => {
14 match x {
15 hax::DestructData::Noop => BuiltinImplData::NoopDestruct,
16 hax::DestructData::Implicit => BuiltinImplData::UntrackedDestruct,
17 hax::DestructData::Glue { .. } => return None,
19 }
20 }
21 hax::BuiltinTraitData::Other => match &trait_def.lang_item {
22 _ if self
23 .tcx
24 .trait_is_auto(trait_def.def_id().real_rust_def_id()) =>
25 {
26 BuiltinImplData::Auto
27 }
28 None => return None,
29 Some(litem) => match *litem {
30 sym::sized => BuiltinImplData::Sized,
31 sym::meta_sized => BuiltinImplData::MetaSized,
32 sym::tuple_trait => BuiltinImplData::Tuple,
33 kw::Fn => BuiltinImplData::Fn,
34 sym::fn_mut => BuiltinImplData::FnMut,
35 sym::fn_once => BuiltinImplData::FnOnce,
36 sym::pointee_trait => BuiltinImplData::Pointee,
37 sym::clone => BuiltinImplData::Clone,
38 sym::copy => BuiltinImplData::Copy,
39 sym::discriminant_kind => BuiltinImplData::DiscriminantKind,
40 _ => return None,
41 },
42 },
43 })
44 }
45}
46
47impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
48 pub(crate) fn register_predicates(
54 &mut self,
55 preds: &hax::GenericPredicates,
56 origin: PredicateOrigin,
57 ) -> Result<(), Error> {
58 let preds = self.translate_predicates(preds, origin)?;
59 self.innermost_generics_mut().take_predicates_from(preds);
60 Ok(())
61 }
62
63 pub(crate) fn translate_predicates(
68 &mut self,
69 preds: &hax::GenericPredicates,
70 origin: PredicateOrigin,
71 ) -> Result<GenericParams, Error> {
72 let mut out = GenericParams::empty();
73 for (clause, span) in &preds.predicates {
77 if matches!(clause.kind.value, hax::ClauseKind::Trait(_)) {
78 self.translate_predicate(clause, span, origin.clone(), &mut out)?;
79 }
80 }
81 for (clause, span) in &preds.predicates {
82 if !matches!(clause.kind.value, hax::ClauseKind::Trait(_)) {
83 self.translate_predicate(clause, span, origin.clone(), &mut out)?;
84 }
85 }
86 Ok(out)
87 }
88
89 pub(crate) fn translate_poly_trait_ref(
90 &mut self,
91 span: Span,
92 bound_trait_ref: &hax::Binder<hax::TraitRef>,
93 ) -> Result<PolyTraitDeclRef, Error> {
94 self.translate_region_binder(span, bound_trait_ref, move |ctx, trait_ref| {
95 ctx.translate_trait_ref(span, trait_ref)
96 })
97 }
98
99 pub(crate) fn translate_poly_trait_predicate(
100 &mut self,
101 span: Span,
102 bound_trait_ref: &hax::Binder<hax::TraitPredicate>,
103 ) -> Result<PolyTraitDeclRef, Error> {
104 self.translate_region_binder(span, bound_trait_ref, move |ctx, trait_ref| {
105 ctx.translate_trait_predicate(span, trait_ref)
106 })
107 }
108
109 pub(crate) fn translate_trait_predicate(
110 &mut self,
111 span: Span,
112 trait_pred: &hax::TraitPredicate,
113 ) -> Result<TraitDeclRef, Error> {
114 assert!(trait_pred.is_positive);
116 self.translate_trait_ref(span, &trait_pred.trait_ref)
117 }
118
119 pub(crate) fn translate_trait_ref(
120 &mut self,
121 span: Span,
122 trait_ref: &hax::TraitRef,
123 ) -> Result<TraitDeclRef, Error> {
124 self.translate_trait_decl_ref(span, trait_ref)
125 }
126
127 pub(crate) fn translate_predicate(
128 &mut self,
129 clause: &hax::Clause,
130 hspan: &hax::Span,
131 origin: PredicateOrigin,
132 into: &mut GenericParams,
133 ) -> Result<(), Error> {
134 use hax::ClauseKind;
135 trace!("{:?}", clause);
136 let span = self.translate_span(hspan);
137 match clause.kind.hax_skip_binder_ref() {
138 ClauseKind::Trait(trait_pred) => {
139 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
140 ctx.translate_trait_predicate(span, trait_pred)
141 })?;
142 into.trait_clauses.push_with(|clause_id| TraitParam {
143 clause_id,
144 origin,
145 span: Some(span),
146 trait_: pred,
147 });
148 }
149 ClauseKind::RegionOutlives(p) => {
150 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
151 let r0 = ctx.translate_region(span, &p.lhs)?;
152 let r1 = ctx.translate_region(span, &p.rhs)?;
153 Ok(OutlivesPred(r0, r1))
154 })?;
155 into.regions_outlive.push(pred);
156 }
157 ClauseKind::TypeOutlives(p) => {
158 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
159 let ty = ctx.translate_ty(span, &p.lhs)?;
160 let r = ctx.translate_region(span, &p.rhs)?;
161 Ok(OutlivesPred(ty, r))
162 })?;
163 into.types_outlive.push(pred);
164 }
165 ClauseKind::Projection(p) => {
166 let pred = self.translate_region_binder(span, &clause.kind, |ctx, _| {
173 let trait_ref = ctx.translate_trait_impl_expr(span, &p.impl_expr)?;
174 let ty = ctx.translate_ty(span, &p.ty)?;
175 let type_name = ctx.t_ctx.translate_trait_item_name(&p.assoc_item.def_id)?;
176 Ok(TraitTypeConstraint {
177 trait_ref,
178 type_name,
179 ty,
180 })
181 })?;
182 into.trait_type_constraints.push(pred);
183 }
184 ClauseKind::ConstArgHasType(..) => {
185 }
188 ClauseKind::HostEffect(..) => {
189 }
192 ClauseKind::WellFormed(..) | ClauseKind::ConstEvaluatable(..) => {
193 }
197 ClauseKind::UnstableFeature(..) => {
198 }
200 #[expect(unreachable_patterns)]
201 kind => raise_error!(self, span, "Unsupported clause: {:?}", kind),
202 }
203 Ok(())
204 }
205
206 pub(crate) fn translate_trait_impl_exprs(
207 &mut self,
208 span: Span,
209 impl_sources: &[hax::ImplExpr],
210 ) -> Result<IndexMap<TraitClauseId, TraitRef>, Error> {
211 impl_sources
212 .iter()
213 .map(|x| self.translate_trait_impl_expr(span, x))
214 .try_collect()
215 }
216
217 #[tracing::instrument(skip(self, span, impl_expr))]
218 pub(crate) fn translate_trait_impl_expr(
219 &mut self,
220 span: Span,
221 impl_expr: &hax::ImplExpr,
222 ) -> Result<TraitRef, Error> {
223 let trait_decl_ref = self.translate_poly_trait_ref(span, &impl_expr.r#trait)?;
224
225 match self.translate_trait_impl_expr_aux(span, impl_expr, trait_decl_ref.clone()) {
226 Ok(res) => Ok(res),
227 Err(err) => {
228 register_error!(self, span, "Error during trait resolution: {}", &err.msg);
229 Ok(TraitRef::new(
230 TraitRefKind::Unknown(err.msg),
231 trait_decl_ref,
232 ))
233 }
234 }
235 }
236
237 pub(crate) fn translate_trait_impl_expr_aux(
238 &mut self,
239 span: Span,
240 impl_source: &hax::ImplExpr,
241 trait_decl_ref: PolyTraitDeclRef,
242 ) -> Result<TraitRef, Error> {
243 trace!("impl_expr: {:#?}", impl_source);
244 use hax::DestructData;
245 use hax::ImplExprAtom;
246
247 let trait_ref = match &impl_source.r#impl {
248 ImplExprAtom::Concrete(item) => {
249 let impl_ref =
250 self.translate_trait_impl_ref(span, item, TraitImplSource::Normal)?;
251 TraitRef::new(TraitRefKind::TraitImpl(impl_ref), trait_decl_ref)
252 }
253 ImplExprAtom::SelfImpl {
254 r#trait: trait_ref,
255 path,
256 }
257 | ImplExprAtom::LocalBound {
258 r#trait: trait_ref,
259 path,
260 ..
261 } => {
262 trace!(
263 "impl source (self or clause): param:\n- trait_ref: {:?}\n- path: {:?}",
264 trait_ref, path,
265 );
266 let mut tref_kind = match &impl_source.r#impl {
268 ImplExprAtom::SelfImpl { .. } => TraitRefKind::SelfId,
269 ImplExprAtom::LocalBound { index, .. } => {
270 match self.lookup_clause_var(span, *index) {
271 Ok(var) => TraitRefKind::Clause(var),
272 Err(err) => TraitRefKind::Unknown(err.msg),
273 }
274 }
275 _ => unreachable!(),
276 };
277
278 let mut current_pred = self.translate_poly_trait_ref(span, trait_ref)?;
279
280 for path_elem in path {
282 use hax::ImplExprPathChunk::*;
283 let trait_ref = Box::new(TraitRef::new(tref_kind, current_pred));
284 match path_elem {
285 AssocItem {
286 item,
287 predicate,
288 index,
289 ..
290 } => {
291 let name = self.t_ctx.translate_trait_item_name(&item.def_id)?;
292 tref_kind = TraitRefKind::ItemClause(
293 trait_ref,
294 name,
295 TraitClauseId::new(*index),
296 );
297 current_pred = self.translate_poly_trait_predicate(span, predicate)?;
298 }
299 Parent {
300 predicate, index, ..
301 } => {
302 tref_kind =
303 TraitRefKind::ParentClause(trait_ref, TraitClauseId::new(*index));
304 current_pred = self.translate_poly_trait_predicate(span, predicate)?;
305 }
306 }
307 }
308
309 TraitRef::new(tref_kind, trait_decl_ref)
310 }
311 ImplExprAtom::Dyn => TraitRef::new(TraitRefKind::Dyn, trait_decl_ref),
312 ImplExprAtom::Builtin {
313 trait_data,
314 impl_exprs,
315 types,
316 ..
317 } => {
318 let tref = &impl_source.r#trait;
319 let trait_def =
320 self.hax_def(&tref.hax_skip_binder_ref().erase(self.hax_state_with_id()))?;
321 let kind = if let hax::FullDefKind::TraitAlias { .. } = trait_def.kind() {
322 let impl_id = self.register_item(
324 span,
325 tref.hax_skip_binder_ref(),
326 TransItemSourceKind::TraitImpl(TraitImplSource::TraitAlias),
327 );
328 let mut generics = self.erase_region_binder(trait_decl_ref.clone()).generics;
329 assert!(
330 generics.trait_refs.is_empty(),
331 "found trait alias with non-empty required predicates"
332 );
333 generics.trait_refs = self.translate_trait_impl_exprs(span, &impl_exprs)?;
334 TraitRefKind::TraitImpl(TraitImplRef {
335 id: impl_id,
336 generics,
337 })
338 } else if let hax::BuiltinTraitData::Destruct(DestructData::Glue { ty, .. }) =
339 trait_data
340 {
341 let (hax::TyKind::Adt(item)
342 | hax::TyKind::Closure(hax::ClosureArgs { item, .. })
343 | hax::TyKind::Array(item)
344 | hax::TyKind::Slice(item)
345 | hax::TyKind::Tuple(item)) = ty.kind()
346 else {
347 raise_error!(self, span, "failed to translate drop glue for type {ty:?}")
348 };
349 TraitRefKind::TraitImpl(self.translate_trait_impl_ref(
350 span,
351 item,
352 TraitImplSource::ImplicitDestruct,
353 )?)
354 } else {
355 let Some(builtin_data) = self.recognize_builtin_impl(trait_data, &trait_def)
356 else {
357 raise_error!(
358 self,
359 span,
360 "found a built-in trait impl we did not recognize: \
361 {:?} (lang_item={:?})",
362 trait_def.def_id(),
363 trait_def.lang_item,
364 )
365 };
366 if let Some(closure_kind) = builtin_data.as_closure_kind()
369 && let Some(hax::GenericArg::Type(closure_ty)) = impl_source
370 .r#trait
371 .hax_skip_binder_ref()
372 .generic_args
373 .first()
374 && let hax::TyKind::Closure(closure_args) = closure_ty.kind()
375 {
376 let binder = self.translate_region_binder(
377 span,
378 &impl_source.r#trait,
379 |ctx, _tref| {
380 ctx.translate_closure_impl_ref(span, closure_args, closure_kind)
381 },
382 )?;
383 TraitRefKind::TraitImpl(self.erase_region_binder(binder))
384 } else {
385 let parent_trait_refs =
386 self.translate_trait_impl_exprs(span, &impl_exprs)?;
387 let types = if self.monomorphize() {
388 vec![]
389 } else {
390 types
391 .iter()
392 .map(|(def_id, ty, impl_exprs)| -> Result<_, Error> {
393 let name = self.t_ctx.translate_trait_item_name(def_id)?;
394 let assoc_ty = TraitAssocTyImpl {
395 value: self.translate_ty(span, ty)?,
396 implied_trait_refs: self
397 .translate_trait_impl_exprs(span, impl_exprs)?,
398 };
399 Ok((name, assoc_ty))
400 })
401 .try_collect()?
402 };
403 TraitRefKind::BuiltinOrAuto {
404 builtin_data,
405 parent_trait_refs,
406 types,
407 }
408 }
409 };
410 TraitRef::new(kind, trait_decl_ref)
411 }
412 ImplExprAtom::Error(msg) => {
413 let trait_ref = TraitRef::new(TraitRefKind::Unknown(msg.clone()), trait_decl_ref);
414 if self.error_on_impl_expr_error {
415 register_error!(self, span, "Error during trait resolution: {}", msg);
416 }
417 trait_ref
418 }
419 };
420 Ok(trait_ref)
421 }
422}