Auto merge of #90645 - terrarier2111:master, r=estebank
Implement diagnostic for String conversion This is my first real contribution to rustc, any feedback is highly appreciated. This should fix https://github.com/rust-lang/rust/issues/89856 Thanks to `@estebank` for guiding me.
This commit is contained in:
commit
d5a0c7cb03
3 changed files with 85 additions and 36 deletions
|
@ -14,6 +14,7 @@ use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_middle::ty::{self, Binder, Ty};
|
use rustc_middle::ty::{self, Binder, Ty};
|
||||||
use rustc_span::symbol::{kw, sym};
|
use rustc_span::symbol::{kw, sym};
|
||||||
|
|
||||||
|
use rustc_middle::ty::subst::GenericArgKind;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
@ -232,48 +233,72 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let is_struct_pat_shorthand_field =
|
let is_struct_pat_shorthand_field =
|
||||||
self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
|
self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
|
||||||
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
|
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
|
||||||
if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
|
if !methods.is_empty() {
|
||||||
let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods)
|
if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
|
||||||
.filter_map(|(receiver, method)| {
|
let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods)
|
||||||
let method_call = format!(".{}()", method.ident);
|
.filter_map(|(receiver, method)| {
|
||||||
if receiver.ends_with(&method_call) {
|
let method_call = format!(".{}()", method.ident);
|
||||||
None // do not suggest code that is already there (#53348)
|
if receiver.ends_with(&method_call) {
|
||||||
} else {
|
None // do not suggest code that is already there (#53348)
|
||||||
let method_call_list = [".to_vec()", ".to_string()"];
|
|
||||||
let mut sugg = if receiver.ends_with(".clone()")
|
|
||||||
&& method_call_list.contains(&method_call.as_str())
|
|
||||||
{
|
|
||||||
let max_len = receiver.rfind('.').unwrap();
|
|
||||||
vec![(
|
|
||||||
expr.span,
|
|
||||||
format!("{}{}", &receiver[..max_len], method_call),
|
|
||||||
)]
|
|
||||||
} else {
|
} else {
|
||||||
if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
|
let method_call_list = [".to_vec()", ".to_string()"];
|
||||||
vec![
|
let mut sugg = if receiver.ends_with(".clone()")
|
||||||
(expr.span.shrink_to_lo(), "(".to_string()),
|
&& method_call_list.contains(&method_call.as_str())
|
||||||
(expr.span.shrink_to_hi(), format!("){}", method_call)),
|
{
|
||||||
]
|
let max_len = receiver.rfind('.').unwrap();
|
||||||
|
vec![(
|
||||||
|
expr.span,
|
||||||
|
format!("{}{}", &receiver[..max_len], method_call),
|
||||||
|
)]
|
||||||
} else {
|
} else {
|
||||||
vec![(expr.span.shrink_to_hi(), method_call)]
|
if expr.precedence().order()
|
||||||
|
< ExprPrecedence::MethodCall.order()
|
||||||
|
{
|
||||||
|
vec![
|
||||||
|
(expr.span.shrink_to_lo(), "(".to_string()),
|
||||||
|
(expr.span.shrink_to_hi(), format!("){}", method_call)),
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
vec![(expr.span.shrink_to_hi(), method_call)]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if is_struct_pat_shorthand_field {
|
||||||
|
sugg.insert(
|
||||||
|
0,
|
||||||
|
(expr.span.shrink_to_lo(), format!("{}: ", receiver)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
Some(sugg)
|
||||||
if is_struct_pat_shorthand_field {
|
}
|
||||||
sugg.insert(
|
})
|
||||||
0,
|
.peekable();
|
||||||
(expr.span.shrink_to_lo(), format!("{}: ", receiver)),
|
if suggestions.peek().is_some() {
|
||||||
|
err.multipart_suggestions(
|
||||||
|
"try using a conversion method",
|
||||||
|
suggestions,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if found.to_string().starts_with("Option<")
|
||||||
|
&& expected.to_string() == "Option<&str>"
|
||||||
|
{
|
||||||
|
if let ty::Adt(_def, subst) = found.kind() {
|
||||||
|
if subst.len() != 0 {
|
||||||
|
if let GenericArgKind::Type(ty) = subst[0].unpack() {
|
||||||
|
let peeled = ty.peel_refs().to_string();
|
||||||
|
if peeled == "String" {
|
||||||
|
let ref_cnt = ty.to_string().len() - peeled.len();
|
||||||
|
let result = format!(".map(|x| &*{}x)", "*".repeat(ref_cnt));
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
expr.span.shrink_to_hi(),
|
||||||
|
"try converting the passed type into a `&str`",
|
||||||
|
result,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Some(sugg)
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.peekable();
|
|
||||||
if suggestions.peek().is_some() {
|
|
||||||
err.multipart_suggestions(
|
|
||||||
"try using a conversion method",
|
|
||||||
suggestions,
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
8
src/test/ui/typeck/issue-89856.rs
Normal file
8
src/test/ui/typeck/issue-89856.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
fn take_str_maybe(x: Option<&str>) -> Option<&str> { None }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let string = String::from("Hello, world");
|
||||||
|
let option = Some(&string);
|
||||||
|
take_str_maybe(option);
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
}
|
16
src/test/ui/typeck/issue-89856.stderr
Normal file
16
src/test/ui/typeck/issue-89856.stderr
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-89856.rs:6:20
|
||||||
|
|
|
||||||
|
LL | take_str_maybe(option);
|
||||||
|
| ^^^^^^ expected `str`, found struct `String`
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<&str>`
|
||||||
|
found enum `Option<&String>`
|
||||||
|
help: try converting the passed type into a `&str`
|
||||||
|
|
|
||||||
|
LL | take_str_maybe(option.map(|x| &**x));
|
||||||
|
| ++++++++++++++
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Reference in a new issue