Skip to content

Commit e7bf524

Browse files
authored
Rollup merge of rust-lang#37658 - GuillaumeGomez:ref_suggestion, r=nikomatsakis,eddyb
Ref suggestion
2 parents 1785bca + 7ce1eb7 commit e7bf524

File tree

8 files changed

+94
-27
lines changed

8 files changed

+94
-27
lines changed

src/librustc_typeck/check/coercion.rs

+11
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ use errors::DiagnosticBuilder;
7878
use syntax::abi;
7979
use syntax::feature_gate;
8080
use syntax::ptr::P;
81+
use syntax_pos;
8182

8283
use std::collections::VecDeque;
8384
use std::ops::Deref;
@@ -722,6 +723,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
722723
Ok(target)
723724
}
724725

726+
/// Same as `try_coerce()`, but without side-effects.
727+
pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
728+
let source = self.resolve_type_vars_with_obligations(expr_ty);
729+
debug!("coercion::can({:?} -> {:?})", source, target);
730+
731+
let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable);
732+
let coerce = Coerce::new(self, cause);
733+
self.probe(|_| coerce.coerce::<hir::Expr>(&[], source, target)).is_ok()
734+
}
735+
725736
/// Given some expressions, their known unified type and another expression,
726737
/// tries to unify the types, potentially inserting coercions on any of the
727738
/// provided expressions and returns their LUB (aka "common supertype").

src/librustc_typeck/check/demand.rs

+75-14
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,14 @@
1010

1111

1212
use check::FnCtxt;
13-
use rustc::ty::Ty;
14-
use rustc::infer::{InferOk};
13+
use rustc::infer::InferOk;
1514
use rustc::traits::ObligationCause;
1615

1716
use syntax::ast;
1817
use syntax_pos::{self, Span};
1918
use rustc::hir;
2019
use rustc::hir::def::Def;
21-
use rustc::ty::{self, AssociatedItem};
20+
use rustc::ty::{self, Ty, AssociatedItem};
2221
use errors::DiagnosticBuilder;
2322

2423
use super::method::probe;
@@ -80,18 +79,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
8079
if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
8180
let cause = self.misc(expr.span);
8281
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
83-
let mode = probe::Mode::MethodCall;
84-
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
85-
mode,
86-
expected,
87-
checked_ty,
88-
ast::DUMMY_NODE_ID);
8982
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
90-
if suggestions.len() > 0 {
91-
err.help(&format!("here are some functions which \
92-
might fulfill your needs:\n{}",
93-
self.get_best_match(&suggestions).join("\n")));
94-
};
83+
if let Some(suggestion) = self.check_ref(expr,
84+
checked_ty,
85+
expected) {
86+
err.help(&suggestion);
87+
} else {
88+
let mode = probe::Mode::MethodCall;
89+
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
90+
mode,
91+
expected,
92+
checked_ty,
93+
ast::DUMMY_NODE_ID);
94+
if suggestions.len() > 0 {
95+
err.help(&format!("here are some functions which \
96+
might fulfill your needs:\n{}",
97+
self.get_best_match(&suggestions).join("\n")));
98+
}
99+
}
95100
err.emit();
96101
}
97102
}
@@ -140,4 +145,60 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
140145
_ => false,
141146
}
142147
}
148+
149+
/// This function is used to determine potential "simple" improvements or users' errors and
150+
/// provide them useful help. For example:
151+
///
152+
/// ```
153+
/// fn some_fn(s: &str) {}
154+
///
155+
/// let x = "hey!".to_owned();
156+
/// some_fn(x); // error
157+
/// ```
158+
///
159+
/// No need to find every potential function which could make a coercion to transform a
160+
/// `String` into a `&str` since a `&` would do the trick!
161+
///
162+
/// In addition of this check, it also checks between references mutability state. If the
163+
/// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
164+
/// `&mut`!".
165+
fn check_ref(&self,
166+
expr: &hir::Expr,
167+
checked_ty: Ty<'tcx>,
168+
expected: Ty<'tcx>)
169+
-> Option<String> {
170+
match (&expected.sty, &checked_ty.sty) {
171+
(&ty::TyRef(_, _), &ty::TyRef(_, _)) => None,
172+
(&ty::TyRef(_, mutability), _) => {
173+
// Check if it can work when put into a ref. For example:
174+
//
175+
// ```
176+
// fn bar(x: &mut i32) {}
177+
//
178+
// let x = 0u32;
179+
// bar(&x); // error, expected &mut
180+
// ```
181+
let ref_ty = match mutability.mutbl {
182+
hir::Mutability::MutMutable => self.tcx.mk_mut_ref(
183+
self.tcx.mk_region(ty::ReStatic),
184+
checked_ty),
185+
hir::Mutability::MutImmutable => self.tcx.mk_imm_ref(
186+
self.tcx.mk_region(ty::ReStatic),
187+
checked_ty),
188+
};
189+
if self.can_coerce(ref_ty, expected) {
190+
if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
191+
return Some(format!("try with `{}{}`",
192+
match mutability.mutbl {
193+
hir::Mutability::MutMutable => "&mut ",
194+
hir::Mutability::MutImmutable => "&",
195+
},
196+
&src));
197+
}
198+
}
199+
None
200+
}
201+
_ => None,
202+
}
203+
}
143204
}

