Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit bfd836b

Browse files
committedOct 25, 2023
Add all RPITITs when augmenting param-env with GAT bounds in check_type_bounds
1 parent 69563f0 commit bfd836b

File tree

2 files changed

+114
-77
lines changed

2 files changed

+114
-77
lines changed
 

‎compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+103-77
Original file line numberDiff line numberDiff line change
@@ -2162,7 +2162,7 @@ pub(super) fn check_type_bounds<'tcx>(
21622162
impl_ty: ty::AssocItem,
21632163
impl_trait_ref: ty::TraitRef<'tcx>,
21642164
) -> Result<(), ErrorGuaranteed> {
2165-
let param_env = param_env_with_gat_bounds(tcx, trait_ty, impl_ty, impl_trait_ref);
2165+
let param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref);
21662166
debug!(?param_env);
21672167

21682168
let container_id = impl_ty.container_id(tcx);
@@ -2288,92 +2288,118 @@ pub(super) fn check_type_bounds<'tcx>(
22882288
/// the trait (notably, that `X: Eq` and `T: Family`).
22892289
fn param_env_with_gat_bounds<'tcx>(
22902290
tcx: TyCtxt<'tcx>,
2291-
trait_ty: ty::AssocItem,
22922291
impl_ty: ty::AssocItem,
22932292
impl_trait_ref: ty::TraitRef<'tcx>,
22942293
) -> ty::ParamEnv<'tcx> {
22952294
let param_env = tcx.param_env(impl_ty.def_id);
22962295
let container_id = impl_ty.container_id(tcx);
22972296
let mut predicates = param_env.caller_bounds().to_vec();
22982297

