diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/select/confirmation.rs')
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/select/confirmation.rs | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2fbe2e1e323..3664121ac4b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -19,6 +19,7 @@ use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData}; use rustc_middle::ty::{self, GenericArgsRef, ToPolyTraitRef, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; +use rustc_type_ir::elaborate; use tracing::{debug, instrument}; use super::SelectionCandidate::{self, *}; @@ -624,6 +625,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for assoc_type in assoc_types { let defs: &ty::Generics = tcx.generics_of(assoc_type); + // When `async_fn_in_dyn_trait` is enabled, we don't need to check the + // RPITIT for compatibility, since it's not provided by the user. + if tcx.features().async_fn_in_dyn_trait() && tcx.is_impl_trait_in_trait(assoc_type) { + continue; + } + if !defs.own_params.is_empty() { tcx.dcx().span_delayed_bug( obligation.cause.span, @@ -1175,6 +1182,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::ClauseKind::TypeOutlives(outlives).upcast(tcx), )); + // Require that all AFIT will return something that can be coerced into `dyn*` + // -- a shim will be responsible for doing the actual coercion to `dyn*`. + if let Some(principal) = data.principal() { + for supertrait in + elaborate::supertraits(tcx, principal.with_self_ty(tcx, source)) + { + if tcx.is_trait_alias(supertrait.def_id()) { + continue; + } + + for &assoc_item in tcx.associated_item_def_ids(supertrait.def_id()) { + if !tcx.is_impl_trait_in_trait(assoc_item) { + continue; + } + + let pointer_like_goal = pointer_like_goal_for_rpitit( + tcx, + supertrait, + assoc_item, + &obligation.cause, + ); + + nested.push(predicate_to_obligation(pointer_like_goal.upcast(tcx))); + } + } + } + ImplSource::Builtin(BuiltinImplSource::Misc, nested) } @@ -1280,3 +1314,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } } + +/// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures) +/// implements the `PointerLike` trait, which is a requirement for the RPITIT to be +/// coercible to `dyn* Future`, which is itself a requirement for the RPITIT's parent +/// trait to be coercible to `dyn Trait`. +/// +/// We do this given a supertrait's substitutions, and then augment the substitutions +/// with bound variables to compute the goal universally. Given that `PointerLike` has +/// no region requirements (at least for the built-in pointer types), this shouldn't +/// *really* matter, but it is the best choice for soundness. +fn pointer_like_goal_for_rpitit<'tcx>( + tcx: TyCtxt<'tcx>, + supertrait: ty::PolyTraitRef<'tcx>, + rpitit_item: DefId, + cause: &ObligationCause<'tcx>, +) -> ty::PolyTraitRef<'tcx> { + let mut bound_vars = supertrait.bound_vars().to_vec(); + + let args = supertrait.skip_binder().args.extend_to(tcx, rpitit_item, |arg, _| match arg.kind { + ty::GenericParamDefKind::Lifetime => { + let kind = ty::BoundRegionKind::Named(arg.def_id, tcx.item_name(arg.def_id)); + bound_vars.push(ty::BoundVariableKind::Region(kind)); + ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }) + .into() + } + ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => { + unreachable!() + } + }); + + ty::Binder::bind_with_vars( + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::PointerLike, Some(cause.span)), [ + Ty::new_projection_from_args(tcx, rpitit_item, args), + ]), + tcx.mk_bound_variable_kinds(&bound_vars), + ) +} |
