Suggest dereferencing when Deref is implemented.

This commit suggests dereferencing a type when it implements `Deref`
with the correct `Output` associated type.
This commit is contained in:
David Wood 2019-04-21 20:00:32 +01:00
parent c9a2616e44
commit fd95ba3574
No known key found for this signature in database
GPG Key ID: 01760B4F9F53F154
9 changed files with 70 additions and 10 deletions

View File

@ -1,6 +1,6 @@
use crate::check::FnCtxt;
use rustc::infer::InferOk;
use rustc::traits::{ObligationCause, ObligationCauseCode};
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
use syntax::util::parser::PREC_POSTFIX;
use syntax_pos::Span;
@ -463,7 +463,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
}
_ => {}
_ => {
// If neither type is a reference, then check for `Deref` implementations by
// constructing a predicate to prove: `<T as Deref>::Output == U`
let deref_trait = self.tcx.lang_items().deref_trait().unwrap();
let item_def_id = self.tcx.associated_items(deref_trait).next().unwrap().def_id;
let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate {
// `<T as Deref>::Output`
projection_ty: ty::ProjectionTy {
// `T`
substs: self.tcx.mk_substs_trait(
checked_ty,
self.fresh_substs_for_item(sp, item_def_id),
),
// `Deref::Output`
item_def_id,
},
// `U`
ty: expected,
}));
let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
if self.infcx.predicate_may_hold(&obligation) {
if let (Ok(code), true) = (cm.span_to_snippet(sp), sp == expr.span) {
let msg = if is_struct_pat_shorthand_field {
format!("{}: *{}", code, code)
} else {
format!("*{}", code)
};
return Some((sp, "consider dereferencing the type", msg));
}
}
}
}
None
}

View File

@ -5,7 +5,7 @@ LL | x = box x;
| ^^^^^
| |
| cyclic type of infinite size
| help: try using a conversion method: `box x.to_string()`
| help: consider dereferencing the type: `*box x`
error[E0055]: reached the recursion limit while auto-dereferencing `Foo`
--> $DIR/infinite-autoderef.rs:25:5

View File

@ -5,7 +5,7 @@ LL | f = box g;
| ^^^^^
| |
| cyclic type of infinite size
| help: try using a conversion method: `box g.to_string()`
| help: consider dereferencing the type: `*box g`
error: aborting due to previous error

View File

@ -5,7 +5,7 @@ LL | f = box f;
| ^^^^^
| |
| cyclic type of infinite size
| help: try using a conversion method: `box f.to_string()`
| help: consider dereferencing the type: `*box f`
error: aborting due to previous error

View File

@ -44,7 +44,7 @@ LL | f = box f;
| ^^^^^
| |
| cyclic type of infinite size
| help: try using a conversion method: `box f.to_string()`
| help: consider dereferencing the type: `*box f`
error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:21:9

View File

@ -0,0 +1,22 @@
// run-rustfix
#![allow(warnings)]
// Test that suggestion to add `*` characters applies to implementations of `Deref` as well as
// references.
struct Foo(i32);
impl std::ops::Deref for Foo {
type Target = i32;
fn deref(&self) -> &i32 {
&self.0
}
}
fn main() {
let x = Foo(42);
let y: i32 = *x; //~ ERROR mismatched types
let a = &42;
let b: i32 = *a; //~ ERROR mismatched types
}

View File

@ -1,3 +1,5 @@
// run-rustfix
#![allow(warnings)]
// Test that suggestion to add `*` characters applies to implementations of `Deref` as well as

View File

@ -1,14 +1,17 @@
error[E0308]: mismatched types
--> $DIR/issue-59819.rs:17:18
--> $DIR/issue-59819.rs:19:18
|
LL | let y: i32 = x;
| ^ expected i32, found struct `Foo`
| ^
| |
| expected i32, found struct `Foo`
| help: consider dereferencing the type: `*x`
|
= note: expected type `i32`
found type `Foo`
error[E0308]: mismatched types
--> $DIR/issue-59819.rs:19:18
--> $DIR/issue-59819.rs:21:18
|
LL | let b: i32 = a;
| ^

View File

@ -2,7 +2,10 @@ error[E0308]: mismatched types
--> $DIR/terr-sorts.rs:10:14
|
LL | want_foo(b);
| ^ expected struct `Foo`, found struct `std::boxed::Box`
| ^
| |
| expected struct `Foo`, found struct `std::boxed::Box`
| help: consider dereferencing the type: `*b`
|
= note: expected type `Foo`
found type `std::boxed::Box<Foo>`