Skip to content

Commit

Permalink
More fix on mismatched type suggestion for shorthand fields
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyukang committed Nov 29, 2023
1 parent 9386e14 commit 3a4edf0
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 9 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ pub struct SuggestConvertViaMethod<'tcx> {
pub span: Span,
#[suggestion_part(code = "")]
pub borrow_removal_span: Option<Span>,
pub sugg: &'static str,
pub sugg: String,
pub expected: Ty<'tcx>,
pub found: Ty<'tcx>,
}
39 changes: 31 additions & 8 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,12 +442,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected,
)
});

let prefix_wrap = |sugg: &str| {
if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
format!(": {}{}", name, sugg)
} else {
sugg.to_string()
}
};

// FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`,
// but those checks need to be a bit more delicate and the benefit is diminishing.
if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref {
let sugg = prefix_wrap(".as_ref()");
err.subdiagnostic(errors::SuggestConvertViaMethod {
span: expr.span.shrink_to_hi(),
sugg: ".as_ref()",
sugg,
expected,
found,
borrow_removal_span,
Expand All @@ -458,9 +468,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& self.can_eq(self.param_env, deref_ty, peeled)
&& error_tys_equate_as_ref
{
let sugg = prefix_wrap(".as_deref()");
err.subdiagnostic(errors::SuggestConvertViaMethod {
span: expr.span.shrink_to_hi(),
sugg: ".as_deref()",
sugg,
expected,
found,
borrow_removal_span,
Expand All @@ -474,10 +485,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.can_eq(self.param_env, found, expected)
})
{
let sugg = prefix_wrap(".map(|x| x.as_str())");
err.span_suggestion_verbose(
expr.span.shrink_to_hi(),
fluent::hir_typeck_convert_to_str,
".map(|x| x.as_str())",
sugg,
Applicability::MachineApplicable,
);
return true;
Expand Down Expand Up @@ -628,12 +640,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.help("use `Box::pin`");
}
_ => {
let prefix = if let Some(name) =
self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr)
{
format!("{}: ", name)
} else {
String::new()
};
let suggestion = vec![
(expr.span.shrink_to_lo(), format!("{prefix}Box::pin(")),
(expr.span.shrink_to_hi(), ")".to_string()),
];
err.multipart_suggestion(
"you need to pin and box this expression",
vec![
(expr.span.shrink_to_lo(), "Box::pin(".to_string()),
(expr.span.shrink_to_hi(), ")".to_string()),
],
suggestion,
Applicability::MaybeIncorrect,
);
}
Expand Down Expand Up @@ -1214,14 +1234,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span = parent_callsite;
}

let sugg = if expr.precedence().order() >= PREC_POSTFIX {
let mut sugg = if expr.precedence().order() >= PREC_POSTFIX {
vec![(span.shrink_to_hi(), ".into()".to_owned())]
} else {
vec![
(span.shrink_to_lo(), "(".to_owned()),
(span.shrink_to_hi(), ").into()".to_owned()),
]
};
if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name)));
}
diag.multipart_suggestion(
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
sugg,
Expand Down
77 changes: 77 additions & 0 deletions tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// run-rustfix
// edition:2021
#![allow(dead_code)]
#![allow(unused_variables)]
use std::future::Future;
use std::pin::Pin;

fn test1() {
let string = String::from("Hello, world");

struct Demo<'a> {
option: Option<&'a str>,
}

let option: Option<String> = Some(string.clone());
let s = Demo { option: option.as_deref() }; //~ ERROR mismatched types
}

fn test2() {
let string = String::from("Hello, world");

struct Demo<'a> {
option_ref: Option<&'a str>,
}

let option_ref = Some(&string);
let s = Demo { option_ref: option_ref.map(|x| x.as_str()) }; //~ ERROR mismatched types
}

fn test3() {
let string = String::from("Hello, world");

struct Demo<'a> {
option_ref_ref: Option<&'a str>,
}

let option_ref = Some(&string);
let option_ref_ref = option_ref.as_ref();

let s = Demo { option_ref_ref: option_ref_ref.map(|x| x.as_str()) }; //~ ERROR mismatched types
}

fn test4() {
let a = 1;
struct Demo {
a: String,
}
let s = Demo { a: a.to_string() }; //~ ERROR mismatched types
}

