From bb74d7e97d8da904bb6deeb78bafeaa6ad7c11c8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 24 Oct 2023 15:49:44 +0000 Subject: [PATCH 1/2] Use the normalizing param-env always in check_type_bounds --- .../src/check/compare_impl_item.rs | 266 ++++++++++-------- ...sume-gat-normalization-for-nested-goals.rs | 18 ++ .../new-solver/specialization-transmute.rs | 2 +- .../specialization-transmute.stderr | 11 +- .../specialization-unconstrained.rs | 2 +- .../specialization-unconstrained.stderr | 11 +- 6 files changed, 167 insertions(+), 143 deletions(-) create mode 100644 tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.rs diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 74e2b157dd0a4..f7664b0c3a120 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2162,128 +2162,10 @@ pub(super) fn check_type_bounds<'tcx>( impl_ty: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let param_env = tcx.param_env(impl_ty.def_id); - let container_id = impl_ty.container_id(tcx); - // Given - // - // impl Foo for (A, B) { - // type Bar = Wrapper - // } - // - // - `impl_trait_ref` would be `<(A, B) as Foo>` - // - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) - // - `normalize_impl_ty` would be `Wrapper` - // - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from - // the *trait* with the generic associated type parameters (as bound vars). - // - // A note regarding the use of bound vars here: - // Imagine as an example - // ``` - // trait Family { - // type Member; - // } - // - // impl Family for VecFamily { - // type Member = i32; - // } - // ``` - // Here, we would generate - // ```notrust - // forall { Normalize(::Member => i32) } - // ``` - // when we really would like to generate - // ```notrust - // forall { Normalize(::Member => i32) :- Implemented(C: Eq) } - // ``` - // But, this is probably fine, because although the first clause can be used with types C that - // do not implement Eq, for it to cause some kind of problem, there would have to be a - // VecFamily::Member for some type X where !(X: Eq), that appears in the value of type - // Member = .... That type would fail a well-formedness check that we ought to be doing - // elsewhere, which would check that any ::Member meets the bounds declared in - // the trait (notably, that X: Eq and T: Family). - let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = - smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); - // 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( - tcx, - impl_ty.def_id, - |param, _| match param.kind { - GenericParamDefKind::Type { .. } => { - let kind = ty::BoundTyKind::Param(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Ty(kind); - bound_vars.push(bound_var); - Ty::new_bound( - tcx, - ty::INNERMOST, - ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() - } - GenericParamDefKind::Lifetime => { - let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Region(kind); - bound_vars.push(bound_var); - ty::Region::new_late_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() - } - GenericParamDefKind::Const { .. } => { - let bound_var = ty::BoundVariableKind::Const; - bound_vars.push(bound_var); - ty::Const::new_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(bound_vars.len() - 1), - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into() - } - }, - ); - // When checking something like - // - // trait X { type Y: PartialEq<::Y> } - // impl X for T { default type Y = S; } - // - // We will have to prove the bound S: PartialEq<::Y>. In this case - // we want ::Y to normalize to S. This is valid because we are - // checking the default value specifically here. Add this equality to the - // ParamEnv for normalization specifically. - let normalize_impl_ty = 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 normalize_param_env = { - let mut predicates = param_env.caller_bounds().iter().collect::>(); - match normalize_impl_ty.kind() { - ty::Alias(ty::Projection, proj) - if proj.def_id == trait_ty.def_id && proj.args == rebased_args => - { - // Don't include this predicate if the projected type is - // exactly the same as the projection. This can occur in - // (somewhat dubious) code like this: - // - // impl X for T where T: X { type Y = ::Y; } - } - _ => predicates.push( - ty::Binder::bind_with_vars( - ty::ProjectionPredicate { - projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args), - term: normalize_impl_ty.into(), - }, - bound_vars, - ) - .to_predicate(tcx), - ), - }; - ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) - }; - debug!(?normalize_param_env); + let param_env = param_env_with_gat_bounds(tcx, trait_ty, impl_ty, impl_trait_ref); + debug!(?param_env); + let container_id = impl_ty.container_id(tcx); let impl_ty_def_id = impl_ty.def_id.expect_local(); let impl_ty_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id); let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); @@ -2336,8 +2218,7 @@ pub(super) fn check_type_bounds<'tcx>( debug!("check_type_bounds: item_bounds={:?}", obligations); for mut obligation in util::elaborate(tcx, obligations) { - let normalized_predicate = - ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate); + let normalized_predicate = ocx.normalize(&normalize_cause, param_env, obligation.predicate); debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); obligation.predicate = normalized_predicate; @@ -2358,6 +2239,145 @@ pub(super) fn check_type_bounds<'tcx>( ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) } +/// Install projection predicates that allow GATs to project to their own +/// definition types. This is not allowed in general in cases of default +/// associated types in trait definitions, or when specialization is involved, +/// but is needed when checking these definition types actually satisfy the +/// trait bounds of the GAT. +/// +/// # How it works +/// +/// ```ignore (example) +/// impl Foo for (A, B) { +/// type Bar = Wrapper +/// } +/// ``` +/// +/// - `impl_trait_ref` would be `<(A, B) as Foo>` +/// - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) +/// - `normalize_impl_ty` would be `Wrapper` +/// - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from +/// the *trait* with the generic associated type parameters (as bound vars). +/// +/// A note regarding the use of bound vars here: +/// Imagine as an example +/// ``` +/// trait Family { +/// type Member; +/// } +/// +/// impl Family for VecFamily { +/// type Member = i32; +/// } +/// ``` +/// Here, we would generate +/// ```ignore (pseudo-rust) +/// forall { Normalize(::Member => i32) } +/// ``` +/// +/// when we really would like to generate +/// ```ignore (pseudo-rust) +/// forall { Normalize(::Member => i32) :- Implemented(C: Eq) } +/// ``` +/// +/// But, this is probably fine, because although the first clause can be used with types `C` that +/// do not implement `Eq`, for it to cause some kind of problem, there would have to be a +/// `VecFamily::Member` for some type `X` where `!(X: Eq)`, that appears in the value of type +/// `Member = ....` That type would fail a well-formedness check that we ought to be doing +/// elsewhere, which would check that any `::Member` meets the bounds declared in +/// the trait (notably, that `X: Eq` and `T: Family`). +fn param_env_with_gat_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ty: ty::AssocItem, + impl_ty: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> ty::ParamEnv<'tcx> { + let param_env = tcx.param_env(impl_ty.def_id); + let container_id = impl_ty.container_id(tcx); + let mut predicates = param_env.caller_bounds().to_vec(); + + let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = + smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); + // 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( + tcx, + impl_ty.def_id, + |param, _| match param.kind { + GenericParamDefKind::Type { .. } => { + let kind = ty::BoundTyKind::Param(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Ty(kind); + bound_vars.push(bound_var); + Ty::new_bound( + tcx, + ty::INNERMOST, + ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, + ) + .into() + } + GenericParamDefKind::Lifetime => { + let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Region(kind); + bound_vars.push(bound_var); + ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, + ) + .into() + } + GenericParamDefKind::Const { .. } => { + let bound_var = ty::BoundVariableKind::Const; + bound_vars.push(bound_var); + ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), + tcx.type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"), + ) + .into() + } + }, + ); + // When checking something like + // + // trait X { type Y: PartialEq<::Y> } + // impl X for T { default type Y = S; } + // + // We will have to prove the bound S: PartialEq<::Y>. In this case + // we want ::Y to normalize to S. This is valid because we are + // checking the default value specifically here. Add this equality to the + // ParamEnv for normalization specifically. + let normalize_impl_ty = 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); + + match normalize_impl_ty.kind() { + ty::Alias(ty::Projection, proj) + if proj.def_id == trait_ty.def_id && proj.args == rebased_args => + { + // Don't include this predicate if the projected type is + // exactly the same as the projection. This can occur in + // (somewhat dubious) code like this: + // + // impl X for T where T: X { type Y = ::Y; } + } + _ => predicates.push( + ty::Binder::bind_with_vars( + ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args), + term: normalize_impl_ty.into(), + }, + bound_vars, + ) + .to_predicate(tcx), + ), + }; + + ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) +} + fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { match impl_item.kind { ty::AssocKind::Const => "const", diff --git a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.rs b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.rs new file mode 100644 index 0000000000000..7b16870723976 --- /dev/null +++ b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.rs @@ -0,0 +1,18 @@ +// check-pass + +#![feature(associated_type_defaults)] + +trait Foo { + type Bar: Baz = i32; + // We should be able to prove that `i32: Baz` because of + // the impl below, which requires that `Self::Bar<()>: Eq` + // which is true, because we assume `for Self::Bar = i32`. +} + +trait Baz {} +impl Baz for i32 where T::Bar<()>: Eq {} + +trait Eq {} +impl Eq for T {} + +fn main() {} diff --git a/tests/ui/traits/new-solver/specialization-transmute.rs b/tests/ui/traits/new-solver/specialization-transmute.rs index 7523b8283215b..f6b19e7adf512 100644 --- a/tests/ui/traits/new-solver/specialization-transmute.rs +++ b/tests/ui/traits/new-solver/specialization-transmute.rs @@ -10,7 +10,7 @@ trait Default { } impl Default for T { - default type Id = T; //~ ERROR: type annotations needed + default type Id = T; // This will be fixed by #111994 fn intu(&self) -> &Self::Id { //~ ERROR type annotations needed self diff --git a/tests/ui/traits/new-solver/specialization-transmute.stderr b/tests/ui/traits/new-solver/specialization-transmute.stderr index 18965a465b3fa..09b1405fefbf3 100644 --- a/tests/ui/traits/new-solver/specialization-transmute.stderr +++ b/tests/ui/traits/new-solver/specialization-transmute.stderr @@ -16,13 +16,6 @@ LL | fn intu(&self) -> &Self::Id { | = note: cannot satisfy `::Id == _` -error[E0282]: type annotations needed - --> $DIR/specialization-transmute.rs:13:23 - | -LL | default type Id = T; - | ^ cannot infer type for associated type `::Id` - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to previous error; 1 warning emitted -Some errors have detailed explanations: E0282, E0284. -For more information about an error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/new-solver/specialization-unconstrained.rs b/tests/ui/traits/new-solver/specialization-unconstrained.rs index 7fd753109be2d..02150689ee5c3 100644 --- a/tests/ui/traits/new-solver/specialization-unconstrained.rs +++ b/tests/ui/traits/new-solver/specialization-unconstrained.rs @@ -11,7 +11,7 @@ trait Default { } impl Default for T { - default type Id = T; //~ ERROR type annotations needed + default type Id = T; } fn test, U>() {} diff --git a/tests/ui/traits/new-solver/specialization-unconstrained.stderr b/tests/ui/traits/new-solver/specialization-unconstrained.stderr index ed4dafa1484c2..910925cbaeb0d 100644 --- a/tests/ui/traits/new-solver/specialization-unconstrained.stderr +++ b/tests/ui/traits/new-solver/specialization-unconstrained.stderr @@ -20,13 +20,6 @@ note: required by a bound in `test` LL | fn test, U>() {} | ^^^^^^ required by this bound in `test` -error[E0282]: type annotations needed - --> $DIR/specialization-unconstrained.rs:14:22 - | -LL | default type Id = T; - | ^ cannot infer type for associated type `::Id` - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to previous error; 1 warning emitted -Some errors have detailed explanations: E0282, E0284. -For more information about an error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. From dd571e472ac46f1abda13f02e49085e458d26614 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 25 Oct 2023 01:30:46 +0000 Subject: [PATCH 2/2] Add all RPITITs when augmenting param-env with GAT bounds in check_type_bounds --- .../src/check/compare_impl_item.rs | 180 ++++++++++-------- .../in-trait/nested-rpitit-bounds.rs | 11 ++ 2 files changed, 114 insertions(+), 77 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index f7664b0c3a120..90babbb63a000 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2162,7 +2162,7 @@ pub(super) fn check_type_bounds<'tcx>( impl_ty: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> 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); 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`). fn param_env_with_gat_bounds<'tcx>( tcx: TyCtxt<'tcx>, - trait_ty: ty::AssocItem, impl_ty: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> ty::ParamEnv<'tcx> { @@ -2296,84 +2295,111 @@ fn param_env_with_gat_bounds<'tcx>( let container_id = impl_ty.container_id(tcx); let mut predicates = param_env.caller_bounds().to_vec(); - let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = - smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); - // 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( - tcx, - impl_ty.def_id, - |param, _| match param.kind { - GenericParamDefKind::Type { .. } => { - let kind = ty::BoundTyKind::Param(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Ty(kind); - bound_vars.push(bound_var); - Ty::new_bound( - tcx, - ty::INNERMOST, - ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() + // 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()) } - GenericParamDefKind::Lifetime => { - let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Region(kind); - bound_vars.push(bound_var); - ty::Region::new_late_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() + }; + + let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = + smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); + // 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(tcx, impl_ty.def_id, |param, _| match param.kind { + GenericParamDefKind::Type { .. } => { + let kind = ty::BoundTyKind::Param(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Ty(kind); + bound_vars.push(bound_var); + Ty::new_bound( + tcx, + ty::INNERMOST, + ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, + ) + .into() + } + GenericParamDefKind::Lifetime => { + let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Region(kind); + bound_vars.push(bound_var); + ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }, + ) + .into() + } + GenericParamDefKind::Const { .. } => { + let bound_var = ty::BoundVariableKind::Const; + bound_vars.push(bound_var); + ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), + tcx.type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"), + ) + .into() + } + }); + // When checking something like + // + // trait X { type Y: PartialEq<::Y> } + // impl X for T { default type Y = S; } + // + // We will have to prove the bound S: PartialEq<::Y>. In this case + // we want ::Y to normalize to S. This is valid because we are + // checking the default value specifically here. Add this equality to the + // ParamEnv for normalization specifically. + let normalize_impl_ty = + 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); + + match normalize_impl_ty.kind() { + ty::Alias(ty::Projection, proj) + if proj.def_id == trait_ty.def_id && proj.args == rebased_args => + { + // Don't include this predicate if the projected type is + // exactly the same as the projection. This can occur in + // (somewhat dubious) code like this: + // + // impl X for T where T: X { type Y = ::Y; } } - GenericParamDefKind::Const { .. } => { - let bound_var = ty::BoundVariableKind::Const; - bound_vars.push(bound_var); - ty::Const::new_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(bound_vars.len() - 1), - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), + _ => predicates.push( + ty::Binder::bind_with_vars( + ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args), + term: normalize_impl_ty.into(), + }, + bound_vars, ) - .into() - } - }, - ); - // When checking something like - // - // trait X { type Y: PartialEq<::Y> } - // impl X for T { default type Y = S; } - // - // We will have to prove the bound S: PartialEq<::Y>. In this case - // we want ::Y to normalize to S. This is valid because we are - // checking the default value specifically here. Add this equality to the - // ParamEnv for normalization specifically. - let normalize_impl_ty = 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); - - match normalize_impl_ty.kind() { - ty::Alias(ty::Projection, proj) - if proj.def_id == trait_ty.def_id && proj.args == rebased_args => - { - // Don't include this predicate if the projected type is - // exactly the same as the projection. This can occur in - // (somewhat dubious) code like this: - // - // impl X for T where T: X { type Y = ::Y; } - } - _ => predicates.push( - ty::Binder::bind_with_vars( - ty::ProjectionPredicate { - projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args), - term: normalize_impl_ty.into(), - }, - bound_vars, - ) - .to_predicate(tcx), - ), - }; + .to_predicate(tcx), + ), + }; + } ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) } diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs b/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs new file mode 100644 index 0000000000000..b97fd7d1ffe90 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs @@ -0,0 +1,11 @@ +// check-pass + +use std::ops::Deref; + +trait Foo { + fn foo() -> impl Deref> { + &&() + } +} + +fn main() {}