Rollup merge of #108254 - Nathan-Fenner:nathanf/error-span-ref-trait-refine, r=WaffleLapkin

Refine error span for trait error into borrowed expression

Extends the error span refinement in #106477 to drill into borrowed expressions just like tuples/struct/enum literals. For example,

```rs
trait Fancy {}
trait Good {}
impl <'a, T> Fancy for &'a T where T: Good {}
impl <S> Good for Option<S> where S: Iterator {}

fn want_fancy<F>(f: F) where F: Fancy {}

fn example() {
    want_fancy(&Some(5));
//  (BEFORE)   ^^^^^^^^ `{integer}` is not an iterator
//  (AFTER)          ^  `{integer}` is not an iterator
}
```

Existing heuristics try to find the right part of the expression to "point at"; current heuristics look at e.g. struct constructors and tuples. This PR adds a new check for borrowed expressions when looking into a borrowed type.
This commit is contained in:
Matthias Krüger 2023-02-20 22:12:18 +01:00 committed by GitHub
commit 194d52cc18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 16 deletions

View File

@ -549,6 +549,19 @@ fn blame_specific_part_of_expr_corresponding_to_generic_param(
return Err(expr);
};
if let (
hir::ExprKind::AddrOf(_borrow_kind, _borrow_mutability, borrowed_expr),
ty::Ref(_ty_region, ty_ref_type, _ty_mutability),
) = (&expr.kind, in_ty.kind())
{
// We can "drill into" the borrowed expression.
return self.blame_specific_part_of_expr_corresponding_to_generic_param(
param,
borrowed_expr,
(*ty_ref_type).into(),
);
}
if let (hir::ExprKind::Tup(expr_elements), ty::Tuple(in_ty_elements)) =
(&expr.kind, in_ty.kind())
{

View File

@ -71,6 +71,8 @@ struct DoubleWrapper<T> {
impl<T: T1> T1 for DoubleWrapper<T> {}
impl<'a, T: T2> T1 for &'a T {}
fn example<Q>(q: Q) {
// In each of the following examples, we expect the error span to point at the 'q' variable,
// since the missing constraint is `Q: T3`.
@ -126,6 +128,10 @@ fn example<Q>(q: Q) {
Two { a: Two { a: (), b: Two { a: Two { a: (), b: q }, b: () } }, b: () },
//~^ ERROR the trait bound `Q: T1` is not satisfied [E0277]
);
// Verifies for reference:
want(&Burrito { spicy: false, filling: q });
//~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
}
fn main() {}

View File

@ -1,5 +1,5 @@
error[E0277]: the trait bound `Q: T3` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:79:60
--> $DIR/blame-trait-error-spans-on-exprs.rs:81:60
|
LL | want(Wrapper { value: Burrito { spicy: false, filling: q } });
| ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`
@ -29,7 +29,7 @@ LL | fn example<Q: T3>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T3` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:83:84
--> $DIR/blame-trait-error-spans-on-exprs.rs:85:84
|
LL | want(Wrapper { value: BurritoKinds::SmallBurrito { spicy: true, small_filling: q } });
| ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`
@ -59,7 +59,7 @@ LL | fn example<Q: T3>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T3` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:87:39
--> $DIR/blame-trait-error-spans-on-exprs.rs:89:39
|
LL | want(Wrapper { value: Taco(false, q) });
| ---- ^ the trait `T3` is not implemented for `Q`
@ -91,7 +91,7 @@ LL | fn example<Q: T3>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T3` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:91:27
--> $DIR/blame-trait-error-spans-on-exprs.rs:93:27
|
LL | want(Wrapper { value: TacoKinds::OneTaco(false, q) });
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q`
@ -123,7 +123,7 @@ LL | fn example<Q: T3>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T3` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:95:74
--> $DIR/blame-trait-error-spans-on-exprs.rs:97:74
|
LL | want(Wrapper { value: GenericBurrito { spiciness: NotSpicy, filling: q } });
| ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`
@ -153,7 +153,7 @@ LL | fn example<Q: T3>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T2` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:99:14
--> $DIR/blame-trait-error-spans-on-exprs.rs:101:14
|
LL | want((3, q));
| ---- ^ the trait `T2` is not implemented for `Q`
@ -178,7 +178,7 @@ LL | fn example<Q: T2>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T3` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:103:31
--> $DIR/blame-trait-error-spans-on-exprs.rs:105:31
|
LL | want(Wrapper { value: (3, q) });
| ---- ^ the trait `T3` is not implemented for `Q`
@ -210,7 +210,7 @@ LL | fn example<Q: T3>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T3` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:107:15
--> $DIR/blame-trait-error-spans-on-exprs.rs:109:15
|
LL | want(((3, q), 5));
| ---- ^ the trait `T3` is not implemented for `Q`
@ -242,7 +242,7 @@ LL | fn example<Q: T3>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T1` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:110:49
--> $DIR/blame-trait-error-spans-on-exprs.rs:112:49
|
LL | want(DoubleWrapper { item: Wrapper { value: q } });
| ---- ^ the trait `T1` is not implemented for `Q`
@ -267,7 +267,7 @@ LL | fn example<Q: T1>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T1` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:113:88
--> $DIR/blame-trait-error-spans-on-exprs.rs:115:88
|
LL | want(DoubleWrapper { item: Wrapper { value: DoubleWrapper { item: Wrapper { value: q } } } });
| ---- required by a bound introduced by this call ^ the trait `T1` is not implemented for `Q`
@ -292,7 +292,7 @@ LL | fn example<Q: T1>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T3` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:117:27
--> $DIR/blame-trait-error-spans-on-exprs.rs:119:27
|
LL | want(Wrapper { value: AliasBurrito { spiciness: q, filling: q } });
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q`
@ -324,7 +324,7 @@ LL | fn example<Q: T3>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T1` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:120:35
--> $DIR/blame-trait-error-spans-on-exprs.rs:122:35
|
LL | want(Two { a: Two { a: (), b: q }, b: () });
| ---- ^ the trait `T1` is not implemented for `Q`
@ -349,7 +349,7 @@ LL | fn example<Q: T1>(q: Q) {
| ++++
error[E0277]: the trait bound `Q: T1` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:126:59
--> $DIR/blame-trait-error-spans-on-exprs.rs:128:59
|
LL | want(
| ---- required by a bound introduced by this call
@ -375,6 +375,38 @@ help: consider restricting type parameter `Q`
LL | fn example<Q: T1>(q: Q) {
| ++++
error: aborting due to 13 previous errors
error[E0277]: the trait bound `Q: T3` is not satisfied
--> $DIR/blame-trait-error-spans-on-exprs.rs:133:44
|
LL | want(&Burrito { spicy: false, filling: q });
| ---- ^ the trait `T3` is not implemented for `Q`
| |
| required by a bound introduced by this call
|
note: required for `Burrito<Q>` to implement `T2`
--> $DIR/blame-trait-error-spans-on-exprs.rs:22:13
|
LL | impl<A: T3> T2 for Burrito<A> {}
| -- ^^ ^^^^^^^^^^
| |
| unsatisfied trait bound introduced here
note: required for `&Burrito<Q>` to implement `T1`
--> $DIR/blame-trait-error-spans-on-exprs.rs:74:17
|
LL | impl<'a, T: T2> T1 for &'a T {}
| -- ^^ ^^^^^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `want`
--> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
|
LL | fn want<V: T1>(_x: V) {}
| ^^ required by this bound in `want`
help: consider restricting type parameter `Q`
|
LL | fn example<Q: T3>(q: Q) {
| ++++
error: aborting due to 14 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied
--> $DIR/issue-39029.rs:16:37
--> $DIR/issue-39029.rs:16:38
|
LL | let _errors = TcpListener::bind(&bad);
| ----------------- ^^^^ the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`
| ----------------- ^^^ the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`
| |
| required by a bound introduced by this call
|