Skip to main content

rustc_trait_selection/traits/
util.rs

1use std::collections::VecDeque;
2
3use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
4use rustc_hir::LangItem;
5use rustc_hir::def_id::DefId;
6use rustc_infer::infer::InferCtxt;
7use rustc_infer::traits::PolyTraitObligation;
8pub use rustc_infer::traits::util::*;
9use rustc_middle::bug;
10use rustc_middle::ty::fast_reject::DeepRejectCtxt;
11use rustc_middle::ty::{
12    self, PolyTraitPredicate, PredicatePolarity, SizedTraitKind, TraitPredicate, TraitRef, Ty,
13    TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, Unnormalized,
14};
15pub use rustc_next_trait_solver::placeholder::BoundVarReplacer;
16use rustc_span::Span;
17use smallvec::{SmallVec, smallvec};
18use tracing::debug;
19
20/// Return the trait and projection predicates that come from eagerly expanding the
21/// trait aliases in the list of clauses. For each trait predicate, record a stack
22/// of spans that trace from the user-written trait alias bound. For projection predicates,
23/// just record the span of the projection itself.
24///
25/// For trait aliases, we don't deduplicte the predicates, since we currently do not
26/// consider duplicated traits as a single trait for the purposes of our "one trait principal"
27/// restriction; however, for projections we do deduplicate them.
28///
29/// ```rust,ignore (fails)
30/// trait Bar {}
31/// trait Foo = Bar + Bar;
32///
33/// let dyn_incompatible: dyn Foo; // bad, two `Bar` principals.
34/// ```
35pub fn expand_trait_aliases<'tcx>(
36    tcx: TyCtxt<'tcx>,
37    clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
38) -> (
39    Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
40    Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
41) {
42    let mut trait_preds = ::alloc::vec::Vec::new()vec![];
43    let mut projection_preds = ::alloc::vec::Vec::new()vec![];
44    let mut seen_projection_preds = FxHashSet::default();
45
46    let mut queue: VecDeque<_> = clauses.into_iter().map(|(p, s)| (p, {
    let count = 0usize + 1usize;
    let mut vec = ::smallvec::SmallVec::new();
    if count <= vec.inline_size() {
        vec.push(s);
        vec
    } else {
        ::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                    [s])))
    }
}smallvec![s])).collect();
47
48    while let Some((clause, spans)) = queue.pop_front() {
49        match clause.kind().skip_binder() {
50            ty::ClauseKind::Trait(trait_pred) => {
51                if tcx.is_trait_alias(trait_pred.def_id()) {
52                    queue.extend(
53                        tcx.explicit_super_predicates_of(trait_pred.def_id())
54                            .iter_identity_copied()
55                            .map(Unnormalized::skip_norm_wip)
56                            .map(|(super_clause, span)| {
57                                let mut spans = spans.clone();
58                                spans.push(span);
59                                (
60                                    super_clause.instantiate_supertrait(
61                                        tcx,
62                                        clause.kind().rebind(trait_pred.trait_ref),
63                                    ),
64                                    spans,
65                                )
66                            }),
67                    );
68                } else {
69                    trait_preds.push((clause.kind().rebind(trait_pred), spans));
70                }
71            }
72            ty::ClauseKind::Projection(projection_pred) => {
73                let projection_pred = clause.kind().rebind(projection_pred);
74                if !seen_projection_preds.insert(tcx.anonymize_bound_vars(projection_pred)) {
75                    continue;
76                }
77                projection_preds.push((projection_pred, *spans.last().unwrap()));
78            }
79            ty::ClauseKind::RegionOutlives(..)
80            | ty::ClauseKind::TypeOutlives(..)
81            | ty::ClauseKind::ConstArgHasType(_, _)
82            | ty::ClauseKind::WellFormed(_)
83            | ty::ClauseKind::ConstEvaluatable(_)
84            | ty::ClauseKind::UnstableFeature(_)
85            | ty::ClauseKind::HostEffect(..) => {}
86        }
87    }
88
89    (trait_preds, projection_preds)
90}
91
92///////////////////////////////////////////////////////////////////////////
93// Other
94///////////////////////////////////////////////////////////////////////////
95
96/// Casts a trait reference into a reference to one of its super
97/// traits; returns `None` if `target_trait_def_id` is not a
98/// supertrait.
99pub fn upcast_choices<'tcx>(
100    tcx: TyCtxt<'tcx>,
101    source_trait_ref: ty::PolyTraitRef<'tcx>,
102    target_trait_def_id: DefId,
103) -> Vec<ty::PolyTraitRef<'tcx>> {
104    if source_trait_ref.def_id() == target_trait_def_id {
105        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [source_trait_ref]))vec![source_trait_ref]; // Shortcut the most common case.
106    }
107
108    supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
109}
110
111pub(crate) fn closure_trait_ref_and_return_type<'tcx>(
112    tcx: TyCtxt<'tcx>,
113    fn_trait_def_id: DefId,
114    self_ty: Ty<'tcx>,
115    sig: ty::PolyFnSig<'tcx>,
116    tuple_arguments: TupleArgumentsFlag,
117) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
118    if !!self_ty.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !self_ty.has_escaping_bound_vars()")
};assert!(!self_ty.has_escaping_bound_vars());
119    let arguments_tuple = match tuple_arguments {
120        TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
121        TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
122    };
123    let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
124    sig.map_bound(|sig| (trait_ref, sig.output()))
125}
126
127pub(crate) fn coroutine_trait_ref_and_outputs<'tcx>(
128    tcx: TyCtxt<'tcx>,
129    fn_trait_def_id: DefId,
130    self_ty: Ty<'tcx>,
131    sig: ty::GenSig<TyCtxt<'tcx>>,
132) -> (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>) {
133    if !!self_ty.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !self_ty.has_escaping_bound_vars()")
};assert!(!self_ty.has_escaping_bound_vars());
134    let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.resume_ty]);
135    (trait_ref, sig.yield_ty, sig.return_ty)
136}
137
138pub(crate) fn future_trait_ref_and_outputs<'tcx>(
139    tcx: TyCtxt<'tcx>,
140    fn_trait_def_id: DefId,
141    self_ty: Ty<'tcx>,
142    sig: ty::GenSig<TyCtxt<'tcx>>,
143) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
144    if !!self_ty.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !self_ty.has_escaping_bound_vars()")
};assert!(!self_ty.has_escaping_bound_vars());
145    let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty]);
146    (trait_ref, sig.return_ty)
147}
148
149pub(crate) fn iterator_trait_ref_and_outputs<'tcx>(
150    tcx: TyCtxt<'tcx>,
151    iterator_def_id: DefId,
152    self_ty: Ty<'tcx>,
153    sig: ty::GenSig<TyCtxt<'tcx>>,
154) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
155    if !!self_ty.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !self_ty.has_escaping_bound_vars()")
};assert!(!self_ty.has_escaping_bound_vars());
156    let trait_ref = ty::TraitRef::new(tcx, iterator_def_id, [self_ty]);
157    (trait_ref, sig.yield_ty)
158}
159
160pub(crate) fn async_iterator_trait_ref_and_outputs<'tcx>(
161    tcx: TyCtxt<'tcx>,
162    async_iterator_def_id: DefId,
163    self_ty: Ty<'tcx>,
164    sig: ty::GenSig<TyCtxt<'tcx>>,
165) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
166    if !!self_ty.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !self_ty.has_escaping_bound_vars()")
};assert!(!self_ty.has_escaping_bound_vars());
167    let trait_ref = ty::TraitRef::new(tcx, async_iterator_def_id, [self_ty]);
168    (trait_ref, sig.yield_ty)
169}
170
171pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
172    assoc_item.defaultness(tcx).is_final()
173        && tcx.defaultness(assoc_item.container_id(tcx)).is_final()
174}
175
176pub(crate) enum TupleArgumentsFlag {
177    Yes,
178    No,
179}
180
181/// Executes `f` on `value` after replacing all escaping bound variables with placeholders
182/// and then replaces these placeholders with the original bound variables in the result.
183///
184/// In most places, bound variables should be replaced right when entering a binder, making
185/// this function unnecessary. However, normalization currently does not do that, so we have
186/// to do this lazily.
187///
188/// You should not add any additional uses of this function, at least not without first
189/// discussing it with t-types.
190///
191/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during
192/// normalization as well, at which point this function will be unnecessary and can be removed.
193pub fn with_replaced_escaping_bound_vars<
194    'a,
195    'tcx,
196    T: TypeFoldable<TyCtxt<'tcx>>,
197    R: TypeFoldable<TyCtxt<'tcx>>,
198>(
199    infcx: &'a InferCtxt<'tcx>,
200    universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
201    value: T,
202    f: impl FnOnce(T) -> R,
203) -> R {
204    if value.has_escaping_bound_vars() {
205        let (value, mapped_regions, mapped_types, mapped_consts) =
206            BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value);
207        let result = f(value);
208        PlaceholderReplacer::replace_placeholders(
209            infcx,
210            mapped_regions,
211            mapped_types,
212            mapped_consts,
213            universe_indices,
214            result,
215        )
216    } else {
217        f(value)
218    }
219}
220
221/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came.
222pub struct PlaceholderReplacer<'a, 'tcx> {
223    infcx: &'a InferCtxt<'tcx>,
224    mapped_regions: FxIndexMap<ty::PlaceholderRegion<'tcx>, ty::BoundRegion<'tcx>>,
225    mapped_types: FxIndexMap<ty::PlaceholderType<'tcx>, ty::BoundTy<'tcx>>,
226    mapped_consts: FxIndexMap<ty::PlaceholderConst<'tcx>, ty::BoundConst<'tcx>>,
227    universe_indices: &'a [Option<ty::UniverseIndex>],
228    current_index: ty::DebruijnIndex,
229}
230
231impl<'a, 'tcx> PlaceholderReplacer<'a, 'tcx> {
232    pub fn replace_placeholders<T: TypeFoldable<TyCtxt<'tcx>>>(
233        infcx: &'a InferCtxt<'tcx>,
234        mapped_regions: FxIndexMap<ty::PlaceholderRegion<'tcx>, ty::BoundRegion<'tcx>>,
235        mapped_types: FxIndexMap<ty::PlaceholderType<'tcx>, ty::BoundTy<'tcx>>,
236        mapped_consts: FxIndexMap<ty::PlaceholderConst<'tcx>, ty::BoundConst<'tcx>>,
237        universe_indices: &'a [Option<ty::UniverseIndex>],
238        value: T,
239    ) -> T {
240        let mut replacer = PlaceholderReplacer {
241            infcx,
242            mapped_regions,
243            mapped_types,
244            mapped_consts,
245            universe_indices,
246            current_index: ty::INNERMOST,
247        };
248        value.fold_with(&mut replacer)
249    }
250}
251
252impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
253    fn cx(&self) -> TyCtxt<'tcx> {
254        self.infcx.tcx
255    }
256
257    fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
258        &mut self,
259        t: ty::Binder<'tcx, T>,
260    ) -> ty::Binder<'tcx, T> {
261        if !t.has_placeholders() && !t.has_infer() {
262            return t;
263        }
264        self.current_index.shift_in(1);
265        let t = t.super_fold_with(self);
266        self.current_index.shift_out(1);
267        t
268    }
269
270    fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
271        let r1 = match r0.kind() {
272            ty::ReVar(vid) => self
273                .infcx
274                .inner
275                .borrow_mut()
276                .unwrap_region_constraints()
277                .opportunistic_resolve_var(self.infcx.tcx, vid),
278            _ => r0,
279        };
280
281        let r2 = match r1.kind() {
282            ty::RePlaceholder(p) => {
283                let replace_var = self.mapped_regions.get(&p);
284                match replace_var {
285                    Some(replace_var) => {
286                        let index = self
287                            .universe_indices
288                            .iter()
289                            .position(|u| #[allow(non_exhaustive_omitted_patterns)] match u {
    Some(pu) if *pu == p.universe => true,
    _ => false,
}matches!(u, Some(pu) if *pu == p.universe))
290                            .unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected placeholder universe."))bug!("Unexpected placeholder universe."));
291                        let db = ty::DebruijnIndex::from_usize(
292                            self.universe_indices.len() - index + self.current_index.as_usize() - 1,
293                        );
294                        ty::Region::new_bound(self.cx(), db, *replace_var)
295                    }
296                    None => r1,
297                }
298            }
299            _ => r1,
300        };
301
302        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/util.rs:302",
                        "rustc_trait_selection::traits::util",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/util.rs"),
                        ::tracing_core::__macro_support::Option::Some(302u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::util"),
                        ::tracing_core::field::FieldSet::new(&["message", "r0",
                                        "r1", "r2"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("fold_region")
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&r0) as
                                            &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&r1) as
                                            &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&r2) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!(?r0, ?r1, ?r2, "fold_region");
