Skip to content

Commit e0179df

Browse files
Rollup merge of #51822 - estebank:suggest-more, r=nikomatsakis
Provide existing ref suggestions for more E0308 errors
2 parents 85804f6 + 54a04b3 commit e0179df

File tree

4 files changed

+59
-38
lines changed

4 files changed

+59
-38
lines changed

Diff for: src/librustc_typeck/check/coercion.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1203,9 +1203,14 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
12031203
"supposed to be part of a block tail expression, but the \
12041204
expression is empty");
12051205
});
1206-
fcx.suggest_mismatched_types_on_tail(&mut db, expr,
1207-
expected, found,
1208-
cause.span, blk_id);
1206+
fcx.suggest_mismatched_types_on_tail(
1207+
&mut db,
1208+
expr,
1209+
expected,
1210+
found,
1211+
cause.span,
1212+
blk_id,
1213+
);
12091214
}
12101215
_ => {
12111216
db = fcx.report_mismatched_types(cause, expected, found, err);

Diff for: src/librustc_typeck/check/demand.rs

+23-33
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::iter;
12-
1311
use check::FnCtxt;
1412
use rustc::infer::InferOk;
1513
use rustc::traits::ObligationCause;
@@ -140,25 +138,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
140138
}
141139
}
142140

143-
if let Some((sp, msg, suggestion)) = self.check_ref(expr, checked_ty, expected) {
144-
err.span_suggestion(sp, msg, suggestion);
145-
} else if !self.check_for_cast(&mut err, expr, expr_ty, expected) {
146-
let methods = self.get_conversion_methods(expr.span, expected, checked_ty);
147-
if let Ok(expr_text) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
148-
let suggestions = iter::repeat(expr_text).zip(methods.iter())
149-
.map(|(receiver, method)| format!("{}.{}()", receiver, method.ident))
150-
.collect::<Vec<_>>();
151-
if !suggestions.is_empty() {
152-
err.span_suggestions(expr.span,
153-
"try using a conversion method",
154-
suggestions);
155-
}
156-
}
157-
}
141+
self.suggest_ref_or_into(&mut err, expr, expected, expr_ty);
142+
158143
(expected, Some(err))
159144
}
160145

