Skip to content

Commit 3ef506f

Browse files
committed
Don't pick T: FnPtr nested goals
1 parent c234b83 commit 3ef506f

26 files changed

+388
-68
lines changed

Diff for: compiler/rustc_trait_selection/src/solve/fulfill.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -513,8 +513,27 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
513513
_ => ChildMode::PassThrough,
514514
};
515515

516+
let nested_goals = candidate.instantiate_nested_goals(self.span());
517+
518+
// If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as
519+
// an actual candidate, instead we should treat them as if the impl was never considered to
520+
// have potentially applied. As if `impl<A, R> Trait for for<..> fn(..A) -> R` was written
521+
// instead of `impl<T: FnPtr> Trait for T`.
522+
//
523+
// We do this as a separate loop so that we do not choose to tell the user about some nested
524+
// goal before we encounter a `T: FnPtr` nested goal.
525+
for nested_goal in &nested_goals {
526+
if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait()
527+
&& let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
528+
&& poly_trait_pred.def_id() == fn_ptr_trait
529+
&& let Err(NoSolution) = nested_goal.result()
530+
{
531+
return ControlFlow::Break(self.obligation.clone());
532+
}
533+
}
534+
516535
let mut impl_where_bound_count = 0;
517-
for nested_goal in candidate.instantiate_nested_goals(self.span()) {
536+
for nested_goal in nested_goals {
518537
trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
519538

520539
let make_obligation = |cause| Obligation {
@@ -605,7 +624,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
605624
}
606625
}
607626

608-
#[derive(Copy, Clone)]
627+
#[derive(Debug, Copy, Clone)]
609628
enum ChildMode<'tcx> {
610629
// Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
611630
// and skip all `GoalSource::Misc`, which represent useless obligations
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0277]: the trait bound `Foo: Trait` is not satisfied
2+
--> $DIR/dont-pick-fnptr-bound-as-leaf.rs:24:20
3+
|
4+
LL | requires_trait(Foo);
5+
| -------------- ^^^ the trait `Trait` is not implemented for `Foo`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
note: required by a bound in `requires_trait`
10+
--> $DIR/dont-pick-fnptr-bound-as-leaf.rs:19:22
11+
|
12+
LL | fn requires_trait<T: Trait>(_: T) {}
13+
| ^^^^^ required by this bound in `requires_trait`
14+
15+
error: aborting due to 1 previous error
16+
17+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0277]: the trait bound `Foo: Trait` is not satisfied
2+
--> $DIR/dont-pick-fnptr-bound-as-leaf.rs:24:20
3+
|
4+
LL | requires_trait(Foo);
5+
| -------------- ^^^ the trait `Trait` is not implemented for `Foo`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
note: required by a bound in `requires_trait`
10+
--> $DIR/dont-pick-fnptr-bound-as-leaf.rs:19:22
11+
|
12+
LL | fn requires_trait<T: Trait>(_: T) {}
13+
| ^^^^^ required by this bound in `requires_trait`
14+
15+
error: aborting due to 1 previous error
16+
17+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@ revisions: current next
2+
//@[next] compile-flags: -Znext-solver
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
5+
// When emitting an error for `Foo: Trait` not holding we attempt to find a nested goal
6+
// to give as the reason why the bound does not hold. This test checks that we do not
7+
// try to tell the user that `Foo: FnPtr` is unimplemented as that would be confusing.
8+
9+
#![feature(fn_ptr_trait)]
10+
11+
use std::marker::FnPtr;
12+
13+
trait Trait {}
14+
15+
impl<T: FnPtr> Trait for T {}
16+
17+
struct Foo;
18+
19+
fn requires_trait<T: Trait>(_: T) {}
20+
//~^ NOTE: required by a bound in `requires_trait`
21+
//~| NOTE: required by this bound in `requires_trait`
22+
23+
fn main() {
24+
requires_trait(Foo);
25+
//~^ ERROR: the trait bound `Foo: Trait` is not satisfied
26+
//~| NOTE: the trait `Trait` is not implemented for `Foo`
27+
//~| NOTE: required by a bound introduced by this call
28+
}

