Skip to main content

rustc_trait_selection/traits/
util.rs

1use std::collections::VecDeque;
2
3use rustc_data_structures::fx::FxHashSet;
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::ty::fast_reject::DeepRejectCtxt;
10use rustc_middle::ty::{
11    self, PolyTraitPredicate, PredicatePolarity, SizedTraitKind, TraitPredicate, TraitRef, Ty,
12    TyCtxt, TypeFoldable, TypeVisitableExt, Unnormalized,
13};
14pub use rustc_next_trait_solver::placeholder::{BoundVarReplacer, PlaceholderReplacer};
15use rustc_span::Span;
16use smallvec::{SmallVec, smallvec};
17use tracing::debug;
18
19/// Return the trait and projection predicates that come from eagerly expanding the
20/// trait aliases in the list of clauses. For each trait predicate, record a stack
21/// of spans that trace from the user-written trait alias bound. For projection predicates,
22/// just record the span of the projection itself.
23///
24/// For trait aliases, we don't deduplicte the predicates, since we currently do not
25/// consider duplicated traits as a single trait for the purposes of our "one trait principal"
26/// restriction; however, for projections we do deduplicate them.
27///
28/// ```rust,ignore (fails)
29/// trait Bar {}
30/// trait Foo = Bar + Bar;
31///
32/// let dyn_incompatible: dyn Foo; // bad, two `Bar` principals.
33/// ```
34pub fn expand_trait_aliases<'tcx>(
35    tcx: TyCtxt<'tcx>,
36    clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
37) -> (
38    Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
39    Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
40) {
41    let mut trait_preds = ::alloc::vec::Vec::new()vec![];
42    let mut projection_preds = ::alloc::vec::Vec::new()vec![];
43    let mut seen_projection_preds = FxHashSet::default();
44
45    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();
46
47    while let Some((clause, spans)) = queue.pop_front() {
48        match clause.kind().skip_binder() {
49            ty::ClauseKind::Trait(trait_pred) => {
50                if tcx.is_trait_alias(trait_pred.def_id()) {
51                    queue.extend(
52                        tcx.explicit_super_predicates_of(trait_pred.def_id())
53                            .iter_identity_copied()
54                            .map(Unnormalized::skip_norm_wip)
55                            .map(|(super_clause, span)| {
56                                let mut spans = spans.clone();
57                                spans.push(span);
58                                (
59                                    super_clause.instantiate_supertrait(
60                                        tcx,
61                                        clause.kind().rebind(trait_pred.trait_ref),
62                                    ),
63                                    spans,
64                                )
65                            }),
66                    );
67                } else {
68                    trait_preds.push((clause.kind().rebind(trait_pred), spans));
69                }
70            }
71            ty::ClauseKind::Projection(projection_pred) => {
72                let projection_pred = clause.kind().rebind(projection_pred);
73                if !seen_projection_preds.insert(tcx.anonymize_bound_vars(projection_pred)) {
74                    continue;
75                }
76                projection_preds.push((projection_pred, *spans.last().unwrap()));
77            }
78            ty::ClauseKind::RegionOutlives(..)
79            | ty::ClauseKind::TypeOutlives(..)
80            | ty::ClauseKind::ConstArgHasType(_, _)
81            | ty::ClauseKind::WellFormed(_)
82            | ty::ClauseKind::ConstEvaluatable(_)
83            | ty::ClauseKind::UnstableFeature(_)
84            | ty::ClauseKind::HostEffect(..) => {}
85        }
86    }
87
88    (trait_preds, projection_preds)
89}
90
91///////////////////////////////////////////////////////////////////////////
92// Other
93///////////////////////////////////////////////////////////////////////////
94
95/// Casts a trait reference into a reference to one of its super
96/// traits; returns `None` if `target_trait_def_id` is not a
97/// supertrait.
98pub fn upcast_choices<'tcx>(
99    tcx: TyCtxt<'tcx>,
100    source_trait_ref: ty::PolyTraitRef<'tcx>,
101    target_trait_def_id: DefId,
102) -> Vec<ty::PolyTraitRef<'tcx>> {
103    if source_trait_ref.def_id() == target_trait_def_id {
104        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.
105    }
106
107    supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
108}
109
110pub(crate) fn closure_trait_ref_and_return_type<'tcx>(
111    tcx: TyCtxt<'tcx>,
112    fn_trait_def_id: DefId,
113    self_ty: Ty<'tcx>,
114    sig: ty::PolyFnSig<'tcx>,
115    tuple_arguments: TupleArgumentsFlag,
116) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
117    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());
118    let arguments_tuple = match tuple_arguments {
119        TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
120        TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
121    };
122    let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
123    sig.map_bound(|sig| (trait_ref, sig.output()))
124}
125
126pub(crate) fn coroutine_trait_ref_and_outputs<'tcx>(
127    tcx: TyCtxt<'tcx>,
128    fn_trait_def_id: DefId,
129    self_ty: Ty<'tcx>,
130    sig: ty::GenSig<TyCtxt<'tcx>>,
131) -> (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>) {
132    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());
133    let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.resume_ty]);
134    (trait_ref, sig.yield_ty, sig.return_ty)
135}
136
137pub(crate) fn future_trait_ref_and_outputs<'tcx>(
138    tcx: TyCtxt<'tcx>,
139    fn_trait_def_id: DefId,
140    self_ty: Ty<'tcx>,
141    sig: ty::GenSig<TyCtxt<'tcx>>,
142) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
143    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());
144    let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty]);
145    (trait_ref, sig.return_ty)
146}
147
148pub(crate) fn iterator_trait_ref_and_outputs<'tcx>(
149    tcx: TyCtxt<'tcx>,
150    iterator_def_id: DefId,
151    self_ty: Ty<'tcx>,
152    sig: ty::GenSig<TyCtxt<'tcx>>,
153) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
154    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());
155    let trait_ref = ty::TraitRef::new(tcx, iterator_def_id, [self_ty]);
156    (trait_ref, sig.yield_ty)
157}
158
159pub(crate) fn async_iterator_trait_ref_and_outputs<'tcx>(
160    tcx: TyCtxt<'tcx>,
161    async_iterator_def_id: DefId,
162    self_ty: Ty<'tcx>,
163    sig: ty::GenSig<TyCtxt<'tcx>>,
164) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
165    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());
166    let trait_ref = ty::TraitRef::new(tcx, async_iterator_def_id, [self_ty]);
167    (trait_ref, sig.yield_ty)
168}
169
170pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
171    assoc_item.defaultness(tcx).is_final()
172        && tcx.defaultness(assoc_item.container_id(tcx)).is_final()
173}
174
175pub(crate) enum TupleArgumentsFlag {
176    Yes,
177    No,
178}
179
180/// Executes `f` on `value` after replacing all escaping bound variables with placeholders
181/// and then replaces these placeholders with the original bound variables in the result.
182///
183/// In most places, bound variables should be replaced right when entering a binder, making
184/// this function unnecessary. However, normalization currently does not do that, so we have
185/// to do this lazily.
186///
187/// You should not add any additional uses of this function, at least not without first
188/// discussing it with t-types.
189///
190/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during
191/// normalization as well, at which point this function will be unnecessary and can be removed.
192pub fn with_replaced_escaping_bound_vars<
193    'a,
194    'tcx,
195    T: TypeFoldable<TyCtxt<'tcx>>,
196    R: TypeFoldable<TyCtxt<'tcx>>,
197>(
198    infcx: &'a InferCtxt<'tcx>,
199    universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
200    value: T,
201    f: impl FnOnce(T) -> R,
202) -> R {
203    if value.has_escaping_bound_vars() {
204        let (value, mapped_regions, mapped_types, mapped_consts) =
205            BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value);
206        let result = f(value);
207        PlaceholderReplacer::replace_placeholders(
208            infcx,
209            mapped_regions,
210            mapped_types,
211            mapped_consts,
212            universe_indices,
213            result,
214        )
215    } else {
216        f(value)
217    }
218}
219
220pub fn sizedness_fast_path<'tcx>(
221    tcx: TyCtxt<'tcx>,
222    predicate: ty::Predicate<'tcx>,
223    param_env: ty::ParamEnv<'tcx>,
224) -> bool {
225    // Proving `Sized`/`MetaSized`, very often on "obviously sized" types like
226    // `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to
227    // canonicalize and all that for such cases.
228    if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
229        predicate.kind().skip_binder()
230        && trait_pred.polarity == ty::PredicatePolarity::Positive
231    {
232        let sizedness = match tcx.as_lang_item(trait_pred.def_id()) {
233            Some(LangItem::Sized) => SizedTraitKind::Sized,
234            Some(LangItem::MetaSized) => SizedTraitKind::MetaSized,
235            _ => return false,
236        };
237
238        if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) {
239            {
    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:239",
                        "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(239u32),
                        ::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");
240            return true;
241        }
242
243        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(_)) {
244            for clause in param_env.caller_bounds() {
245                if let ty::ClauseKind::Trait(clause_pred) = clause.kind().skip_binder()
246                    && clause_pred.polarity == ty::PredicatePolarity::Positive
247                    && clause_pred.self_ty() == trait_pred.self_ty()
248                    && (clause_pred.def_id() == trait_pred.def_id()
249                        || (sizedness == SizedTraitKind::MetaSized
250                            && tcx.is_lang_item(clause_pred.def_id(), LangItem::Sized)))
251                {
252                    return true;
253                }
254            }
255        }
256    }
257
258    false
259}
260
261/// To improve performance, sizedness traits are not elaborated and so special-casing is required
262/// in the trait solver to find a `Sized` candidate for a `MetaSized` obligation. Returns the
263/// predicate to used in the candidate for such a `obligation`, given a `candidate`.
264pub(crate) fn lazily_elaborate_sizedness_candidate<'tcx>(
265    infcx: &InferCtxt<'tcx>,
266    obligation: &PolyTraitObligation<'tcx>,
267    candidate: PolyTraitPredicate<'tcx>,
268) -> PolyTraitPredicate<'tcx> {
269    if !infcx.tcx.is_lang_item(obligation.predicate.def_id(), LangItem::MetaSized)
270        || !infcx.tcx.is_lang_item(candidate.def_id(), LangItem::Sized)
271    {
272        return candidate;
273    }
274
275    if obligation.predicate.polarity() != PredicatePolarity::Positive
276        || candidate.polarity() != PredicatePolarity::Positive
277    {
278        return candidate;
279    }
280
281    let drcx = DeepRejectCtxt::relate_rigid_rigid(infcx.tcx);
282    if !drcx.args_may_unify(
283        obligation.predicate.skip_binder().trait_ref.args,
284        candidate.skip_binder().trait_ref.args,
285    ) {
286        return candidate;
287    }
288
289    candidate.map_bound(|c| TraitPredicate {
290        trait_ref: TraitRef::new_from_args(
291            infcx.tcx,
292            obligation.predicate.def_id(),
293            c.trait_ref.args,
294        ),
295        polarity: c.polarity,
296    })
297}