Skip to content

Commit 83a9dc9

Browse files
committed
Normalize bounds fully when checking defaulted types
1 parent 8ad7bc3 commit 83a9dc9

File tree

2 files changed

+58
-3
lines changed

2 files changed

+58
-3
lines changed

src/librustc_typeck/check/compare_method.rs

+33-3
Original file line numberDiff line numberDiff line change
@@ -1196,8 +1196,6 @@ fn compare_projection_bounds<'tcx>(
11961196
return Ok(());
11971197
}
11981198

1199-
let param_env = tcx.param_env(impl_ty.def_id);
1200-
12011199
// Given
12021200
//
12031201
// impl<A, B> Foo<u32> for (A, B) {
@@ -1212,6 +1210,36 @@ fn compare_projection_bounds<'tcx>(
12121210
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
12131211
let impl_ty_value = tcx.type_of(impl_ty.def_id);
12141212

1213+
let param_env = tcx.param_env(impl_ty.def_id);
1214+
1215+
// When checking something like
1216+
//
1217+
// trait X { type Y: PartialEq<<Self as X>::Y> }
1218+
// impl X for T { default type Y = S; }
1219+
//
1220+
// We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
1221+
// we want <T as X>::Y to normalize to S. This is valid because we are
1222+
// checking the default value specifically here. Add this equality to the
1223+
// ParamEnv for normalization specifically.
1224+
let normalize_param_env = if impl_ty.defaultness.is_final() {
1225+
// If the associated type is final then normalization can already
1226+
// do this without the explicit predicate.
1227+
param_env
1228+
} else {
1229+
let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
1230+
predicates.push(
1231+
ty::Binder::dummy(ty::ProjectionPredicate {
1232+
projection_ty: ty::ProjectionTy {
1233+
item_def_id: trait_ty.def_id,
1234+
substs: rebased_substs,
1235+
},
1236+
ty: impl_ty_value,
1237+
})
1238+
.to_predicate(tcx),
1239+
);
1240+
ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing, None)
1241+
};
1242+
12151243
// Map the predicate from the trait to the corresponding one for the impl.
12161244
// For example:
12171245
//
@@ -1275,9 +1303,11 @@ fn compare_projection_bounds<'tcx>(
12751303
_ => bug!("unexepected projection predicate kind: `{:?}`", predicate),
12761304
};
12771305

1306+
debug!("compare_projection_bounds: concrete predicate = {:?}", concrete_ty_predicate);
1307+
12781308
let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
12791309
&mut selcx,
1280-
param_env,
1310+
normalize_param_env,
12811311
normalize_cause.clone(),
12821312
&concrete_ty_predicate,
12831313
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Test that associated type bounds are correctly normalized when checking
2+
// default associated type values.
3+
// check-pass
4+
5+
#![allow(incomplete_features)]
6+
#![feature(specialization)]
7+
8+
#[derive(PartialEq)]
9+
enum Never {}
10+
trait Foo {
11+
type Assoc: PartialEq; // PartialEq<<Self as Foo>::Assoc>
12+
}
13+
impl<T> Foo for T {
14+
default type Assoc = Never;
15+
}
16+
17+
trait Trait1 {
18+
type Selection: PartialEq;
19+
}
20+
trait Trait2: PartialEq<Self> {}
21+
impl<T: Trait2> Trait1 for T {
22+
default type Selection = T;
23+
}
24+
25+
fn main() {}

0 commit comments

Comments
 (0)