Diff for: tests/ui/typeck/bad-index-due-to-nested.stderr renamed to tests/ui/typeck/bad-index-due-to-nested.current.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0277]: the trait bound `K: Hash` is not satisfied
2-
--> $DIR/bad-index-due-to-nested.rs:20:5
2+
--> $DIR/bad-index-due-to-nested.rs:24:5
33
|
44
LL | map[k]
55
| ^^^ the trait `Hash` is not implemented for `K`
66
|
77
note: required for `HashMap<K, V>` to implement `Index<&K>`
8-
--> $DIR/bad-index-due-to-nested.rs:7:12
8+
--> $DIR/bad-index-due-to-nested.rs:11:12
99
|
1010
LL | impl<K, V> Index<&K> for HashMap<K, V>
1111
| ^^^^^^^^^ ^^^^^^^^^^^^^
@@ -18,13 +18,13 @@ LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V
1818
| +++++++++++++++++
1919

2020
error[E0277]: the trait bound `V: Copy` is not satisfied
21-
--> $DIR/bad-index-due-to-nested.rs:20:5
21+
--> $DIR/bad-index-due-to-nested.rs:24:5
2222
|
2323
LL | map[k]
2424
| ^^^ the trait `Copy` is not implemented for `V`
2525
|
2626
note: required for `HashMap<K, V>` to implement `Index<&K>`
27-
--> $DIR/bad-index-due-to-nested.rs:7:12
27+
--> $DIR/bad-index-due-to-nested.rs:11:12
2828
|
2929
LL | impl<K, V> Index<&K> for HashMap<K, V>
3030
| ^^^^^^^^^ ^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap<K, V>, k: K) -> &'a
3737
| +++++++++++++++++++
3838

3939
error[E0308]: mismatched types
40-
--> $DIR/bad-index-due-to-nested.rs:20:9
40+
--> $DIR/bad-index-due-to-nested.rs:24:9
4141
|
4242
LL | fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
4343
| - found this type parameter
@@ -52,7 +52,7 @@ LL | map[&k]
5252
| +
5353

5454
error[E0308]: mismatched types
55-
--> $DIR/bad-index-due-to-nested.rs:20:5
55+
--> $DIR/bad-index-due-to-nested.rs:24:5
5656
|
5757
LL | fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
5858
| - found this type parameter ----- expected `&'a V` because of return type

