rustc_trait_selection/traits/
effects.rs

1use rustc_hir::{self as hir, LangItem};
2use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
3use rustc_infer::traits::{
4    ImplDerivedHostCause, ImplSource, Obligation, ObligationCause, ObligationCauseCode,
5    PredicateObligation,
6};
7use rustc_middle::span_bug;
8use rustc_middle::traits::query::NoSolution;
9use rustc_middle::ty::elaborate::elaborate;
10use rustc_middle::ty::fast_reject::DeepRejectCtxt;
11use rustc_middle::ty::{self, Ty, TypingMode};
12use thin_vec::{ThinVec, thin_vec};
13
14use super::SelectionContext;
15use super::normalize::normalize_with_depth_to;
16
17pub type HostEffectObligation<'tcx> = Obligation<'tcx, ty::HostEffectPredicate<'tcx>>;
18
19pub enum EvaluationFailure {
20    Ambiguous,
21    NoSolution,
22}
23
24pub fn evaluate_host_effect_obligation<'tcx>(
25    selcx: &mut SelectionContext<'_, 'tcx>,
26    obligation: &HostEffectObligation<'tcx>,
27) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
28    if matches!(selcx.infcx.typing_mode(), TypingMode::Coherence) {
29        span_bug!(
30            obligation.cause.span,
31            "should not select host obligation in old solver in intercrate mode"
32        );
33    }
34
35    let ref obligation = selcx.infcx.resolve_vars_if_possible(obligation.clone());
36
37    // Force ambiguity for infer self ty.
38    if obligation.predicate.self_ty().is_ty_var() {
39        return Err(EvaluationFailure::Ambiguous);
40    }
41
42    match evaluate_host_effect_from_bounds(selcx, obligation) {
43        Ok(result) => return Ok(result),
44        Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
45        Err(EvaluationFailure::NoSolution) => {}
46    }
47
48    match evaluate_host_effect_from_conditionally_const_item_bounds(selcx, obligation) {
49        Ok(result) => return Ok(result),
50        Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
51        Err(EvaluationFailure::NoSolution) => {}
52    }
53
54    match evaluate_host_effect_from_item_bounds(selcx, obligation) {
55        Ok(result) => return Ok(result),
56        Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
57        Err(EvaluationFailure::NoSolution) => {}
58    }
59
60    match evaluate_host_effect_from_builtin_impls(selcx, obligation) {
61        Ok(result) => return Ok(result),
62        Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
63        Err(EvaluationFailure::NoSolution) => {}
64    }
65
66    match evaluate_host_effect_from_selection_candidate(selcx, obligation) {
67        Ok(result) => return Ok(result),
68        Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
69        Err(EvaluationFailure::NoSolution) => {}
70    }
71
72    match evaluate_host_effect_from_trait_alias(selcx, obligation) {
73        Ok(result) => return Ok(result),
74        Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
75        Err(EvaluationFailure::NoSolution) => {}
76    }
77
78    Err(EvaluationFailure::NoSolution)
79}
80
81fn match_candidate<'tcx>(
82    selcx: &mut SelectionContext<'_, 'tcx>,
83    obligation: &HostEffectObligation<'tcx>,
84    candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
85    candidate_is_unnormalized: bool,
86    more_nested: impl FnOnce(&mut SelectionContext<'_, 'tcx>, &mut ThinVec<PredicateObligation<'tcx>>),
87) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> {
88    if !candidate.skip_binder().constness.satisfies(obligation.predicate.constness) {
89        return Err(NoSolution);
90    }
91
92    let mut candidate = selcx.infcx.instantiate_binder_with_fresh_vars(
93        obligation.cause.span,
94        BoundRegionConversionTime::HigherRankedType,
95        candidate,
96    );
97
98    let mut nested = thin_vec![];
99
100    // Unlike param-env bounds, item bounds may not be normalized.
101    if candidate_is_unnormalized {
102        candidate = normalize_with_depth_to(
103            selcx,
104            obligation.param_env,
105            obligation.cause.clone(),
106            obligation.recursion_depth,
107            candidate,
108            &mut nested,
109        );
110    }
111
112    nested.extend(
113        selcx
114            .infcx
115            .at(&obligation.cause, obligation.param_env)
116            .eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)?
117            .into_obligations(),
118    );
119
120    more_nested(selcx, &mut nested);
121
122    Ok(nested)
123}
124
125fn evaluate_host_effect_from_bounds<'tcx>(
126    selcx: &mut SelectionContext<'_, 'tcx>,
127    obligation: &HostEffectObligation<'tcx>,
128) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
129    let infcx = selcx.infcx;
130    let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
131    let mut candidate = None;
132
133    for clause in obligation.param_env.caller_bounds() {
134        let bound_clause = clause.kind();
135        let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else {
136            continue;
137        };
138        let data = bound_clause.rebind(data);
139        if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
140            continue;
141        }
142
143        if !drcx
144            .args_may_unify(obligation.predicate.trait_ref.args, data.skip_binder().trait_ref.args)
145        {
146            continue;
147        }
148
149        let is_match =
150            infcx.probe(|_| match_candidate(selcx, obligation, data, false, |_, _| {}).is_ok());
151
152        if is_match {
153            if candidate.is_some() {
154                return Err(EvaluationFailure::Ambiguous);
155            } else {
156                candidate = Some(data);
157            }
158        }
159    }
160
161    if let Some(data) = candidate {
162        Ok(match_candidate(selcx, obligation, data, false, |_, _| {})
163            .expect("candidate matched before, so it should match again"))
164    } else {
165        Err(EvaluationFailure::NoSolution)
166    }
167}
168
169/// Assembles constness bounds from `~const` item bounds on alias types, which only
170/// hold if the `~const` where bounds also hold and the parent trait is `~const`.
171fn evaluate_host_effect_from_conditionally_const_item_bounds<'tcx>(
172    selcx: &mut SelectionContext<'_, 'tcx>,
173    obligation: &HostEffectObligation<'tcx>,
174) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
175    let infcx = selcx.infcx;
176    let tcx = infcx.tcx;
177    let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
178    let mut candidate = None;
179
180    let mut consider_ty = obligation.predicate.self_ty();
181    while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() {
182        if tcx.is_conditionally_const(alias_ty.def_id) {
183            for clause in elaborate(
184                tcx,
185                tcx.explicit_implied_const_bounds(alias_ty.def_id)
186                    .iter_instantiated_copied(tcx, alias_ty.args)
187                    .map(|(trait_ref, _)| {
188                        trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness)
189                    }),
190            ) {
191                let bound_clause = clause.kind();
192                let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else {
193                    unreachable!("should not elaborate non-HostEffect from HostEffect")
194                };
195                let data = bound_clause.rebind(data);
196                if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
197                    continue;
198                }
199
200                if !drcx.args_may_unify(
201                    obligation.predicate.trait_ref.args,
202                    data.skip_binder().trait_ref.args,
203                ) {
204                    continue;
205                }
206
207                let is_match = infcx
208                    .probe(|_| match_candidate(selcx, obligation, data, true, |_, _| {}).is_ok());
209
210                if is_match {
211                    if candidate.is_some() {
212                        return Err(EvaluationFailure::Ambiguous);
213                    } else {
214                        candidate = Some((data, alias_ty));
215                    }
216                }
217            }
218        }
219
220        if kind != ty::Projection {
221            break;
222        }
223
224        consider_ty = alias_ty.self_ty();
225    }
226
227    if let Some((data, alias_ty)) = candidate {
228        Ok(match_candidate(selcx, obligation, data, true, |selcx, nested| {
229            // An alias bound only holds if we also check the const conditions
230            // of the alias, so we need to register those, too.
231            let const_conditions = normalize_with_depth_to(
232                selcx,
233                obligation.param_env,
234                obligation.cause.clone(),
235                obligation.recursion_depth,
236                tcx.const_conditions(alias_ty.def_id).instantiate(tcx, alias_ty.args),
237                nested,
238            );
239            nested.extend(const_conditions.into_iter().map(|(trait_ref, _)| {
240                obligation
241                    .with(tcx, trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness))
242            }));
243        })
244        .expect("candidate matched before, so it should match again"))
245    } else {
246        Err(EvaluationFailure::NoSolution)
247    }
248}
249
250/// Assembles constness bounds "normal" item bounds on aliases, which may include
251/// unconditionally `const` bounds that are *not* conditional and thus always hold.
252fn evaluate_host_effect_from_item_bounds<'tcx>(
253    selcx: &mut SelectionContext<'_, 'tcx>,
254    obligation: &HostEffectObligation<'tcx>,
255) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
256    let infcx = selcx.infcx;
257    let tcx = infcx.tcx;
258    let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
259    let mut candidate = None;
260
261    let mut consider_ty = obligation.predicate.self_ty();
262    while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() {
263        for clause in tcx.item_bounds(alias_ty.def_id).iter_instantiated(tcx, alias_ty.args) {
264            let bound_clause = clause.kind();
265            let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else {
266                continue;
267            };
268            let data = bound_clause.rebind(data);
269            if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
270                continue;
271            }
272
273            if !drcx.args_may_unify(
274                obligation.predicate.trait_ref.args,
275                data.skip_binder().trait_ref.args,
276            ) {
277                continue;
278            }
279
280            let is_match =
281                infcx.probe(|_| match_candidate(selcx, obligation, data, true, |_, _| {}).is_ok());
282
283            if is_match {
284                if candidate.is_some() {
285                    return Err(EvaluationFailure::Ambiguous);
286                } else {
287                    candidate = Some(data);
288                }
289            }
290        }
291
292        if kind != ty::Projection {
293            break;
294        }
295
296        consider_ty = alias_ty.self_ty();
297    }
298
299    if let Some(data) = candidate {
300        Ok(match_candidate(selcx, obligation, data, true, |_, _| {})
301            .expect("candidate matched before, so it should match again"))
302    } else {
303        Err(EvaluationFailure::NoSolution)
304    }
305}
306
307fn evaluate_host_effect_from_builtin_impls<'tcx>(
308    selcx: &mut SelectionContext<'_, 'tcx>,
309    obligation: &HostEffectObligation<'tcx>,
310) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
311    match selcx.tcx().as_lang_item(obligation.predicate.def_id()) {
312        Some(LangItem::Copy | LangItem::Clone) => {
313            evaluate_host_effect_for_copy_clone_goal(selcx, obligation)
314        }
315        Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation),
316        Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => {
317            evaluate_host_effect_for_fn_goal(selcx, obligation)
318        }
319        _ => Err(EvaluationFailure::NoSolution),
320    }
321}
322
323fn evaluate_host_effect_for_copy_clone_goal<'tcx>(
324    selcx: &mut SelectionContext<'_, 'tcx>,
325    obligation: &HostEffectObligation<'tcx>,
326) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
327    let tcx = selcx.tcx();
328    let self_ty = obligation.predicate.self_ty();
329    let constituent_tys = match *self_ty.kind() {
330        // impl Copy/Clone for FnDef, FnPtr
331        ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])),
332
333        // Implementations are provided in core
334        ty::Uint(_)
335        | ty::Int(_)
336        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
337        | ty::Bool
338        | ty::Float(_)
339        | ty::Char
340        | ty::RawPtr(..)
341        | ty::Never
342        | ty::Ref(_, _, ty::Mutability::Not)
343        | ty::Array(..) => Err(EvaluationFailure::NoSolution),
344
345        // Cannot implement in core, as we can't be generic over patterns yet,
346        // so we'd have to list all patterns and type combinations.
347        ty::Pat(ty, ..) => Ok(ty::Binder::dummy(vec![ty])),
348
349        ty::Dynamic(..)
350        | ty::Str
351        | ty::Slice(_)
352        | ty::Foreign(..)
353        | ty::Ref(_, _, ty::Mutability::Mut)
354        | ty::Adt(_, _)
355        | ty::Alias(_, _)
356        | ty::Param(_)
357        | ty::Placeholder(..) => Err(EvaluationFailure::NoSolution),
358
359        ty::Bound(..)
360        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
361            panic!("unexpected type `{self_ty:?}`")
362        }
363
364        // impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone
365        ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.to_vec())),
366
367        // impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone
368        ty::Closure(_, args) => Ok(ty::Binder::dummy(vec![args.as_closure().tupled_upvars_ty()])),
369
370        // impl Copy/Clone for CoroutineClosure where Self::TupledUpvars: Copy/Clone
371        ty::CoroutineClosure(_, args) => {
372            Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()]))
373        }
374
375        // only when `coroutine_clone` is enabled and the coroutine is movable
376        // impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses)
377        ty::Coroutine(def_id, args) => {
378            if selcx.should_stall_coroutine(def_id) {
379                return Err(EvaluationFailure::Ambiguous);
380            }
381            match tcx.coroutine_movability(def_id) {
382                ty::Movability::Static => Err(EvaluationFailure::NoSolution),
383                ty::Movability::Movable => {
384                    if tcx.features().coroutine_clone() {
385                        Ok(ty::Binder::dummy(vec![
386                            args.as_coroutine().tupled_upvars_ty(),
387                            Ty::new_coroutine_witness_for_coroutine(tcx, def_id, args),
388                        ]))
389                    } else {
390                        Err(EvaluationFailure::NoSolution)
391                    }
392                }
393            }
394        }
395
396        ty::UnsafeBinder(_) => Err(EvaluationFailure::NoSolution),
397
398        // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
399        ty::CoroutineWitness(def_id, args) => Ok(tcx
400            .coroutine_hidden_types(def_id)
401            .instantiate(tcx, args)
402            .map_bound(|bound| bound.types.to_vec())),
403    }?;
404
405    Ok(constituent_tys
406        .iter()
407        .map(|ty| {
408            obligation.with(
409                tcx,
410                ty.map_bound(|ty| ty::TraitRef::new(tcx, obligation.predicate.def_id(), [ty]))
411                    .to_host_effect_clause(tcx, obligation.predicate.constness),
412            )
413        })
414        .collect())
415}
416
417// NOTE: Keep this in sync with `const_conditions_for_destruct` in the new solver.
418fn evaluate_host_effect_for_destruct_goal<'tcx>(
419    selcx: &mut SelectionContext<'_, 'tcx>,
420    obligation: &HostEffectObligation<'tcx>,
421) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
422    let tcx = selcx.tcx();
423    let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, obligation.cause.span);
424    let self_ty = obligation.predicate.self_ty();
425
426    let const_conditions = match *self_ty.kind() {
427        // `ManuallyDrop` is trivially `[const] Destruct` as we do not run any drop glue on it.
428        ty::Adt(adt_def, _) if adt_def.is_manually_drop() => thin_vec![],
429
430        // An ADT is `[const] Destruct` only if all of the fields are,
431        // *and* if there is a `Drop` impl, that `Drop` impl is also `[const]`.
432        ty::Adt(adt_def, args) => {
433            let mut const_conditions: ThinVec<_> = adt_def
434                .all_fields()
435                .map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)]))
436                .collect();
437            match adt_def.destructor(tcx).map(|dtor| tcx.constness(dtor.did)) {
438                // `Drop` impl exists, but it's not const. Type cannot be `[const] Destruct`.
439                Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution),
440                // `Drop` impl exists, and it's const. Require `Ty: [const] Drop` to hold.
441                Some(hir::Constness::Const) => {
442                    let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span);
443                    let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]);
444                    const_conditions.push(drop_trait_ref);
445                }
446                // No `Drop` impl, no need to require anything else.
447                None => {}
448            }
449            const_conditions
450        }
451
452        ty::Array(ty, _) | ty::Pat(ty, _) | ty::Slice(ty) => {
453            thin_vec![ty::TraitRef::new(tcx, destruct_def_id, [ty])]
454        }
455
456        ty::Tuple(tys) => {
457            tys.iter().map(|field_ty| ty::TraitRef::new(tcx, destruct_def_id, [field_ty])).collect()
458        }
459
460        // Trivially implement `[const] Destruct`
461        ty::Bool
462        | ty::Char
463        | ty::Int(..)
464        | ty::Uint(..)
465        | ty::Float(..)
466        | ty::Str
467        | ty::RawPtr(..)
468        | ty::Ref(..)
469        | ty::FnDef(..)
470        | ty::FnPtr(..)
471        | ty::Never
472        | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
473        | ty::Error(_) => thin_vec![],
474
475        // Coroutines and closures could implement `[const] Drop`,
476        // but they don't really need to right now.
477        ty::Closure(_, _)
478        | ty::CoroutineClosure(_, _)
479        | ty::Coroutine(_, _)
480        | ty::CoroutineWitness(_, _) => return Err(EvaluationFailure::NoSolution),
481
482        // FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop`
483        // if their inner type implements it.
484        ty::UnsafeBinder(_) => return Err(EvaluationFailure::NoSolution),
485
486        ty::Dynamic(..) | ty::Param(_) | ty::Alias(..) | ty::Placeholder(_) | ty::Foreign(_) => {
487            return Err(EvaluationFailure::NoSolution);
488        }
489
490        ty::Bound(..)
491        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
492            panic!("unexpected type `{self_ty:?}`")
493        }
494    };
495
496    Ok(const_conditions
497        .into_iter()
498        .map(|trait_ref| {
499            obligation.with(
500                tcx,
501                ty::Binder::dummy(trait_ref)
502                    .to_host_effect_clause(tcx, obligation.predicate.constness),
503            )
504        })
505        .collect())
506}
507
508// NOTE: Keep this in sync with `extract_fn_def_from_const_callable` in the new solver.
509fn evaluate_host_effect_for_fn_goal<'tcx>(
510    selcx: &mut SelectionContext<'_, 'tcx>,
511    obligation: &HostEffectObligation<'tcx>,
512) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
513    let tcx = selcx.tcx();
514    let self_ty = obligation.predicate.self_ty();
515
516    let (def, args) = match *self_ty.kind() {
517        ty::FnDef(def, args) => (def, args),
518
519        // We may support function pointers at some point in the future
520        ty::FnPtr(..) => return Err(EvaluationFailure::NoSolution),
521
522        // Closures could implement `[const] Fn`,
523        // but they don't really need to right now.
524        ty::Closure(..) | ty::CoroutineClosure(_, _) => {
525            return Err(EvaluationFailure::NoSolution);
526        }
527
528        // Everything else needs explicit impls or cannot have an impl
529        _ => return Err(EvaluationFailure::NoSolution),
530    };
531
532    match tcx.constness(def) {
533        hir::Constness::Const => Ok(tcx
534            .const_conditions(def)
535            .instantiate(tcx, args)
536            .into_iter()
537            .map(|(c, span)| {
538                let code = ObligationCauseCode::WhereClause(def, span);
539                let cause =
540                    ObligationCause::new(obligation.cause.span, obligation.cause.body_id, code);
541                Obligation::new(
542                    tcx,
543                    cause,
544                    obligation.param_env,
545                    c.to_host_effect_clause(tcx, obligation.predicate.constness),
546                )
547            })
548            .collect()),
549        hir::Constness::NotConst => Err(EvaluationFailure::NoSolution),
550    }
551}
552
553fn evaluate_host_effect_from_selection_candidate<'tcx>(
554    selcx: &mut SelectionContext<'_, 'tcx>,
555    obligation: &HostEffectObligation<'tcx>,
556) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
557    let tcx = selcx.tcx();
558    selcx.infcx.commit_if_ok(|_| {
559        match selcx.select(&obligation.with(tcx, obligation.predicate.trait_ref)) {
560            Ok(None) => Err(EvaluationFailure::Ambiguous),
561            Err(_) => Err(EvaluationFailure::NoSolution),
562            Ok(Some(source)) => match source {
563                ImplSource::UserDefined(impl_) => {
564                    if tcx.impl_trait_header(impl_.impl_def_id).constness != hir::Constness::Const {
565                        return Err(EvaluationFailure::NoSolution);
566                    }
567
568                    let mut nested = impl_.nested;
569                    nested.extend(
570                        tcx.const_conditions(impl_.impl_def_id)
571                            .instantiate(tcx, impl_.args)
572                            .into_iter()
573                            .map(|(trait_ref, span)| {
574                                Obligation::new(
575                                    tcx,
576                                    obligation.cause.clone().derived_host_cause(
577                                        ty::Binder::dummy(obligation.predicate),
578                                        |derived| {
579                                            ObligationCauseCode::ImplDerivedHost(Box::new(
580                                                ImplDerivedHostCause {
581                                                    derived,
582                                                    impl_def_id: impl_.impl_def_id,
583                                                    span,
584                                                },
585                                            ))
586                                        },
587                                    ),
588                                    obligation.param_env,
589                                    trait_ref
590                                        .to_host_effect_clause(tcx, obligation.predicate.constness),
591                                )
592                            }),
593                    );
594
595                    Ok(nested)
596                }
597                _ => Err(EvaluationFailure::NoSolution),
598            },
599        }
600    })
601}
602
603fn evaluate_host_effect_from_trait_alias<'tcx>(
604    selcx: &mut SelectionContext<'_, 'tcx>,
605    obligation: &HostEffectObligation<'tcx>,
606) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
607    let tcx = selcx.tcx();
608    let def_id = obligation.predicate.def_id();
609    if !tcx.trait_is_alias(def_id) {
610        return Err(EvaluationFailure::NoSolution);
611    }
612
613    Ok(tcx
614        .const_conditions(def_id)
615        .instantiate(tcx, obligation.predicate.trait_ref.args)
616        .into_iter()
617        .map(|(trait_ref, span)| {
618            Obligation::new(
619                tcx,
620                obligation.cause.clone().derived_host_cause(
621                    ty::Binder::dummy(obligation.predicate),
622                    |derived| {
623                        ObligationCauseCode::ImplDerivedHost(Box::new(ImplDerivedHostCause {
624                            derived,
625                            impl_def_id: def_id,
626                            span,
627                        }))
628                    },
629                ),
630                obligation.param_env,
631                trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness),
632            )
633        })
634        .collect())
635}