1use crate::prelude::*;
2
3#[cfg(feature = "rustc")]
4mod resolution;
5#[cfg(feature = "rustc")]
6mod utils;
7#[cfg(feature = "rustc")]
8pub use utils::{
9 ToPolyTraitRef, erase_and_norm, implied_predicates, is_sized_related_trait,
10 predicates_defined_on, required_predicates, self_predicate,
11};
12
13#[cfg(feature = "rustc")]
14pub use resolution::PredicateSearcher;
15#[cfg(feature = "rustc")]
16use rustc_middle::ty;
17#[cfg(feature = "rustc")]
18use rustc_span::def_id::DefId as RDefId;
19
20#[derive_group(Serializers)]
21#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
22pub enum ImplExprPathChunk {
23 AssocItem {
24 item: ItemRef,
32 assoc_item: AssocItem,
33 predicate: Binder<TraitPredicate>,
35 predicate_id: PredicateId,
36 index: usize,
38 },
39 Parent {
40 predicate: Binder<TraitPredicate>,
42 predicate_id: PredicateId,
43 index: usize,
45 },
46}
47
48#[cfg(feature = "rustc")]
49impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, ImplExprPathChunk> for resolution::PathChunk<'tcx> {
50 fn sinto(&self, s: &S) -> ImplExprPathChunk {
51 match self {
52 resolution::PathChunk::AssocItem {
53 item,
54 generic_args,
55 impl_exprs,
56 predicate,
57 index,
58 ..
59 } => ImplExprPathChunk::AssocItem {
60 item: ItemRef::new(
61 s,
62 item.def_id.sinto(s),
63 generic_args.sinto(s),
64 impl_exprs.sinto(s),
65 None,
66 ),
67 assoc_item: item.sinto(s),
68 predicate: predicate.sinto(s),
69 predicate_id: <_ as SInto<_, Clause>>::sinto(predicate, s).id,
70 index: index.sinto(s),
71 },
72 resolution::PathChunk::Parent {
73 predicate, index, ..
74 } => ImplExprPathChunk::Parent {
75 predicate: predicate.sinto(s),
76 predicate_id: <_ as SInto<_, Clause>>::sinto(predicate, s).id,
77 index: index.sinto(s),
78 },
79 }
80 }
81}
82
83#[derive(AdtInto)]
86#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::ImplExprAtom<'tcx>, state: S as s)]
87#[derive_group(Serializers)]
88#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
89pub enum ImplExprAtom {
90 #[custom_arm(FROM_TYPE::Concrete { def_id, generics, impl_exprs } => TO_TYPE::Concrete(
92 ItemRef::new(
93 s,
94 def_id.sinto(s),
95 generics.sinto(s),
96 impl_exprs.sinto(s),
97 None,
98 )
99 ),)]
100 Concrete(ItemRef),
101 LocalBound {
103 #[not_in_source]
104 #[value({
105 let Self::LocalBound { predicate, .. } = self else { unreachable!() };
106 predicate.sinto(s).id
107 })]
108 predicate_id: PredicateId,
109 index: usize,
112 r#trait: Binder<TraitRef>,
113 path: Vec<ImplExprPathChunk>,
114 },
115 SelfImpl {
118 r#trait: Binder<TraitRef>,
119 path: Vec<ImplExprPathChunk>,
120 },
121 Dyn,
128 Drop(DropData),
133 Builtin {
137 r#trait: Binder<TraitRef>,
138 impl_exprs: Vec<ImplExpr>,
142 types: Vec<(DefId, Ty)>,
144 },
145 Error(String),
147}
148
149#[derive(AdtInto)]
150#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::DropData<'tcx>, state: S as s)]
151#[derive_group(Serializers)]
152#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
153pub enum DropData {
154 Noop,
156 Implicit,
161 Glue {
165 ty: Ty,
167 impl_exprs: Vec<ImplExpr>,
170 },
171}
172
173#[derive_group(Serializers)]
178#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema, AdtInto)]
179#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::ImplExpr<'tcx>, state: S as s)]
180pub struct ImplExpr {
181 pub r#trait: Binder<TraitRef>,
183 pub r#impl: ImplExprAtom,
185}
186
187#[cfg(feature = "rustc")]
190pub fn super_clause_to_clause_and_impl_expr<'tcx, S: UnderOwnerState<'tcx>>(
191 s: &S,
192 impl_did: rustc_span::def_id::DefId,
193 clause: rustc_middle::ty::Clause<'tcx>,
194 span: rustc_span::Span,
195) -> Option<(Clause, ImplExpr, Span)> {
196 let tcx = s.base().tcx;
197 let impl_trait_ref = tcx
198 .impl_trait_ref(impl_did)
199 .map(|binder| rustc_middle::ty::Binder::dummy(binder.instantiate_identity()))?;
200 let original_predicate_id = {
201 let s = &with_owner_id(s.base(), (), (), impl_trait_ref.def_id());
204 clause.sinto(s).id
205 };
206 let new_clause = clause.instantiate_supertrait(tcx, impl_trait_ref);
207 let impl_expr = solve_trait(
208 s,
209 new_clause
210 .as_predicate()
211 .as_trait_clause()?
212 .to_poly_trait_ref(),
213 );
214 let mut new_clause_no_binder = new_clause.sinto(s);
215 new_clause_no_binder.id = original_predicate_id;
216 Some((new_clause_no_binder, impl_expr, span.sinto(s)))
217}
218
219#[cfg(feature = "rustc")]
221#[tracing::instrument(level = "trace", skip(s))]
222pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>(
223 s: &S,
224 trait_ref: rustc_middle::ty::PolyTraitRef<'tcx>,
225) -> ImplExpr {
226 let warn = |msg: &str| {
227 if !s.base().ty_alias_mode {
228 crate::warning!(s, "{}", msg)
229 }
230 };
231 if let Some(impl_expr) = s.with_cache(|cache| cache.impl_exprs.get(&trait_ref).cloned()) {
232 return impl_expr;
233 }
234 let resolved = s.with_cache(|cache| {
235 cache
236 .predicate_searcher
237 .get_or_insert_with(|| {
238 PredicateSearcher::new_for_owner(
239 s.base().tcx,
240 s.owner_id(),
241 s.base().options.bounds_options,
242 )
243 })
244 .resolve(&trait_ref, &warn)
245 });
246 let impl_expr = match resolved {
247 Ok(x) => x.sinto(s),
248 Err(e) => crate::fatal!(s, "{}", e),
249 };
250 s.with_cache(|cache| cache.impl_exprs.insert(trait_ref, impl_expr.clone()));
251 impl_expr
252}
253
254#[cfg(feature = "rustc")]
256#[tracing::instrument(level = "trace", skip(s), ret)]
257pub fn translate_item_ref<'tcx, S: UnderOwnerState<'tcx>>(
258 s: &S,
259 def_id: RDefId,
260 generics: ty::GenericArgsRef<'tcx>,
261) -> ItemRef {
262 let key = (def_id, generics);
263 if let Some(item) = s.with_cache(|cache| cache.item_refs.get(&key).cloned()) {
264 return item;
265 }
266 let mut impl_exprs = solve_item_required_traits(s, def_id, generics);
267 let mut generic_args = generics.sinto(s);
268
269 let trait_info = self_clause_for_item(s, def_id, generics);
271 if let Some(tinfo) = &trait_info {
273 let trait_ref = tinfo.r#trait.hax_skip_binder_ref();
290 let num_trait_generics = trait_ref.generic_args.len();
291 generic_args.drain(0..num_trait_generics);
292 let num_trait_trait_clauses = trait_ref.impl_exprs.len();
293 impl_exprs.drain(0..num_trait_trait_clauses);
294 }
295
296 let content = ItemRefContents {
297 def_id: def_id.sinto(s),
298 generic_args,
299 impl_exprs,
300 in_trait: trait_info,
301 };
302 let item = content.intern(s);
303 s.with_cache(|cache| {
304 cache.item_refs.insert(key, item.clone());
305 });
306 item
307}
308
309#[cfg(feature = "rustc")]
313#[tracing::instrument(level = "trace", skip(s), ret)]
314pub fn solve_item_required_traits<'tcx, S: UnderOwnerState<'tcx>>(
315 s: &S,
316 def_id: RDefId,
317 generics: ty::GenericArgsRef<'tcx>,
318) -> Vec<ImplExpr> {
319 fn accumulate<'tcx, S: UnderOwnerState<'tcx>>(
320 s: &S,
321 def_id: RDefId,
322 generics: ty::GenericArgsRef<'tcx>,
323 impl_exprs: &mut Vec<ImplExpr>,
324 ) {
325 let tcx = s.base().tcx;
326 use rustc_hir::def::DefKind::*;
327 match tcx.def_kind(def_id) {
328 AssocTy | AssocFn | AssocConst | Closure | Ctor(..) | Variant => {
329 let parent = tcx.parent(def_id);
330 accumulate(s, parent, generics, impl_exprs);
331 }
332 _ => {}
333 }
334 let predicates = required_predicates(tcx, def_id, s.base().options.bounds_options);
335 impl_exprs.extend(solve_item_traits_inner(s, generics, predicates));
336 }
337 let mut impl_exprs = vec![];
338 accumulate(s, def_id, generics, &mut impl_exprs);
339 impl_exprs
340}
341
342#[cfg(feature = "rustc")]
345#[tracing::instrument(level = "trace", skip(s), ret)]
346pub fn solve_item_implied_traits<'tcx, S: UnderOwnerState<'tcx>>(
347 s: &S,
348 def_id: RDefId,
349 generics: ty::GenericArgsRef<'tcx>,
350) -> Vec<ImplExpr> {
351 let predicates = implied_predicates(s.base().tcx, def_id, s.base().options.bounds_options);
352 solve_item_traits_inner(s, generics, predicates)
353}
354
355#[cfg(feature = "rustc")]
358fn solve_item_traits_inner<'tcx, S: UnderOwnerState<'tcx>>(
359 s: &S,
360 generics: ty::GenericArgsRef<'tcx>,
361 predicates: ty::GenericPredicates<'tcx>,
362) -> Vec<ImplExpr> {
363 let tcx = s.base().tcx;
364 let typing_env = s.typing_env();
365 predicates
366 .predicates
367 .iter()
368 .map(|(clause, _span)| *clause)
369 .filter_map(|clause| clause.as_trait_clause())
370 .map(|clause| clause.to_poly_trait_ref())
371 .map(|trait_ref| ty::EarlyBinder::bind(trait_ref).instantiate(tcx, generics))
373 .map(|trait_ref| {
375 tcx.try_normalize_erasing_regions(typing_env, trait_ref)
376 .unwrap_or(trait_ref)
377 })
378 .map(|trait_ref| solve_trait(s, trait_ref))
380 .collect()
381}
382
383#[cfg(feature = "rustc")]
385pub fn self_clause_for_item<'tcx, S: UnderOwnerState<'tcx>>(
386 s: &S,
387 def_id: RDefId,
388 generics: rustc_middle::ty::GenericArgsRef<'tcx>,
389) -> Option<ImplExpr> {
390 use rustc_middle::ty::EarlyBinder;
391 let tcx = s.base().tcx;
392
393 let tr_def_id = tcx.trait_of_item(def_id)?;
394 let self_pred = self_predicate(tcx, tr_def_id);
396 let generics = generics.truncate_to(tcx, tcx.generics_of(tr_def_id));
398 let self_pred = EarlyBinder::bind(self_pred).instantiate(tcx, generics);
399
400 Some(solve_trait(s, self_pred))
402}