Diff for: tests/ui/typeck/bad-index-due-to-nested.next.stderr

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
error[E0277]: the trait bound `K: Hash` is not satisfied
2+
--> $DIR/bad-index-due-to-nested.rs:24:5
3+
|
4+
LL | map[k]
5+
| ^^^ the trait `Hash` is not implemented for `K`
6+
|
7+
note: required for `HashMap<K, V>` to implement `Index<&K>`
8+
--> $DIR/bad-index-due-to-nested.rs:11:12
9+
|
10+
LL | impl<K, V> Index<&K> for HashMap<K, V>
11+
| ^^^^^^^^^ ^^^^^^^^^^^^^
12+
LL | where
13+
LL | K: Hash,
14+
| ---- unsatisfied trait bound introduced here
15+
help: consider restricting type parameter `K` with trait `Hash`
16+
|
17+
LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
18+
| +++++++++++++++++
19+
20+
error[E0277]: the trait bound `V: Copy` is not satisfied
21+
--> $DIR/bad-index-due-to-nested.rs:24:5
22+
|
23+
LL | map[k]
24+
| ^^^ the trait `Copy` is not implemented for `V`
25+
|
26+
note: required for `HashMap<K, V>` to implement `Index<&K>`
27+
--> $DIR/bad-index-due-to-nested.rs:11:12
28+
|
29+
LL | impl<K, V> Index<&K> for HashMap<K, V>
30+
| ^^^^^^^^^ ^^^^^^^^^^^^^
31+
...
32+
LL | V: Copy,
33+
| ---- unsatisfied trait bound introduced here
34+
help: consider restricting type parameter `V` with trait `Copy`
35+
|
36+
LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap<K, V>, k: K) -> &'a V {
37+
| +++++++++++++++++++
38+
39+
error[E0308]: mismatched types
40+
--> $DIR/bad-index-due-to-nested.rs:24:9
41+
|
42+
LL | fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
43+
| - found this type parameter
44+
LL | map[k]
45+
| ^ expected `&K`, found type parameter `K`
46+
|
47+
= note: expected reference `&_`
48+
found type parameter `_`
49+
help: consider borrowing here
50+
|
51+
LL | map[&k]
52+
| +
53+
54+
error[E0277]: the trait bound `K: Hash` is not satisfied
55+
--> $DIR/bad-index-due-to-nested.rs:24:5
56+
|
57+
LL | map[k]
58+
| ^^^^^^ the trait `Hash` is not implemented for `K`
59+
|
60+
note: required for `HashMap<K, V>` to implement `Index<&K>`
61+
--> $DIR/bad-index-due-to-nested.rs:11:12
62+
|
63+
LL | impl<K, V> Index<&K> for HashMap<K, V>
64+
| ^^^^^^^^^ ^^^^^^^^^^^^^
65+
LL | where
66+
LL | K: Hash,
67+
| ---- unsatisfied trait bound introduced here
68+
help: consider restricting type parameter `K` with trait `Hash`
69+
|
70+
LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
71+
| +++++++++++++++++
72+
73+
error: aborting due to 4 previous errors
74+
75+
Some errors have detailed explanations: E0277, E0308.
76+
For more information about an error, try `rustc --explain E0277`.

Diff for: tests/ui/typeck/bad-index-due-to-nested.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
//@ revisions: current next
2+
//@[next] compile-flags: -Znext-solver
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
15
use std::hash::Hash;
26
use std::marker::PhantomData;
37
use std::ops::Index;
@@ -21,7 +25,8 @@ fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
2125
//~^ ERROR the trait bound `K: Hash` is not satisfied
2226
//~| ERROR the trait bound `V: Copy` is not satisfied
2327
//~| ERROR mismatched types
24-
//~| ERROR mismatched types
28+
//[current]~| ERROR mismatched types
29+
//[next]~^^^^^ ERROR the trait bound `K: Hash` is not satisfied
2530
}
2631

2732
fn main() {}

Diff for: tests/ui/union/union-derive-eq.stderr renamed to tests/ui/union/union-derive-eq.current.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied
2-
--> $DIR/union-derive-eq.rs:13:5
2+
--> $DIR/union-derive-eq.rs:21:5
33
|
44
LL | #[derive(Eq)]
55
| -- in this derive macro expansion

Diff for: tests/ui/union/union-derive-eq.next.stderr

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied
2+
--> $DIR/union-derive-eq.rs:21:5
3+
|
4+
LL | #[derive(Eq)]
5+
| -- in this derive macro expansion
6+
LL | union U2 {
7+
LL | a: PartialEqNotEq,
8+
| ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
9+
|
10+
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
11+
help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]`
12+
|
13+
LL + #[derive(Eq)]
14+
LL | struct PartialEqNotEq;
15+
|
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0277`.

Diff for: tests/ui/union/union-derive-eq.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1+
//@ revisions: current next
2+
//@[next] compile-flags: -Znext-solver
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
15
#[derive(Eq)] // OK
26
union U1 {
37
a: u8,
48
}
59

6-
impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } }
10+
impl PartialEq for U1 {
11+
fn eq(&self, rhs: &Self) -> bool {
12+
true
13+
}
14+
}
715

