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