From fd95ba357465e39386924e40e05efef715a4ad46 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 21 Apr 2019 20:00:32 +0100 Subject: [PATCH] Suggest dereferencing when `Deref` is implemented. This commit suggests dereferencing a type when it implements `Deref` with the correct `Output` associated type. --- src/librustc_typeck/check/demand.rs | 34 +++++++++++++++++-- .../ui/infinite/infinite-autoderef.stderr | 2 +- src/test/ui/occurs-check-2.stderr | 2 +- src/test/ui/occurs-check.stderr | 2 +- src/test/ui/span/coerce-suggestions.stderr | 2 +- src/test/ui/suggestions/issue-59819.fixed | 22 ++++++++++++ src/test/ui/suggestions/issue-59819.rs | 2 ++ src/test/ui/suggestions/issue-59819.stderr | 9 +++-- src/test/ui/terr-sorts.stderr | 5 ++- 9 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/suggestions/issue-59819.fixed diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 8c1f4aabb1b..648a48d8907 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -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: `::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 { + // `::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 } diff --git a/src/test/ui/infinite/infinite-autoderef.stderr b/src/test/ui/infinite/infinite-autoderef.stderr index a5cc66f4473..04c84bae2dc 100644 --- a/src/test/ui/infinite/infinite-autoderef.stderr +++ b/src/test/ui/infinite/infinite-autoderef.stderr @@ -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 diff --git a/src/test/ui/occurs-check-2.stderr b/src/test/ui/occurs-check-2.stderr index 74e29a5aea7..7b475c3cb22 100644 --- a/src/test/ui/occurs-check-2.stderr +++ b/src/test/ui/occurs-check-2.stderr @@ -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 diff --git a/src/test/ui/occurs-check.stderr b/src/test/ui/occurs-check.stderr index 61ce61b1cbe..fe4248a95c9 100644 --- a/src/test/ui/occurs-check.stderr +++ b/src/test/ui/occurs-check.stderr @@ -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 diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index 996d80a07e0..1d8400b20ac 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -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 diff --git a/src/test/ui/suggestions/issue-59819.fixed b/src/test/ui/suggestions/issue-59819.fixed new file mode 100644 index 00000000000..0bf5d32daf9 --- /dev/null +++ b/src/test/ui/suggestions/issue-59819.fixed @@ -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 +} diff --git a/src/test/ui/suggestions/issue-59819.rs b/src/test/ui/suggestions/issue-59819.rs index b3c4df40161..e7e9c7ae259 100644 --- a/src/test/ui/suggestions/issue-59819.rs +++ b/src/test/ui/suggestions/issue-59819.rs @@ -1,3 +1,5 @@ +// run-rustfix + #![allow(warnings)] // Test that suggestion to add `*` characters applies to implementations of `Deref` as well as diff --git a/src/test/ui/suggestions/issue-59819.stderr b/src/test/ui/suggestions/issue-59819.stderr index 9c4d6134663..175c39cfc4f 100644 --- a/src/test/ui/suggestions/issue-59819.stderr +++ b/src/test/ui/suggestions/issue-59819.stderr @@ -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; | ^ diff --git a/src/test/ui/terr-sorts.stderr b/src/test/ui/terr-sorts.stderr index 05b9fb43fe1..edc042c85ee 100644 --- a/src/test/ui/terr-sorts.stderr +++ b/src/test/ui/terr-sorts.stderr @@ -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`