Skip to content

Commit

Permalink
Auto merge of #122317 - compiler-errors:fulfill-method-probe, r=lcnr
Browse files Browse the repository at this point in the history
Use fulfillment in method probe, not evaluation

This PR reworks method probing to use fulfillment instead of a `for`-loop of `evaluate_predicate` calls, and moves normalization from method candidate assembly into the `consider_probe`, where it's applied to *all* candidates. This last part coincidentally fixes #121643 (comment).

Regarding *why* this large rewrite is done: In general, it's an anti-pattern to do `for o in obligations { evaluate(o); }` because it's not compatible with the way that the new solver emits alias-relate obligations which constrain variables that may show up in other predicates.

r? lcnr
  • Loading branch information
bors committed Apr 23, 2024
2 parents ad07aa1 + 8995c2c commit cd90d5c
Show file tree
Hide file tree
Showing 19 changed files with 322 additions and 457 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
[candidate] => format!(
"the method of the same name on {} `{}`",
match candidate.kind {
probe::CandidateKind::InherentImplCandidate(..) => "the inherent impl for",
probe::CandidateKind::InherentImplCandidate(_) => "the inherent impl for",
_ => "trait",
},
self.tcx.def_path_str(candidate.item.container_id(self.tcx))
Expand Down
518 changes: 174 additions & 344 deletions compiler/rustc_hir_typeck/src/method/probe.rs

Large diffs are not rendered by default.

27 changes: 4 additions & 23 deletions tests/ui/derives/issue-91550.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ error[E0599]: the method `insert` exists for struct `HashSet<Value>`, but its tr
--> $DIR/issue-91550.rs:8:8
|
LL | struct Value(u32);
| ------------ doesn't satisfy `Value: Eq`, `Value: Hash` or `Value: PartialEq`
| ------------ doesn't satisfy `Value: Eq` or `Value: Hash`
...
LL | hs.insert(Value(0));
| ^^^^^^
|
= note: the following trait bounds were not satisfied:
`Value: Eq`
`Value: PartialEq`
which is required by `Value: Eq`
`Value: Hash`
help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]`
|
Expand All @@ -22,7 +20,7 @@ error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its
--> $DIR/issue-91550.rs:26:9
|
LL | pub struct NoDerives;
| -------------------- doesn't satisfy `NoDerives: Eq` or `NoDerives: PartialEq`
| -------------------- doesn't satisfy `NoDerives: Eq`
LL |
LL | struct Object<T>(T);
| ---------------- method `use_eq` not found for this struct
Expand All @@ -37,9 +35,6 @@ LL | impl<T: Eq> Object<T> {
| ^^ ---------
| |
| unsatisfied trait bound introduced here
= note: the following trait bounds were not satisfied:
`NoDerives: PartialEq`
which is required by `NoDerives: Eq`
help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]`
|
LL + #[derive(Eq, PartialEq)]
Expand All @@ -50,7 +45,7 @@ error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but it
--> $DIR/issue-91550.rs:27:9
|
LL | pub struct NoDerives;
| -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd`
| -------------------- doesn't satisfy `NoDerives: Ord`
LL |
LL | struct Object<T>(T);
| ---------------- method `use_ord` not found for this struct
Expand All @@ -65,13 +60,6 @@ LL | impl<T: Ord> Object<T> {
| ^^^ ---------
| |
| unsatisfied trait bound introduced here
= note: the following trait bounds were not satisfied:
`NoDerives: PartialOrd`
which is required by `NoDerives: Ord`
`NoDerives: PartialEq`
which is required by `NoDerives: Ord`
`NoDerives: Eq`
which is required by `NoDerives: Ord`
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
|
LL + #[derive(Eq, Ord, PartialEq, PartialOrd)]
Expand All @@ -82,7 +70,7 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object<NoD
--> $DIR/issue-91550.rs:28:9
|
LL | pub struct NoDerives;
| -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd`
| -------------------- doesn't satisfy `NoDerives: Ord` or `NoDerives: PartialOrd`
LL |
LL | struct Object<T>(T);
| ---------------- method `use_ord_and_partial_ord` not found for this struct
Expand All @@ -100,13 +88,6 @@ LL | impl<T: Ord + PartialOrd> Object<T> {
| | |
| | unsatisfied trait bound introduced here
| unsatisfied trait bound introduced here
= note: the following trait bounds were not satisfied:
`NoDerives: PartialEq`
which is required by `NoDerives: Ord`
`NoDerives: Eq`
which is required by `NoDerives: Ord`
`NoDerives: PartialEq`
which is required by `NoDerives: PartialOrd`
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
|
LL + #[derive(Eq, Ord, PartialEq, PartialOrd)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ where

fn main() {
let mut list = RcNode::<i32>::new();
//~^ ERROR trait bounds were not satisfied
//~^ ERROR the variant or associated item `new` exists for enum `Node<i32, RcFamily>`, but its trait bounds were not satisfied
}
11 changes: 8 additions & 3 deletions tests/ui/impl-trait/issues/issue-62742.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
use std::marker::PhantomData;

fn _alias_check() {
fn a() {
WrongImpl::foo(0i32);
//~^ ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
//~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
//~^ ERROR overflow assigning `_` to `[_]`
}

fn b() {
WrongImpl::<()>::foo(0i32);
//~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied
//~| ERROR trait bounds were not satisfied
}

fn c() {
CorrectImpl::foo(0i32);
}

Expand Down
44 changes: 11 additions & 33 deletions tests/ui/impl-trait/issues/issue-62742.stderr
Original file line number Diff line number Diff line change
@@ -1,33 +1,11 @@
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
--> $DIR/issue-62742.rs:4:5
error[E0275]: overflow assigning `_` to `[_]`
--> $DIR/issue-62742.rs:4:16
|
LL | WrongImpl::foo(0i32);
| ^^^^^^^^^^^^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
|
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
note: required by a bound in `SafeImpl::<T, A>::foo`
--> $DIR/issue-62742.rs:29:20
|
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
| ^^^^^^ required by this bound in `SafeImpl::<T, A>::foo`
LL | pub fn foo(value: A::Value) {}
| --- required by a bound in this associated function

error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
--> $DIR/issue-62742.rs:4:5
|
LL | WrongImpl::foo(0i32);
| ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
|
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:27:35
|
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ^^^^^^ required by this bound in `SafeImpl`
| ^^^

error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied
--> $DIR/issue-62742.rs:7:22
--> $DIR/issue-62742.rs:9:22
|
LL | WrongImpl::<()>::foo(0i32);
| ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds
Expand All @@ -39,33 +17,33 @@ LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ----------------------------------------- function or associated item `foo` not found for this struct
|
note: trait bound `RawImpl<()>: Raw<()>` was not satisfied
--> $DIR/issue-62742.rs:29:20
--> $DIR/issue-62742.rs:34:20
|
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
| ^^^^^^ --------------
| |
| unsatisfied trait bound introduced here
note: the trait `Raw` must be implemented
--> $DIR/issue-62742.rs:13:1
--> $DIR/issue-62742.rs:18:1
|
LL | pub trait Raw<T: ?Sized> {
| ^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied
--> $DIR/issue-62742.rs:7:5
--> $DIR/issue-62742.rs:9:5
|
LL | WrongImpl::<()>::foo(0i32);
| ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>`
|
= help: the trait `Raw<[()]>` is implemented for `RawImpl<()>`
= help: for that trait implementation, expected `[()]`, found `()`
note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:27:35
--> $DIR/issue-62742.rs:32:35
|
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ^^^^^^ required by this bound in `SafeImpl`

error: aborting due to 4 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0275, E0277, E0599.
For more information about an error, try `rustc --explain E0275`.
3 changes: 2 additions & 1 deletion tests/ui/impl-trait/issues/issue-84073.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ where
}

fn main() {
Race::new(|race| race.when()); //~ ERROR overflow assigning `_` to `Option<_>`
Race::new(|race| race.when());
//~^ ERROR overflow assigning `_` to `Option<_>`
}
4 changes: 2 additions & 2 deletions tests/ui/impl-trait/issues/issue-84073.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0275]: overflow assigning `_` to `Option<_>`
--> $DIR/issue-84073.rs:32:22
--> $DIR/issue-84073.rs:32:27
|
LL | Race::new(|race| race.when());
| ^^^^
| ^^^^

error: aborting due to 1 previous error

Expand Down
32 changes: 32 additions & 0 deletions tests/ui/methods/fulfillment-disqualifies-method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Tests that using fulfillment in the trait solver means that we detect that a
// method is impossible, leading to no ambiguity.
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

#[derive(Default)]
struct W<A, B>(A, B);

trait Constrain {
type Output;
}

impl Constrain for i32 {
type Output = u32;
}

trait Impossible {}

impl<A, B> W<A, B> where A: Constrain<Output = B>, B: Impossible {
fn method(&self) {}
}

impl W<i32, u32> {
fn method(&self) {}
}

fn main() {
let w: W<i32, _> = W::default();
w.method();
}
26 changes: 26 additions & 0 deletions tests/ui/methods/leak-check-disquality.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Tests that using fulfillment in the trait solver means that we detect that a
// method is impossible, leading to no ambiguity.
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

struct W<T, U>(Option<T>, Option<U>);

impl<'a> W<fn(&'a ()), u32> {
fn method(&self) {}
}

trait Leak {}
impl<T: Fn(&())> Leak for T {}

impl<T: Leak> W<T, i32> {
fn method(&self) {}
}

fn test<'a>() {
let x: W<fn(&'a ()), _> = W(None, None);
x.method();
}

fn main() {}
24 changes: 24 additions & 0 deletions tests/ui/methods/self-type-is-sup-no-eq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//@ check-pass

// Test that we use `sup` not `eq` during method probe, since this has an effect
// on the leak check. This is (conceptually) minimized from a crater run for
// `wrend 0.3.6`.

use std::ops::Deref;

struct A;

impl Deref for A {
type Target = B<dyn Fn(&())>;

fn deref(&self) -> &<Self as Deref>::Target { todo!() }
}

struct B<T: ?Sized>(T);
impl<T> B<dyn Fn(T)> {
fn method(&self) {}
}

fn main() {
A.method();
}
2 changes: 0 additions & 2 deletions tests/ui/missing-trait-bounds/issue-35677.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ LL | this.is_subset(other)
|
= note: the following trait bounds were not satisfied:
`T: Eq`
`T: PartialEq`
which is required by `T: Eq`
`T: Hash`
help: consider restricting the type parameters to satisfy the trait bounds
|
Expand Down
4 changes: 3 additions & 1 deletion tests/ui/nll/issue-57362-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ impl<'a> X for fn(&'a ()) {
}
}

// FIXME(@compiler-errors): This error message is less than helpful.
fn g() {
let x = <fn (&())>::make_g(); //~ ERROR the function
let x = <fn (&())>::make_g();
//~^ ERROR no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope
}

fn main() {}
8 changes: 3 additions & 5 deletions tests/ui/nll/issue-57362-2.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
error[E0599]: the function or associated item `make_g` exists for fn pointer `fn(&())`, but its trait bounds were not satisfied
--> $DIR/issue-57362-2.rs:22:25
error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope
--> $DIR/issue-57362-2.rs:23:25
|
LL | let x = <fn (&())>::make_g();
| ^^^^^^ function or associated item cannot be called on `fn(&())` due to unsatisfied trait bounds
| ^^^^^^ function or associated item not found in `fn(&())`
|
= note: the following trait bounds were not satisfied:
`for<'a> fn(&'a ()): X`
= help: items from traits can only be used if the trait is implemented and in scope
note: `X` defines an item `make_g`, perhaps you need to implement it
--> $DIR/issue-57362-2.rs:8:1
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/nll/issue-57642-higher-ranked-subtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ impl<T> Y for fn(T) {
}

fn higher_ranked_region_has_lost_its_binder() {
let x = <fn (&())>::make_g(); //~ ERROR the function
let x = <fn (&())>::make_g();
//~^ ERROR no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope
}

fn magical() {
Expand Down
8 changes: 3 additions & 5 deletions tests/ui/nll/issue-57642-higher-ranked-subtype.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
error[E0599]: the function or associated item `make_g` exists for fn pointer `fn(&())`, but its trait bounds were not satisfied
error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope
--> $DIR/issue-57642-higher-ranked-subtype.rs:31:25
|
LL | let x = <fn (&())>::make_g();
| ^^^^^^ function or associated item cannot be called on `fn(&())` due to unsatisfied trait bounds
| ^^^^^^ function or associated item not found in `fn(&())`
|
= note: the following trait bounds were not satisfied:
`for<'a> fn(&'a ()): X`
= help: items from traits can only be used if the trait is implemented and in scope
note: `X` defines an item `make_g`, perhaps you need to implement it
--> $DIR/issue-57642-higher-ranked-subtype.rs:4:1
Expand All @@ -14,7 +12,7 @@ LL | trait X {
| ^^^^^^^

error[E0599]: no function or associated item named `make_f` found for fn pointer `for<'a> fn(&'a ())` in the current scope
--> $DIR/issue-57642-higher-ranked-subtype.rs:35:25
--> $DIR/issue-57642-higher-ranked-subtype.rs:36:25
|
LL | let x = <fn (&())>::make_f();
| ^^^^^^ function or associated item not found in `fn(&())`
Expand Down
Loading

0 comments on commit cd90d5c

Please sign in to comment.