161-
fn get_conversion_methods(&self, span: Span, expected: Ty<'tcx>, checked_ty: Ty<'tcx>)
146+
pub fn get_conversion_methods(&self, span: Span, expected: Ty<'tcx>, checked_ty: Ty<'tcx>)
162147
-> Vec<AssociatedItem> {
163148
let mut methods = self.probe_for_return_type(span,
164149
probe::Mode::MethodCall,
@@ -261,19 +246,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
261246
/// In addition of this check, it also checks between references mutability state. If the
262247
/// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
263248
/// `&mut`!".
264-
fn check_ref(&self,
249+
pub fn check_ref(&self,
265250
expr: &hir::Expr,
266251
checked_ty: Ty<'tcx>,
267252
expected: Ty<'tcx>)
268253
-> Option<(Span, &'static str, String)> {
269-
let sp = expr.span;
254+
let cm = self.sess().codemap();
255+
// Use the callsite's span if this is a macro call. #41858
256+
let sp = cm.call_span_if_macro(expr.span);
257+
if !cm.span_to_filename(sp).is_real() {
258+
return None;
259+
}
260+
270261
match (&expected.sty, &checked_ty.sty) {
271262
(&ty::TyRef(_, exp, _), &ty::TyRef(_, check, _)) => match (&exp.sty, &check.sty) {
272263
(&ty::TyStr, &ty::TyArray(arr, _)) |
273264
(&ty::TyStr, &ty::TySlice(arr)) if arr == self.tcx.types.u8 => {
274265
if let hir::ExprLit(_) = expr.node {
275-
let sp = self.sess().codemap().call_span_if_macro(expr.span);
276-
if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(sp) {
266+
if let Ok(src) = cm.span_to_snippet(sp) {
277267
return Some((sp,
278268
"consider removing the leading `b`",
279269
src[1..].to_string()));
@@ -283,8 +273,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
283273
(&ty::TyArray(arr, _), &ty::TyStr) |
284274
(&ty::TySlice(arr), &ty::TyStr) if arr == self.tcx.types.u8 => {
285275
if let hir::ExprLit(_) = expr.node {
286-
let sp = self.sess().codemap().call_span_if_macro(expr.span);
287-
if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(sp) {
276+
if let Ok(src) = cm.span_to_snippet(sp) {
288277
return Some((sp,
289278
"consider adding a leading `b`",
290279
format!("b{}", src)));
@@ -311,9 +300,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
311300
checked_ty),
312301
};
313302
if self.can_coerce(ref_ty, expected) {
314-
// Use the callsite's span if this is a macro call. #41858
315-
let sp = self.sess().codemap().call_span_if_macro(expr.span);
316-
if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(sp) {
303+
if let Ok(src) = cm.span_to_snippet(sp) {
317304
let sugg_expr = match expr.node { // parenthesize if needed (Issue #46756)
318305
hir::ExprCast(_, _) | hir::ExprBinary(_, _, _) => format!("({})", src),
319306
_ => src,
@@ -342,11 +329,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
342329
// a macro; if so, it's hard to extract the text and make a good
343330
// suggestion, so don't bother.)
344331
if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() &&
345-
expr.span.ctxt().outer().expn_info().is_none() {
332+
sp.ctxt().outer().expn_info().is_none() {
346333
match expr.node {
347334
// Maybe remove `&`?
348335
hir::ExprAddrOf(_, ref expr) => {
349-
if let Ok(code) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
336+
if !cm.span_to_filename(expr.span).is_real() {
337+
return None;
338+
}
339+
if let Ok(code) = cm.span_to_snippet(expr.span) {
350340
return Some((sp, "consider removing the borrow", code));
351341
}
352342
}
@@ -355,9 +345,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
355345
_ => {
356346
if !self.infcx.type_moves_by_default(self.param_env,
357347
checked,
358-
expr.span) {
359-
let sp = self.sess().codemap().call_span_if_macro(expr.span);
360-
if let Ok(code) = self.tcx.sess.codemap().span_to_snippet(sp) {
348+
sp) {
349+
let sp = cm.call_span_if_macro(sp);
350+
if let Ok(code) = cm.span_to_snippet(sp) {
361351
return Some((sp,
362352
"consider dereferencing the borrow",
363353
format!("*{}", code)));
@@ -372,7 +362,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
372362
None
373363
}
374364

375-
fn check_for_cast(&self,
365+
pub fn check_for_cast(&self,
376366
err: &mut DiagnosticBuilder<'tcx>,
377367
expr: &hir::Expr,
378368
checked_ty: Ty<'tcx>,

Diff for: src/librustc_typeck/check/mod.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ use rustc_data_structures::sync::Lrc;
116116
use std::collections::hash_map::Entry;
117117
use std::cmp;
118118
use std::fmt::Display;
119+
use std::iter;
119120
use std::mem::replace;
120121
use std::ops::{self, Deref};
121122
use rustc_target::spec::abi::Abi;
@@ -4539,10 +4540,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
45394540
cause_span: Span,
45404541
blk_id: ast::NodeId) {
45414542
self.suggest_missing_semicolon(err, expression, expected, cause_span);
4542-
45434543
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
45444544
self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
45454545
}
4546+
self.suggest_ref_or_into(err, expression, expected, found);
4547+
}
4548+
4549+
pub fn suggest_ref_or_into(
4550+
&self,
4551+
err: &mut DiagnosticBuilder<'tcx>,
4552+
expr: &hir::Expr,
4553+
expected: Ty<'tcx>,
4554+
found: Ty<'tcx>,
4555+
) {
4556+
if let Some((sp, msg, suggestion)) = self.check_ref(expr, found, expected) {
4557+
err.span_suggestion(sp, msg, suggestion);
4558+
} else if !self.check_for_cast(err, expr, found, expected) {
4559+
let methods = self.get_conversion_methods(expr.span, expected, found);
4560+
if let Ok(expr_text) = self.sess().codemap().span_to_snippet(expr.span) {
4561+
let suggestions = iter::repeat(expr_text).zip(methods.iter())
4562+
.map(|(receiver, method)| format!("{}.{}()", receiver, method.ident))
4563+
.collect::<Vec<_>>();
4564+
if !suggestions.is_empty() {
4565+
err.span_suggestions(expr.span, "try using a conversion method", suggestions);
4566+
}
4567+
}
4568+
}
45464569
}
45474570

45484571
/// A common error is to forget to add a semicolon at the end of a block:

Diff for: src/test/ui/suggestions/str-array-assignment.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ LL | fn main() {
1414
| - expected `()` because of default return type
1515
...
1616
LL | let u: &str = if true { s[..2] } else { s };
17-
| ^^^^^^ expected &str, found str
17+
| ^^^^^^
18+
| |
19+
| expected &str, found str
20+
| help: consider borrowing here: `&s[..2]`
1821
|
1922
= note: expected type `&str`
2023
found type `str`

0 commit comments

Comments
 (0)