type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
fn test5() {
let a = async { 42 };
struct Demo {
a: BoxFuture<'static, i32>,
}
let s = Demo { a: Box::pin(a) }; //~ ERROR mismatched types
}

fn test6() {
struct A;
struct B;

impl From<B> for A {
fn from(_: B) -> Self {
A
}
}

struct Demo {
a: A,
}
let a = B;
let s = Demo { a: a.into() }; //~ ERROR mismatched types
}

fn main() {}
77 changes: 77 additions & 0 deletions tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// run-rustfix
// edition:2021
#![allow(dead_code)]
#![allow(unused_variables)]
use std::future::Future;
use std::pin::Pin;

fn test1() {
let string = String::from("Hello, world");

struct Demo<'a> {
option: Option<&'a str>,
}

let option: Option<String> = Some(string.clone());
let s = Demo { option }; //~ ERROR mismatched types
}

fn test2() {
let string = String::from("Hello, world");

struct Demo<'a> {
option_ref: Option<&'a str>,
}

let option_ref = Some(&string);
let s = Demo { option_ref }; //~ ERROR mismatched types
}

fn test3() {
let string = String::from("Hello, world");

struct Demo<'a> {
option_ref_ref: Option<&'a str>,
}

let option_ref = Some(&string);
let option_ref_ref = option_ref.as_ref();

let s = Demo { option_ref_ref }; //~ ERROR mismatched types
}

fn test4() {
let a = 1;
struct Demo {
a: String,
}
let s = Demo { a }; //~ ERROR mismatched types
}

type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
fn test5() {
let a = async { 42 };
struct Demo {
a: BoxFuture<'static, i32>,
}
let s = Demo { a }; //~ ERROR mismatched types
}

fn test6() {
struct A;
struct B;

impl From<B> for A {
fn from(_: B) -> Self {
A
}
}

struct Demo {
a: A,
}
let a = B;
let s = Demo { a }; //~ ERROR mismatched types
}

fn main() {}
80 changes: 80 additions & 0 deletions tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:16:20
|
LL | let s = Demo { option };
| ^^^^^^ expected `Option<&str>`, found `Option<String>`
|
= note: expected enum `Option<&str>`
found enum `Option<String>`
help: try using `: option.as_deref()` to convert `Option<String>` to `Option<&str>`
|
LL | let s = Demo { option: option.as_deref() };
| +++++++++++++++++++

error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:27:20
|
LL | let s = Demo { option_ref };
| ^^^^^^^^^^ expected `Option<&str>`, found `Option<&String>`
|
= note: expected enum `Option<&str>`
found enum `Option<&String>`
help: try converting the passed type into a `&str`
|
LL | let s = Demo { option_ref: option_ref.map(|x| x.as_str()) };
| ++++++++++++++++++++++++++++++++

error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:40:20
|
LL | let s = Demo { option_ref_ref };
| ^^^^^^^^^^^^^^ expected `Option<&str>`, found `Option<&&String>`
|
= note: expected enum `Option<&str>`
found enum `Option<&&String>`
help: try converting the passed type into a `&str`
|
LL | let s = Demo { option_ref_ref: option_ref_ref.map(|x| x.as_str()) };
| ++++++++++++++++++++++++++++++++++++

error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:48:20
|
LL | let s = Demo { a };
| ^ expected `String`, found integer
|
help: try using a conversion method
|
LL | let s = Demo { a: a.to_string() };
| ++ ++++++++++++

error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:57:20
|
LL | let a = async { 42 };
| ------------ the found `async` block
...
LL | let s = Demo { a };
| ^ expected `Pin<Box<...>>`, found `async` block
|
= note: expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>`
found `async` block `{async block@$DIR/mismatch-sugg-for-shorthand-field.rs:53:13: 53:25}`
help: you need to pin and box this expression
|
LL | let s = Demo { a: Box::pin(a) };
| ++++++++++++ +

error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:74:20
|
LL | let s = Demo { a };
| ^ expected `A`, found `B`
|
help: call `Into::into` on this expression to convert `B` into `A`
|
LL | let s = Demo { a: a.into() };
| ++ +++++++

error: aborting due to 6 previous errors

For more information about this error, try `rustc --explain E0308`.

0 comments on commit 3a4edf0

Please sign in to comment.