816
#[derive(PartialEq, Copy, Clone)]
917
struct PartialEqNotEq;
@@ -13,6 +21,10 @@ union U2 {
1321
a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: Eq` is not satisfied
1422
}
1523

16-
impl PartialEq for U2 { fn eq(&self, rhs: &Self) -> bool { true } }
24+
impl PartialEq for U2 {
25+
fn eq(&self, rhs: &Self) -> bool {
26+
true
27+
}
28+
}
1729

1830
fn main() {}

Diff for: tests/ui/wf/wf-trait-fn-arg.stderr renamed to tests/ui/wf/wf-trait-fn-arg.current.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
error[E0277]: the trait bound `Self: Eq` is not satisfied
2-
--> $DIR/wf-trait-fn-arg.rs:10:23
2+
--> $DIR/wf-trait-fn-arg.rs:16:23
33
|
44
LL | fn bar(&self, x: &Bar<Self>);
55
| ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
66
|
77
note: required by a bound in `Bar`
8-
--> $DIR/wf-trait-fn-arg.rs:7:14
8+
--> $DIR/wf-trait-fn-arg.rs:11:15
99
|
10-
LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
11-
| ^^ required by this bound in `Bar`
10+
LL | struct Bar<T: Eq + ?Sized> {
11+
| ^^ required by this bound in `Bar`
1212
help: consider further restricting `Self`
1313
|
1414
LL | fn bar(&self, x: &Bar<Self>) where Self: Eq;

Diff for: tests/ui/wf/wf-trait-fn-arg.next.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0277]: the trait bound `Self: Eq` is not satisfied
2+
--> $DIR/wf-trait-fn-arg.rs:16:23
3+
|
4+
LL | fn bar(&self, x: &Bar<Self>);
5+
| ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
6+
|
7+
help: consider further restricting `Self`
8+
|
9+
LL | fn bar(&self, x: &Bar<Self>) where Self: Eq;
10+
| ++++++++++++++
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0277`.

Diff for: tests/ui/wf/wf-trait-fn-arg.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
1+
//@ revisions: current next
2+
//@[next] compile-flags: -Znext-solver
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
15
// Check that we test WF conditions for fn arguments in a trait definition.
26

37
#![feature(rustc_attrs)]
48
#![allow(dead_code)]
59
#![allow(unused_variables)]
610

7-
struct Bar<T:Eq+?Sized> { value: Box<T> }
11+
struct Bar<T: Eq + ?Sized> {
12+
value: Box<T>,
13+
}
814

915
trait Foo {
1016
fn bar(&self, x: &Bar<Self>);
11-
//~^ ERROR E0277
12-
//
13-
// Here, Eq ought to be implemented.
17+
//~^ ERROR E0277
18+
//
19+
// Here, Eq ought to be implemented.
1420
}
1521

16-
fn main() { }
22+
fn main() {}

Diff for: tests/ui/wf/wf-trait-fn-ret.stderr renamed to tests/ui/wf/wf-trait-fn-ret.current.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
error[E0277]: the trait bound `Self: Eq` is not satisfied
2-
--> $DIR/wf-trait-fn-ret.rs:10:23
2+
--> $DIR/wf-trait-fn-ret.rs:15:23
33
|
44
LL | fn bar(&self) -> &Bar<Self>;
55
| ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
66
|
77
note: required by a bound in `Bar`
8-
--> $DIR/wf-trait-fn-ret.rs:7:14
8+
--> $DIR/wf-trait-fn-ret.rs:10:15
99
|
10-
LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
11-
| ^^ required by this bound in `Bar`
10+
LL | struct Bar<T: Eq + ?Sized> {
11+
| ^^ required by this bound in `Bar`
1212
help: consider further restricting `Self`
1313
|
1414
LL | fn bar(&self) -> &Bar<Self> where Self: Eq;

Diff for: tests/ui/wf/wf-trait-fn-ret.next.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0277]: the trait bound `Self: Eq` is not satisfied
2+
--> $DIR/wf-trait-fn-ret.rs:15:23
3+
|
4+
LL | fn bar(&self) -> &Bar<Self>;
5+
| ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
6+
|
7+
help: consider further restricting `Self`
8+
|
9+
LL | fn bar(&self) -> &Bar<Self> where Self: Eq;
10+
| ++++++++++++++
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)