Change:
can easily be converted to , but we give a somewhat opaque E0308 when with the following situation: This results in: Which is not totally clear to people who do not understand the trait and/or do not know that it is implemented for these types. We should suggest that the user use to convert between these types. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
claim
only works for and not for There are a couple of options I thought about, if there is a better one i'd be happy to use it: tell the user to pass a instead of a and use try to find where the parameter comes from and tell the user to remove the & sign and use if this is the last instance where the was used just handle the cases in which a is passed try to find a Copy or Clone impl on the struct and suggest to use it and use (this one seems like the most unsafe for arbitrary types, but in this particular case it would work) sorry for the inconvenience, I am new to rustc and I am currently trying to get started with this issue.
another option that would remain more local than finding where the was constructed is to try and suggest for that case in particular. Having said that, finding where the was constructed would be great because it's a type that is almost always wrong to use, unless it comes from a place where you end up with that because of type params (like a hashmap or another container), so it'd be good to lead people towards better code. What you can do is indeed split your work and focus on making the case work on its own PR, and then follow up with an attempt to handle .

Discussion:
use rustc_middle::ty::{self, Binder, Ty}; use rustc_span::symbol::{kw, sym}; <ins> use rustc_middle::ty::subst::GenericArgKind; </ins> use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let is_struct_pat_shorthand_field = 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); <del> if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods) .filter_map(|(receiver, method)| { let method_call = format!(".{}()", method.ident); if receiver.ends_with(&method_call) { None // do not suggest code that is already there (#53348) } else { 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), )] </del> <ins> if !methods.is_empty() { if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods) .filter_map(|(receiver, method)| { let method_call = format!(".{}()", method.ident); if receiver.ends_with(&method_call) { None // do not suggest code that is already there (#53348) </ins> } else { <del> if expr.precedence().order() < ExprPrecedence::MethodCall.order() { vec![ (expr.span.shrink_to_lo(), "(".to_string()), (expr.span.shrink_to_hi(), format!("){}", method_call)), ] </del> <ins> 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), )] </ins> } else { <del> vec![(expr.span.shrink_to_hi(), method_call)] </del> <ins> 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)), ); </ins> } <del> }; if is_struct_pat_shorthand_field { sugg.insert( 0, (expr.span.shrink_to_lo(), format!("{}: ", receiver)), </del> <ins> Some(sugg) } }) .peekable(); 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, </ins> ); } <del> Some(sugg) </del> } <del> }) .peekable(); if suggestions.peek().is_some() { err.multipart_suggestions( "try using a conversion method", suggestions, Applicability::MaybeIncorrect, ); </del> <ins> } </ins> } } }

<ins> 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] } </ins>

<ins> 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`. </ins>