Add all RPITITs when augmenting param-env with GAT bounds in check_type_bounds

This commit is contained in:
Michael Goulet 2023-10-25 01:30:46 +00:00
parent bb74d7e97d
commit dd571e472a
2 changed files with 116 additions and 79 deletions

View File

@ -2162,7 +2162,7 @@ pub(super) fn check_type_bounds<'tcx>(
impl_ty: ty::AssocItem, impl_ty: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>, impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let param_env = param_env_with_gat_bounds(tcx, trait_ty, impl_ty, impl_trait_ref); let param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref);
debug!(?param_env); debug!(?param_env);
let container_id = impl_ty.container_id(tcx); let container_id = impl_ty.container_id(tcx);
@ -2288,7 +2288,6 @@ pub(super) fn check_type_bounds<'tcx>(
/// the trait (notably, that `X: Eq` and `T: Family`). /// the trait (notably, that `X: Eq` and `T: Family`).
fn param_env_with_gat_bounds<'tcx>( fn param_env_with_gat_bounds<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
trait_ty: ty::AssocItem,
impl_ty: ty::AssocItem, impl_ty: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>, impl_trait_ref: ty::TraitRef<'tcx>,
) -> ty::ParamEnv<'tcx> { ) -> ty::ParamEnv<'tcx> {
@ -2296,13 +2295,35 @@ fn param_env_with_gat_bounds<'tcx>(
let container_id = impl_ty.container_id(tcx); let container_id = impl_ty.container_id(tcx);
let mut predicates = param_env.caller_bounds().to_vec(); let mut predicates = param_env.caller_bounds().to_vec();
// for RPITITs, we should install predicates that allow us to project all
// of the RPITITs associated with the same body. This is because checking
// the item bounds of RPITITs often involves nested RPITITs having to prove
// bounds about themselves.
let impl_tys_to_install = match impl_ty.opt_rpitit_info {
None => vec![impl_ty],
Some(
ty::ImplTraitInTraitData::Impl { fn_def_id }
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
) => tcx
.associated_types_for_impl_traits_in_associated_fn(fn_def_id)
.iter()
.map(|def_id| tcx.associated_item(*def_id))
.collect(),
};
for impl_ty in impl_tys_to_install {
let trait_ty = match impl_ty.container {
ty::AssocItemContainer::TraitContainer => impl_ty,
ty::AssocItemContainer::ImplContainer => {
tcx.associated_item(impl_ty.trait_item_def_id.unwrap())
}
};
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len());
// Extend the impl's identity args with late-bound GAT vars // Extend the impl's identity args with late-bound GAT vars
let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id).extend_to( let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id)
tcx, .extend_to(tcx, impl_ty.def_id, |param, _| match param.kind {
impl_ty.def_id,
|param, _| match param.kind {
GenericParamDefKind::Type { .. } => { GenericParamDefKind::Type { .. } => {
let kind = ty::BoundTyKind::Param(param.def_id, param.name); let kind = ty::BoundTyKind::Param(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Ty(kind); let bound_var = ty::BoundVariableKind::Ty(kind);
@ -2321,7 +2342,10 @@ fn param_env_with_gat_bounds<'tcx>(
ty::Region::new_late_bound( ty::Region::new_late_bound(
tcx, tcx,
ty::INNERMOST, ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, ty::BoundRegion {
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
kind,
},
) )
.into() .into()
} }
@ -2338,8 +2362,7 @@ fn param_env_with_gat_bounds<'tcx>(
) )
.into() .into()
} }
}, });
);
// When checking something like // When checking something like
// //
// trait X { type Y: PartialEq<<Self as X>::Y> } // trait X { type Y: PartialEq<<Self as X>::Y> }
@ -2349,8 +2372,10 @@ fn param_env_with_gat_bounds<'tcx>(
// we want <T as X>::Y to normalize to S. This is valid because we are // we want <T as X>::Y to normalize to S. This is valid because we are
// checking the default value specifically here. Add this equality to the // checking the default value specifically here. Add this equality to the
// ParamEnv for normalization specifically. // ParamEnv for normalization specifically.
let normalize_impl_ty = tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args); let normalize_impl_ty =
let rebased_args = normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args);
let rebased_args =
normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args);
let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
match normalize_impl_ty.kind() { match normalize_impl_ty.kind() {
@ -2374,6 +2399,7 @@ fn param_env_with_gat_bounds<'tcx>(
.to_predicate(tcx), .to_predicate(tcx),
), ),
}; };
}
ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing)
} }

View File

@ -0,0 +1,11 @@
// check-pass
use std::ops::Deref;
trait Foo {
fn foo() -> impl Deref<Target = impl Deref<Target = impl Sized>> {
&&()
}
}
fn main() {}