Skip to content

Commit

Permalink
Rollup merge of rust-lang#118413 - chenyukang:yukang-fix-118145-unwra…
Browse files Browse the repository at this point in the history
…p-for-shorthand, r=compiler-errors

Fix the issue of suggesting unwrap/expect for shorthand field

Fixes rust-lang#118145
  • Loading branch information
matthiaskrgr authored Nov 29, 2023
2 parents 69e48d0 + 3a4edf0 commit 8727538
Show file tree
Hide file tree
Showing 8 changed files with 341 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>,
}
45 changes: 37 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 Expand Up @@ -1811,6 +1834,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
".expect(\"REASON\")",
)
};

let sugg = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!(": {ident}{sugg}"),
None => sugg.to_string(),
};

err.span_suggestion_verbose(
expr.span.shrink_to_hi(),
msg,
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// run-rustfix
#![allow(unused, dead_code)]

#[derive(Clone, Copy)]
struct Stuff {
count: i32,
}
struct Error;

fn demo() -> Result<Stuff, Error> {
let count = Ok(1);
Ok(Stuff { count: count? }) //~ ERROR mismatched types
}

fn demo_unwrap() -> Stuff {
let count = Some(1);
Stuff { count: count.expect("REASON") } //~ ERROR mismatched types
}

fn main() {}
20 changes: 20 additions & 0 deletions tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// run-rustfix
#![allow(unused, dead_code)]

#[derive(Clone, Copy)]
struct Stuff {
count: i32,
}
struct Error;

fn demo() -> Result<Stuff, Error> {
let count = Ok(1);
Ok(Stuff { count }) //~ ERROR mismatched types
}

fn demo_unwrap() -> Stuff {
let count = Some(1);
Stuff { count } //~ ERROR mismatched types
}

fn main() {}
29 changes: 29 additions & 0 deletions tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
error[E0308]: mismatched types
--> $DIR/issue-118145-unwrap-for-shorthand.rs:12:16
|
LL | Ok(Stuff { count })
| ^^^^^ expected `i32`, found `Result<{integer}, _>`
|
= note: expected type `i32`
found enum `Result<{integer}, _>`
help: use the `?` operator to extract the `Result<{integer}, _>` value, propagating a `Result::Err` value to the caller
|
LL | Ok(Stuff { count: count? })
| ++++++++

error[E0308]: mismatched types
--> $DIR/issue-118145-unwrap-for-shorthand.rs:17:13
|
LL | Stuff { count }
| ^^^^^ expected `i32`, found `Option<{integer}>`
|
= note: expected type `i32`
found enum `Option<{integer}>`
help: consider using `Option::expect` to unwrap the `Option<{integer}>` value, panicking if the value is an `Option::None`
|
LL | Stuff { count: count.expect("REASON") }
| ++++++++++++++++++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0308`.
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() {}
Loading

0 comments on commit 8727538

Please sign in to comment.