diff options
| author | Tyler Mandry <tmandry@gmail.com> | 2020-07-23 01:34:35 -0700 |
|---|---|---|
| committer | Tyler Mandry <tmandry@gmail.com> | 2020-07-23 01:34:35 -0700 |
| commit | 83a9dc92d58c8145b3fb0cec5ea205ad66c399a7 (patch) | |
| tree | 48b9b1ae74d3fbe56c5ea296016aa93fc0a97a87 | |
| parent | 8ad7bc3f428300aee6764f6e23527e19eb235e81 (diff) | |
| download | rust-83a9dc92d58c8145b3fb0cec5ea205ad66c399a7.tar.gz rust-83a9dc92d58c8145b3fb0cec5ea205ad66c399a7.zip | |
Normalize bounds fully when checking defaulted types
| -rw-r--r-- | src/librustc_typeck/check/compare_method.rs | 36 | ||||
| -rw-r--r-- | src/test/ui/associated-type-bounds/issue-73818.rs | 25 |
2 files changed, 58 insertions, 3 deletions
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index a90ed455d04..fac87866b80 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -1196,8 +1196,6 @@ fn compare_projection_bounds<'tcx>( return Ok(()); } - let param_env = tcx.param_env(impl_ty.def_id); - // Given // // impl<A, B> Foo<u32> for (A, B) { @@ -1212,6 +1210,36 @@ fn compare_projection_bounds<'tcx>( impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs); let impl_ty_value = tcx.type_of(impl_ty.def_id); + let param_env = tcx.param_env(impl_ty.def_id); + + // When checking something like + // + // trait X { type Y: PartialEq<<Self as X>::Y> } + // impl X for T { default type Y = S; } + // + // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case + // 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 + // ParamEnv for normalization specifically. + let normalize_param_env = if impl_ty.defaultness.is_final() { + // If the associated type is final then normalization can already + // do this without the explicit predicate. + param_env + } else { + let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>(); + predicates.push( + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + item_def_id: trait_ty.def_id, + substs: rebased_substs, + }, + ty: impl_ty_value, + }) + .to_predicate(tcx), + ); + ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing, None) + }; + // Map the predicate from the trait to the corresponding one for the impl. // For example: // @@ -1275,9 +1303,11 @@ fn compare_projection_bounds<'tcx>( _ => bug!("unexepected projection predicate kind: `{:?}`", predicate), }; + debug!("compare_projection_bounds: concrete predicate = {:?}", concrete_ty_predicate); + let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize( &mut selcx, - param_env, + normalize_param_env, normalize_cause.clone(), &concrete_ty_predicate, ); diff --git a/src/test/ui/associated-type-bounds/issue-73818.rs b/src/test/ui/associated-type-bounds/issue-73818.rs new file mode 100644 index 00000000000..bb890f72a32 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-73818.rs @@ -0,0 +1,25 @@ +// Test that associated type bounds are correctly normalized when checking +// default associated type values. +// check-pass + +#![allow(incomplete_features)] +#![feature(specialization)] + +#[derive(PartialEq)] +enum Never {} +trait Foo { + type Assoc: PartialEq; // PartialEq<<Self as Foo>::Assoc> +} +impl<T> Foo for T { + default type Assoc = Never; +} + +trait Trait1 { + type Selection: PartialEq; +} +trait Trait2: PartialEq<Self> {} +impl<T: Trait2> Trait1 for T { + default type Selection = T; +} + +fn main() {} |
