Skip to content

Commit fd95ba3

Browse files
committed
Suggest dereferencing when Deref is implemented.
This commit suggests dereferencing a type when it implements `Deref` with the correct `Output` associated type.
1 parent c9a2616 commit fd95ba3

File tree

9 files changed

+70
-10
lines changed

9 files changed

+70
-10
lines changed

src/librustc_typeck/check/demand.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::check::FnCtxt;
22
use rustc::infer::InferOk;
3-
use rustc::traits::{ObligationCause, ObligationCauseCode};
3+
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
44

55
use syntax::util::parser::PREC_POSTFIX;
66
use syntax_pos::Span;
@@ -463,7 +463,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
463463
}
464464
}
465465
}
466-
_ => {}
466+
_ => {
467+
// If neither type is a reference, then check for `Deref` implementations by
468+
// constructing a predicate to prove: `<T as Deref>::Output == U`
469+
let deref_trait = self.tcx.lang_items().deref_trait().unwrap();
470+
let item_def_id = self.tcx.associated_items(deref_trait).next().unwrap().def_id;
471+
let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate {
472+
// `<T as Deref>::Output`
473+
projection_ty: ty::ProjectionTy {
474+
// `T`
475+
substs: self.tcx.mk_substs_trait(
476+
checked_ty,
477+
self.fresh_substs_for_item(sp, item_def_id),
478+
),
479+
// `Deref::Output`
480+
item_def_id,
481+
},
482+
// `U`
483+
ty: expected,
484+
}));
485+
let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
486+
if self.infcx.predicate_may_hold(&obligation) {
487+
if let (Ok(code), true) = (cm.span_to_snippet(sp), sp == expr.span) {
488+
let msg = if is_struct_pat_shorthand_field {
489+
format!("{}: *{}", code, code)
490+
} else {
491+
format!("*{}", code)
492+
};
493+
return Some((sp, "consider dereferencing the type", msg));
494+
}
495+
}
496+
}
467497
}
468498
None
469499
}

src/test/ui/infinite/infinite-autoderef.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | x = box x;
55
| ^^^^^
66
| |
77
| cyclic type of infinite size
8-
| help: try using a conversion method: `box x.to_string()`
8+
| help: consider dereferencing the type: `*box x`
99

1010
error[E0055]: reached the recursion limit while auto-dereferencing `Foo`
1111
--> $DIR/infinite-autoderef.rs:25:5

src/test/ui/occurs-check-2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | f = box g;
55
| ^^^^^
66
| |
77
| cyclic type of infinite size
8-
| help: try using a conversion method: `box g.to_string()`
8+
| help: consider dereferencing the type: `*box g`
99

1010
error: aborting due to previous error
1111

src/test/ui/occurs-check.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | f = box f;
55
| ^^^^^
66
| |
77
| cyclic type of infinite size
8-
| help: try using a conversion method: `box f.to_string()`
8+
| help: consider dereferencing the type: `*box f`
99

1010
error: aborting due to previous error
1111

src/test/ui/span/coerce-suggestions.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ LL | f = box f;
4444
| ^^^^^
4545
| |
4646
| cyclic type of infinite size
47-
| help: try using a conversion method: `box f.to_string()`
47+
| help: consider dereferencing the type: `*box f`
4848

4949
error[E0308]: mismatched types
5050
--> $DIR/coerce-suggestions.rs:21:9
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// run-rustfix
2+
3+
#![allow(warnings)]
4+
5+
// Test that suggestion to add `*` characters applies to implementations of `Deref` as well as
6+
// references.
7+
8+
struct Foo(i32);
9+
10+
impl std::ops::Deref for Foo {
11+
type Target = i32;
12+
fn deref(&self) -> &i32 {
13+
&self.0
14+
}
15+
}
16+
17+
fn main() {
18+
let x = Foo(42);
19+
let y: i32 = *x; //~ ERROR mismatched types
20+
let a = &42;
21+
let b: i32 = *a; //~ ERROR mismatched types
22+
}

src/test/ui/suggestions/issue-59819.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// run-rustfix
2+
13
#![allow(warnings)]
24

35
// Test that suggestion to add `*` characters applies to implementations of `Deref` as well as

src/test/ui/suggestions/issue-59819.stderr

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
error[E0308]: mismatched types
2-
--> $DIR/issue-59819.rs:17:18
2+
--> $DIR/issue-59819.rs:19:18
33
|
44
LL | let y: i32 = x;
5-
| ^ expected i32, found struct `Foo`
5+
| ^
6+
| |
7+
| expected i32, found struct `Foo`
8+
| help: consider dereferencing the type: `*x`
69
|
710
= note: expected type `i32`
811
found type `Foo`
912

1013
error[E0308]: mismatched types
11-
--> $DIR/issue-59819.rs:19:18
14+
--> $DIR/issue-59819.rs:21:18
1215
|
1316
LL | let b: i32 = a;
1417
| ^

src/test/ui/terr-sorts.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error[E0308]: mismatched types
22
--> $DIR/terr-sorts.rs:10:14
33
|
44
LL | want_foo(b);
5-
| ^ expected struct `Foo`, found struct `std::boxed::Box`
5+
| ^
6+
| |
7+
| expected struct `Foo`, found struct `std::boxed::Box`
8+
| help: consider dereferencing the type: `*b`
69
|
710
= note: expected type `Foo`
811
found type `std::boxed::Box<Foo>`

0 commit comments

Comments
 (0)