Skip to content

Commit 39ee66a

Browse files
committed
Consider well-formed predicates in min-specialization
1 parent 4377ac3 commit 39ee66a

File tree

4 files changed

+82
-4
lines changed

4 files changed

+82
-4
lines changed

src/librustc_typeck/impl_wf_check/min_specialization.rs

+23-4
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
//! in the *unconstrained* substs for `impl2`. A parameter is constrained if
2222
//! its value is completely determined by an associated type projection
2323
//! predicate.
24-
//! 4. Check that all predicates on `impl1` also exist on `impl2` (after
25-
//! matching substs).
24+
//! 4. Check that all predicates on `impl1` either exist on `impl2` (after
25+
//! matching substs), or are well-formed predicates for the trait's type
26+
//! arguments.
2627
//!
2728
//! ## Example
2829
//!
@@ -129,7 +130,7 @@ fn check_always_applicable(
129130
check_static_lifetimes(tcx, &parent_substs, span);
130131
check_duplicate_params(tcx, impl1_substs, &parent_substs, span);
131132

132-
check_predicates(tcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span);
133+
check_predicates(infcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span);
133134
}
134135
}
135136

@@ -282,14 +283,17 @@ fn check_static_lifetimes<'tcx>(
282283
/// * on the base `impl impl2`
283284
/// * Currently this check is done using syntactic equality, which is
284285
/// conservative but generally sufficient.
286+
/// * a well-formed predicate of a type argument of the trait being implemented,
287+
/// including the `Self`-type.
285288
fn check_predicates<'tcx>(
286-
tcx: TyCtxt<'tcx>,
289+
infcx: &InferCtxt<'_, 'tcx>,
287290
impl1_def_id: DefId,
288291
impl1_substs: SubstsRef<'tcx>,
289292
impl2_node: Node,
290293
impl2_substs: SubstsRef<'tcx>,
291294
span: Span,
292295
) {
296+
let tcx = infcx.tcx;
293297
let impl1_predicates = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
294298
let mut impl2_predicates = if impl2_node.is_from_trait() {
295299
// Always applicable traits have to be always applicable without any
@@ -329,6 +333,21 @@ fn check_predicates<'tcx>(
329333
})
330334
.copied()
331335
.collect();
336+
337+
// Include the well-formed predicates of the type parameters of the impl.
338+
for ty in tcx.impl_trait_ref(impl1_def_id).unwrap().substs.types() {
339+
if let Some(obligations) = wf::obligations(
340+
infcx,
341+
tcx.param_env(impl1_def_id),
342+
tcx.hir().as_local_hir_id(impl1_def_id).unwrap(),
343+
ty,
344+
span,
345+
) {
346+
impl2_predicates
347+
.predicates
348+
.extend(obligations.into_iter().map(|obligation| obligation.predicate))
349+
}
350+
}
332351
impl2_predicates.predicates.extend(traits::elaborate_predicates(tcx, always_applicable_traits));
333352

334353
for predicate in impl1_predicates.predicates {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Test that specializing on the well-formed predicates of the trait and
2+
// self-type of an impl is allowed.
3+
4+
// check-pass
5+
6+
#![feature(min_specialization)]
7+
8+
struct OrdOnly<T: Ord>(T);
9+
10+
trait SpecTrait<U> {
11+
fn f();
12+
}
13+
14+
impl<T, U> SpecTrait<U> for T {
15+
default fn f() {}
16+
}
17+
18+
impl<T: Ord> SpecTrait<()> for OrdOnly<T> {
19+
fn f() {}
20+
}
21+
22+
impl<T: Ord> SpecTrait<OrdOnly<T>> for () {
23+
fn f() {}
24+
}
25+
26+
impl<T: Ord, U: Ord, V: Ord> SpecTrait<(OrdOnly<T>, OrdOnly<U>)> for &[OrdOnly<V>] {
27+
fn f() {}
28+
}
29+
30+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Test that supertraits can't be assumed in impls of
2+
// `rustc_specialization_trait`, as such impls would
3+
// allow specializing on the supertrait.
4+
5+
#![feature(min_specialization)]
6+
#![feature(rustc_attrs)]
7+
8+
#[rustc_specialization_trait]
9+
trait SpecMarker: Default {
10+
fn f();
11+
}
12+
13+
impl<T: Default> SpecMarker for T {
14+
//~^ ERROR cannot specialize
15+
fn f() {}
16+
}
17+
18+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: cannot specialize on trait `std::default::Default`
2+
--> $DIR/specialization_super_trait.rs:13:1
3+
|
4+
LL | / impl<T: Default> SpecMarker for T {
5+
LL | |
6+
LL | | fn f() {}
7+
LL | | }
8+
| |_^
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)