Suggest .as_ref() when appropriate for Option and Result
This commit is contained in:
parent
fb86d604bf
commit
8da6727e96
4 changed files with 165 additions and 47 deletions
|
|
@ -956,6 +956,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
diag.span_label(span, message);
|
||||
}
|
||||
}
|
||||
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
|
||||
}
|
||||
|
||||
diag.note_expected_found(&"type", expected, found);
|
||||
|
|
@ -972,6 +973,79 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
self.note_error_origin(diag, &cause);
|
||||
}
|
||||
|
||||
/// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
|
||||
/// suggest it.
|
||||
fn suggest_as_ref_where_appropriate(
|
||||
&self,
|
||||
span: Span,
|
||||
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
|
||||
diag: &mut DiagnosticBuilder<'tcx>,
|
||||
) {
|
||||
match (&exp_found.expected.sty, &exp_found.found.sty) {
|
||||
(TyKind::Adt(exp_def, exp_substs), TyKind::Ref(_, found_ty, _)) => {
|
||||
if let TyKind::Adt(found_def, found_substs) = found_ty.sty {
|
||||
let path_str = format!("{:?}", exp_def);
|
||||
if exp_def == &found_def {
|
||||
let opt_msg = "you can convert from `&Option<T>` to `Option<&T>` using \
|
||||
`.as_ref()`";
|
||||
let result_msg = "you can convert from `&Result<T, E>` to \
|
||||
`Result<&T, &E>` using `.as_ref()`";
|
||||
let have_as_ref = &[
|
||||
("std::option::Option", opt_msg),
|
||||
("core::option::Option", opt_msg),
|
||||
("std::result::Result", result_msg),
|
||||
("core::result::Result", result_msg),
|
||||
];
|
||||
if let Some(msg) = have_as_ref.iter()
|
||||
.filter_map(|(path, msg)| if &path_str == path {
|
||||
Some(msg)
|
||||
} else {
|
||||
None
|
||||
}).next()
|
||||
{
|
||||
let mut show_suggestion = true;
|
||||
for (exp_ty, found_ty) in exp_substs.types().zip(found_substs.types()) {
|
||||
if let TyKind::Ref(_, exp_ty, _) = exp_ty.sty {
|
||||
match (&exp_ty.sty, &found_ty.sty) {
|
||||
(TyKind::Adt(exp_did, _), TyKind::Adt(found_did, _))
|
||||
if exp_did == found_did => {}
|
||||
(TyKind::Bool, TyKind::Bool) |
|
||||
(TyKind::Char, TyKind::Char) |
|
||||
(TyKind::Str, TyKind::Str) |
|
||||
(_, TyKind::Param(_)) |
|
||||
(_, TyKind::Infer(_)) |
|
||||
(TyKind::Param(_), _) |
|
||||
(TyKind::Infer(_), _) => {}
|
||||
(TyKind::Int(x), TyKind::Int(y)) if x == y => {}
|
||||
(TyKind::Uint(x), TyKind::Uint(y)) if x == y => {}
|
||||
(TyKind::Int(x), TyKind::Int(y)) if x == y => {}
|
||||
(TyKind::Uint(x), TyKind::Uint(y)) if x == y => {}
|
||||
(TyKind::Float(x), TyKind::Float(y)) if x == y => {}
|
||||
_ => show_suggestion = false,
|
||||
}
|
||||
} else {
|
||||
show_suggestion = false;
|
||||
}
|
||||
}
|
||||
if let (Ok(snippet), true) = (
|
||||
self.tcx.sess.source_map().span_to_snippet(span),
|
||||
show_suggestion,
|
||||
) {
|
||||
diag.span_suggestion_with_applicability(
|
||||
span,
|
||||
msg,
|
||||
format!("{}.as_ref()", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report_and_explain_type_error(
|
||||
&self,
|
||||
trace: TypeTrace<'tcx>,
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:6:27
|
||||
|
|
||||
LL | opt.map(|arg| takes_ref(arg));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:8:37
|
||||
|
|
||||
LL | opt.and_then(|arg| Some(takes_ref(arg)));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:11:27
|
||||
|
|
||||
LL | opt.map(|arg| takes_ref(arg));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:13:35
|
||||
|
|
||||
LL | opt.and_then(|arg| Ok(takes_ref(arg)));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
@ -12,4 +12,14 @@ fn main() {
|
|||
//~^ ERROR mismatched types [E0308]
|
||||
opt.and_then(|arg| Ok(takes_ref(arg)));
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
let x: &Option<usize> = &Some(3);
|
||||
let y: Option<&usize> = x;
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
let x: &Result<usize, usize> = &Ok(3);
|
||||
let y: Result<&usize, &usize> = x;
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
// note: do not suggest because of `E: usize`
|
||||
let x: &Result<usize, usize> = &Ok(3);
|
||||
let y: Result<&usize, usize> = x;
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
}
|
||||
81
src/test/ui/suggestions/as-ref.stderr
Normal file
81
src/test/ui/suggestions/as-ref.stderr
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:6:27
|
||||
|
|
||||
LL | opt.map(|arg| takes_ref(arg));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:8:37
|
||||
|
|
||||
LL | opt.and_then(|arg| Some(takes_ref(arg)));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:11:27
|
||||
|
|
||||
LL | opt.map(|arg| takes_ref(arg));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:13:35
|
||||
|
|
||||
LL | opt.and_then(|arg| Ok(takes_ref(arg)));
|
||||
| - ^^^ expected &Foo, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:16:27
|
||||
|
|
||||
LL | let y: Option<&usize> = x;
|
||||
| ^
|
||||
| |
|
||||
| expected enum `std::option::Option`, found reference
|
||||
| help: you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`: `x.as_ref()`
|
||||
|
|
||||
= note: expected type `std::option::Option<&usize>`
|
||||
found type `&std::option::Option<usize>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:19:35
|
||||
|
|
||||
LL | let y: Result<&usize, &usize> = x;
|
||||
| ^ expected enum `std::result::Result`, found reference
|
||||
|
|
||||
= note: expected type `std::result::Result<&usize, &usize>`
|
||||
found type `&std::result::Result<usize, usize>`
|
||||
help: you can convert from `&Result<T, E>` to `Result<&T, &E>` using `.as_ref()`
|
||||
|
|
||||
LL | let y: Result<&usize, &usize> = x.as_ref();
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:23:34
|
||||
|
|
||||
LL | let y: Result<&usize, usize> = x;
|
||||
| ^ expected enum `std::result::Result`, found reference
|
||||
|
|
||||
= note: expected type `std::result::Result<&usize, usize>`
|
||||
found type `&std::result::Result<usize, usize>`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue