Skip to content

Commit

Permalink
Rollup merge of rust-lang#71829 - kper:issue71136, r=matthewjasper
Browse files Browse the repository at this point in the history
Fix suggestion to borrow in struct

The corresponding issue is rust-lang#71136.
The compiler suggests that borrowing `the_foos` might solve the problem. This is obviously incorrect.
```
struct Foo(u8);

#[derive(Clone)]
struct FooHolster {
    the_foos: Vec<Foo>,
}
```

I propose as fix to check if there is any colon in the span. However, there might a case where `my_method(B { a: 1, b : foo })` would be appropriate to show a suggestion for `&B ...`.  To fix that too, we can simply check if there is a bracket in the span. This is only possible because both spans are different.
Issue's span: `the_foos: Vec<Foo>`
other's span: `B { a : 1, b : foo }`
  • Loading branch information
RalfJung authored May 22, 2020
2 parents a9ca1ec + e776121 commit 9c34481
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 6 deletions.
25 changes: 19 additions & 6 deletions src/librustc_trait_selection/traits/error_reporting/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,13 +631,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
param_env,
new_trait_ref.without_const().to_predicate(self.tcx),
);

if self.predicate_must_hold_modulo_regions(&new_obligation) {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
// We have a very specific type of error, where just borrowing this argument
// might solve the problem. In cases like this, the important part is the
// original type obligation, not the last one that failed, which is arbitrary.
// Because of this, we modify the error to refer to the original obligation and
// return early in the caller.

let msg = format!(
"the trait bound `{}: {}` is not satisfied",
found,
Expand All @@ -660,12 +662,23 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
obligation.parent_trait_ref.skip_binder().print_only_trait_path(),
),
);
err.span_suggestion(
span,
"consider borrowing here",
format!("&{}", snippet),
Applicability::MaybeIncorrect,
);

// This if is to prevent a special edge-case
if !span.from_expansion() {
// We don't want a borrowing suggestion on the fields in structs,
// ```
// struct Foo {
// the_foos: Vec<Foo>
// }
// ```

err.span_suggestion(
span,
"consider borrowing here",
format!("&{}", snippet),
Applicability::MaybeIncorrect,
);
}
return true;
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/traits/traits-issue-71136.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
struct Foo(u8);

#[derive(Clone)]
struct FooHolster {
the_foos: Vec<Foo>, //~ERROR Clone
}

fn main() {}
13 changes: 13 additions & 0 deletions src/test/ui/traits/traits-issue-71136.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error[E0277]: the trait bound `Foo: std::clone::Clone` is not satisfied
--> $DIR/traits-issue-71136.rs:5:5
|
LL | the_foos: Vec<Foo>,
| ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `std::clone::Clone`
|
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<Foo>`
= note: required by `std::clone::Clone::clone`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.

0 comments on commit 9c34481

Please sign in to comment.