2299-
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
2300-
smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len());
2301-
// Extend the impl's identity args with late-bound GAT vars
2302-
let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id).extend_to(
2303-
tcx,
2304-
impl_ty.def_id,
2305-
|param, _| match param.kind {
2306-
GenericParamDefKind::Type { .. } => {
2307-
let kind = ty::BoundTyKind::Param(param.def_id, param.name);
2308-
let bound_var = ty::BoundVariableKind::Ty(kind);
2309-
bound_vars.push(bound_var);
2310-
Ty::new_bound(
2311-
tcx,
2312-
ty::INNERMOST,
2313-
ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
2314-
)
2315-
.into()
2298+
// for RPITITs, we should install predicates that allow us to project all
2299+
// of the RPITITs associated with the same body. This is because checking
2300+
// the item bounds of RPITITs often involves nested RPITITs having to prove
2301+
// bounds about themselves.
2302+
let impl_tys_to_install = match impl_ty.opt_rpitit_info {
2303+
None => vec![impl_ty],
2304+
Some(
2305+
ty::ImplTraitInTraitData::Impl { fn_def_id }
2306+
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
2307+
) => tcx
2308+
.associated_types_for_impl_traits_in_associated_fn(fn_def_id)
2309+
.iter()
2310+
.map(|def_id| tcx.associated_item(*def_id))
2311+
.collect(),
2312+
};
2313+
2314+
for impl_ty in impl_tys_to_install {
2315+
let trait_ty = match impl_ty.container {
2316+
ty::AssocItemContainer::TraitContainer => impl_ty,
2317+
ty::AssocItemContainer::ImplContainer => {
2318+
tcx.associated_item(impl_ty.trait_item_def_id.unwrap())
23162319
}
2317-
GenericParamDefKind::Lifetime => {
2318-
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
2319-
let bound_var = ty::BoundVariableKind::Region(kind);
2320-
bound_vars.push(bound_var);
2321-
ty::Region::new_late_bound(
2322-
tcx,
2323-
ty::INNERMOST,
2324-
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
2325-
)
2326-
.into()
2320+
};
2321+
2322+
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
2323+
smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len());
2324+
// Extend the impl's identity args with late-bound GAT vars
2325+
let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id)
2326+
.extend_to(tcx, impl_ty.def_id, |param, _| match param.kind {
2327+
GenericParamDefKind::Type { .. } => {
2328+
let kind = ty::BoundTyKind::Param(param.def_id, param.name);
2329+
let bound_var = ty::BoundVariableKind::Ty(kind);
2330+
bound_vars.push(bound_var);
2331+
Ty::new_bound(
2332+
tcx,
2333+
ty::INNERMOST,
2334+
ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
2335+
)
2336+
.into()
2337+
}
2338+
GenericParamDefKind::Lifetime => {
2339+
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
2340+
let bound_var = ty::BoundVariableKind::Region(kind);
2341+
bound_vars.push(bound_var);
2342+
ty::Region::new_late_bound(
2343+
tcx,
2344+
ty::INNERMOST,
2345+
ty::BoundRegion {
2346+
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
2347+
kind,
2348+
},
2349+
)
2350+
.into()
2351+
}
2352+
GenericParamDefKind::Const { .. } => {
2353+
let bound_var = ty::BoundVariableKind::Const;
2354+
bound_vars.push(bound_var);
2355+
ty::Const::new_bound(
2356+
tcx,
2357+
ty::INNERMOST,
2358+
ty::BoundVar::from_usize(bound_vars.len() - 1),
2359+
tcx.type_of(param.def_id)
2360+
.no_bound_vars()
2361+
.expect("const parameter types cannot be generic"),
2362+
)
2363+
.into()
2364+
}
2365+
});
2366+
// When checking something like
2367+
//
2368+
// trait X { type Y: PartialEq<<Self as X>::Y> }
2369+
// impl X for T { default type Y = S; }
2370+
//
2371+
// We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
2372+
// we want <T as X>::Y to normalize to S. This is valid because we are
2373+
// checking the default value specifically here. Add this equality to the
2374+
// ParamEnv for normalization specifically.
2375+
let normalize_impl_ty =
2376+
tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args);
2377+
let rebased_args =
2378+
normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args);
2379+
let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
2380+
2381+
match normalize_impl_ty.kind() {
2382+
ty::Alias(ty::Projection, proj)
2383+
if proj.def_id == trait_ty.def_id && proj.args == rebased_args =>
2384+
{
2385+
// Don't include this predicate if the projected type is
2386+
// exactly the same as the projection. This can occur in
2387+
// (somewhat dubious) code like this:
2388+
//
2389+
// impl<T> X for T where T: X { type Y = <T as X>::Y; }
23272390
}
2328-
GenericParamDefKind::Const { .. } => {
2329-
let bound_var = ty::BoundVariableKind::Const;
2330-
bound_vars.push(bound_var);
2331-
ty::Const::new_bound(
2332-
tcx,
2333-
ty::INNERMOST,
2334-
ty::BoundVar::from_usize(bound_vars.len() - 1),
2335-
tcx.type_of(param.def_id)
2336-
.no_bound_vars()
2337-
.expect("const parameter types cannot be generic"),
2391+
_ => predicates.push(
2392+
ty::Binder::bind_with_vars(
2393+
ty::ProjectionPredicate {
2394+
projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args),
2395+
term: normalize_impl_ty.into(),
2396+
},
2397+
bound_vars,
23382398
)
2339-
.into()
2340-
}
2341-
},
2342-
);
2343-
// When checking something like
2344-
//
2345-
// trait X { type Y: PartialEq<<Self as X>::Y> }
2346-
// impl X for T { default type Y = S; }
2347-
//
2348-
// We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
2349-
// we want <T as X>::Y to normalize to S. This is valid because we are
2350-
// checking the default value specifically here. Add this equality to the
2351-
// ParamEnv for normalization specifically.
2352-
let normalize_impl_ty = tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args);
2353-
let rebased_args = normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args);
2354-
let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
2355-
2356-
match normalize_impl_ty.kind() {
2357-
ty::Alias(ty::Projection, proj)
2358-
if proj.def_id == trait_ty.def_id && proj.args == rebased_args =>
2359-
{
2360-
// Don't include this predicate if the projected type is
2361-
// exactly the same as the projection. This can occur in
2362-
// (somewhat dubious) code like this:
2363-
//
2364-
// impl<T> X for T where T: X { type Y = <T as X>::Y; }
2365-
}
2366-
_ => predicates.push(
2367-
ty::Binder::bind_with_vars(
2368-
ty::ProjectionPredicate {
2369-
projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args),
2370-
term: normalize_impl_ty.into(),
2371-
},
2372-
bound_vars,
2373-
)
2374-
.to_predicate(tcx),
2375-
),
2376-
};
2399+
.to_predicate(tcx),
2400+
),
2401+
};
2402+
}
23772403

23782404
ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing)
23792405
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// check-pass
2+
3+
use std::ops::Deref;
4+
5+
trait Foo {
6+
fn foo() -> impl Deref<Target = impl Deref<Target = impl Sized>> {
7+
&&()
8+
}
9+
}
10+
11+
fn main() {}

0 commit comments

Comments
 (0)
Please sign in to comment.