303
304        r2
305    }
306
307    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
308        let ty = self.infcx.shallow_resolve(ty);
309        match *ty.kind() {
310            ty::Placeholder(p) => {
311                let replace_var = self.mapped_types.get(&p);
312                match replace_var {
313                    Some(replace_var) => {
314                        let index = self
315                            .universe_indices
316                            .iter()
317                            .position(|u| #[allow(non_exhaustive_omitted_patterns)] match u {
    Some(pu) if *pu == p.universe => true,
    _ => false,
}matches!(u, Some(pu) if *pu == p.universe))
318                            .unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected placeholder universe."))bug!("Unexpected placeholder universe."));
319                        let db = ty::DebruijnIndex::from_usize(
320                            self.universe_indices.len() - index + self.current_index.as_usize() - 1,
321                        );
322                        Ty::new_bound(self.infcx.tcx, db, *replace_var)
323                    }
324                    None => {
325                        if ty.has_infer() {
326                            ty.super_fold_with(self)
327                        } else {
328                            ty
329                        }
330                    }
331                }
332            }
333
334            _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self),
335            _ => ty,
336        }
337    }
338
339    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
340        let ct = self.infcx.shallow_resolve_const(ct);
341        if let ty::ConstKind::Placeholder(p) = ct.kind() {
342            let replace_var = self.mapped_consts.get(&p);
343            match replace_var {
344                Some(replace_var) => {
345                    let index = self
346                        .universe_indices
347                        .iter()
348                        .position(|u| #[allow(non_exhaustive_omitted_patterns)] match u {
    Some(pu) if *pu == p.universe => true,
    _ => false,
}matches!(u, Some(pu) if *pu == p.universe))
349                        .unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected placeholder universe."))bug!("Unexpected placeholder universe."));
350                    let db = ty::DebruijnIndex::from_usize(
351                        self.universe_indices.len() - index + self.current_index.as_usize() - 1,
352                    );
353                    ty::Const::new_bound(self.infcx.tcx, db, *replace_var)
354                }
355                None => {
356                    if ct.has_infer() {
357                        ct.super_fold_with(self)
358                    } else {
359                        ct
360                    }
361                }
362            }
363        } else {
364            ct.super_fold_with(self)
365        }
366    }
367}
368
369pub fn sizedness_fast_path<'tcx>(
370    tcx: TyCtxt<'tcx>,
371    predicate: ty::Predicate<'tcx>,
372    param_env: ty::ParamEnv<'tcx>,
373) -> bool {
374    // Proving `Sized`/`MetaSized`, very often on "obviously sized" types like
375    // `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to
376    // canonicalize and all that for such cases.
377    if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
378        predicate.kind().skip_binder()
379        && trait_pred.polarity == ty::PredicatePolarity::Positive
380    {
381        let sizedness = match tcx.as_lang_item(trait_pred.def_id()) {
382            Some(LangItem::Sized) => SizedTraitKind::Sized,
383            Some(LangItem::MetaSized) => SizedTraitKind::MetaSized,
384            _ => return false,
385        };
386
387        if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) {
388            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/util.rs:388",
                        "rustc_trait_selection::traits::util",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/util.rs"),
                        ::tracing_core::__macro_support::Option::Some(388u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::util"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("fast path -- trivial sizedness")
                                            as &dyn Value))])
            });
    } else { ; }
};debug!("fast path -- trivial sizedness");
389            return true;
390        }
391
392        if #[allow(non_exhaustive_omitted_patterns)] match trait_pred.self_ty().kind() {
    ty::Param(_) | ty::Placeholder(_) => true,
    _ => false,
}matches!(trait_pred.self_ty().kind(), ty::Param(_) | ty::Placeholder(_)) {
393            for clause in param_env.caller_bounds() {
394                if let ty::ClauseKind::Trait(clause_pred) = clause.kind().skip_binder()
395                    && clause_pred.polarity == ty::PredicatePolarity::Positive
396                    && clause_pred.self_ty() == trait_pred.self_ty()
397                    && (clause_pred.def_id() == trait_pred.def_id()
398                        || (sizedness == SizedTraitKind::MetaSized
399                            && tcx.is_lang_item(clause_pred.def_id(), LangItem::Sized)))
400                {
401                    return true;
402                }
403            }
404        }
405    }
406
407    false
408}
409
410/// To improve performance, sizedness traits are not elaborated and so special-casing is required
411/// in the trait solver to find a `Sized` candidate for a `MetaSized` obligation. Returns the
412/// predicate to used in the candidate for such a `obligation`, given a `candidate`.
413pub(crate) fn lazily_elaborate_sizedness_candidate<'tcx>(
414    infcx: &InferCtxt<'tcx>,
415    obligation: &PolyTraitObligation<'tcx>,
416    candidate: PolyTraitPredicate<'tcx>,
417) -> PolyTraitPredicate<'tcx> {
418    if !infcx.tcx.is_lang_item(obligation.predicate.def_id(), LangItem::MetaSized)
419        || !infcx.tcx.is_lang_item(candidate.def_id(), LangItem::Sized)
420    {
421        return candidate;
422    }
423
424    if obligation.predicate.polarity() != PredicatePolarity::Positive
425        || candidate.polarity() != PredicatePolarity::Positive
426    {
427        return candidate;
428    }
429
430    let drcx = DeepRejectCtxt::relate_rigid_rigid(infcx.tcx);
431    if !drcx.args_may_unify(
432        obligation.predicate.skip_binder().trait_ref.args,
433        candidate.skip_binder().trait_ref.args,
434    ) {
435        return candidate;
436    }
437
438    candidate.map_bound(|c| TraitPredicate {
439        trait_ref: TraitRef::new_from_args(
440            infcx.tcx,
441            obligation.predicate.def_id(),
442            c.trait_ref.args,
443        ),
444        polarity: c.polarity,
445    })
446}