src/test/compile-fail/coercion-slice.rs

-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,5 @@ fn main() {
1414
let _: &[i32] = [0];
1515
//~^ ERROR mismatched types
1616
//~| expected type `&[i32]`
17-
//~| found type `[{integer}; 1]`
1817
//~| expected &[i32], found array of 1 elements
1918
}

src/test/compile-fail/cross-borrow-trait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ impl Trait for Foo {}
1717

1818
pub fn main() {
1919
let x: Box<Trait> = Box::new(Foo);
20-
let _y: &Trait = x; //~ ERROR mismatched types
20+
let _y: &Trait = x; //~ ERROR E0308
2121
//~| expected type `&Trait`
2222
//~| found type `std::boxed::Box<Trait>`
2323
}

src/test/compile-fail/issue-11374.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ pub fn for_stdin<'a>() -> Container<'a> {
3333
fn main() {
3434
let mut c = for_stdin();
3535
let mut v = Vec::new();
36-
c.read_to(v); //~ ERROR mismatched types
36+
c.read_to(v); //~ ERROR E0308
3737
}

src/test/compile-fail/issue-13058.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@ fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool
3535
fn main() {
3636
check((3, 5));
3737
//~^ ERROR mismatched types
38+
//~| HELP try with `&(3, 5)`
3839
}

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

-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ fn main() {
3232
//~| NOTE types differ in mutability
3333
//~| NOTE expected type `&mut std::string::String`
3434
//~| NOTE found type `&std::string::String`
35-
//~| HELP try with `&mut y`
3635
test2(&y);
3736
//~^ ERROR E0308
3837
//~| NOTE types differ in mutability

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

+5-9
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@ error[E0308]: mismatched types
1818
|
1919
= note: expected type `&str`
2020
found type `std::string::String`
21-
= help: here are some functions which might fulfill your needs:
22-
- .as_str()
23-
- .trim()
24-
- .trim_left()
25-
- .trim_right()
21+
= help: try with `&String::new()`
2622

2723
error[E0308]: mismatched types
2824
--> $DIR/coerce-suggestions.rs:30:10
@@ -34,18 +30,18 @@ error[E0308]: mismatched types
3430
found type `&std::string::String`
3531

3632
error[E0308]: mismatched types
37-
--> $DIR/coerce-suggestions.rs:36:11
33+
--> $DIR/coerce-suggestions.rs:35:11
3834
|
39-
36 | test2(&y);
35+
35 | test2(&y);
4036
| ^^ types differ in mutability
4137
|
4238
= note: expected type `&mut i32`
4339
found type `&std::string::String`
4440

4541
error[E0308]: mismatched types
46-
--> $DIR/coerce-suggestions.rs:42:9
42+
--> $DIR/coerce-suggestions.rs:41:9
4743
|
48-
42 | f = box f;
44+
41 | f = box f;
4945
| ^^^^^ cyclic type of infinite size
5046
|
5147
= note: expected type `_`

0 commit comments

Comments
 (0)