diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index b5fd3eb4462..0e198907c8d 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1375,22 +1375,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let matching_variants: Vec<_> = kind .variants() .iter() - .filter_map(|variant| { + .flat_map(|variant| { let [field] = &variant.fields[..] else { return None; }; let field_ty = field.ty(tcx, substs); // Skip `_`, since that'll just lead to ambiguity. - if matches!(self.resolve_vars_if_possible(field_ty).kind(), ty::Infer(_)) { + if self.resolve_vars_if_possible(field_ty).is_ty_var() { return None; } - if let Ok(pick) = - self.lookup_probe(span, item_name, field_ty, call_expr, ProbeScope::AllTraits) - { - Some((variant, field, pick)) - } else { - None - } + self.lookup_probe(span, item_name, field_ty, call_expr, ProbeScope::AllTraits) + .ok() + .map(|pick| (variant, field, pick)) }) .collect(); @@ -1409,45 +1405,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; match &matching_variants[..] { - [(_, field, pick)] if Some(kind.did()) == tcx.get_diagnostic_item(sym::Result) => { + [(_, field, pick)] => { let self_ty = field.ty(tcx, substs); err.span_note( tcx.def_span(pick.item.def_id), &format!("the method `{item_name}` exists on the type `{self_ty}`"), ); - if ret_ty_matches(sym::Result) { + let (article, kind, variant, question) = + if Some(kind.did()) == tcx.get_diagnostic_item(sym::Result) { + ("a", "Result", "Err", ret_ty_matches(sym::Result)) + } else if Some(kind.did()) == tcx.get_diagnostic_item(sym::Option) { + ("an", "Option", "None", ret_ty_matches(sym::Option)) + } else { + return; + }; + if question { err.span_suggestion_verbose( expr.span.shrink_to_hi(), - format!("use the `?` operator to extract the `{self_ty}` value, propagating a `Result::Err` value to the caller"), + format!( + "use the `?` operator to extract the `{self_ty}` value, propagating \ + {article} `{kind}::{variant}` value to the caller" + ), "?".to_owned(), Applicability::MachineApplicable, ); } else { err.span_suggestion_verbose( expr.span.shrink_to_hi(), - format!("consider using `Result::expect` to unwrap the `{self_ty}` value, panicking if the value is an `Err`"), - ".expect(\"REASON\")".to_owned(), - Applicability::HasPlaceholders, - ); - } - } - [(_, field, pick)] if Some(kind.did()) == tcx.get_diagnostic_item(sym::Option) => { - let self_ty = field.ty(tcx, substs); - err.span_note( - tcx.def_span(pick.item.def_id), - &format!("the method `{item_name}` exists on the type `{self_ty}`"), - ); - if ret_ty_matches(sym::Option) { - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - format!("use the `?` operator to extract the `{self_ty}` value, propagating a `None` to the caller"), - "?".to_owned(), - Applicability::MachineApplicable, - ); - } else { - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - format!("consider using `Option::expect` to unwrap the `{self_ty}` value, panicking if the value is `None`"), + format!( + "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \ + panicking if the value is {article} `{kind}::{variant}`" + ), ".expect(\"REASON\")".to_owned(), Applicability::HasPlaceholders, ); diff --git a/src/test/ui/suggestions/enum-method-probe.fixed b/src/test/ui/suggestions/enum-method-probe.fixed index 990f7900f22..6499c92bc6f 100644 --- a/src/test/ui/suggestions/enum-method-probe.fixed +++ b/src/test/ui/suggestions/enum-method-probe.fixed @@ -1,4 +1,6 @@ +// compile-flags: --edition=2021 // run-rustfix + #![allow(unused)] struct Foo; @@ -17,11 +19,26 @@ fn test_result_in_result() -> Result<(), ()> { Ok(()) } -fn test_result_in_plain() { +async fn async_test_result_in_result() -> Result<(), ()> { + let res: Result<_, ()> = Ok(Foo); + res?.get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP use the `?` operator + Ok(()) +} + +fn test_result_in_unit_return() { let res: Result<_, ()> = Ok(Foo); res.expect("REASON").get(); //~^ ERROR no method named `get` found for enum `Result` in the current scope - //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is an `Err` + //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` +} + +async fn async_test_result_in_unit_return() { + let res: Result<_, ()> = Ok(Foo); + res.expect("REASON").get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` } fn test_option_in_option() -> Option<()> { @@ -32,11 +49,11 @@ fn test_option_in_option() -> Option<()> { Some(()) } -fn test_option_in_plain() { +fn test_option_in_unit_return() { let res: Option<_> = Some(Foo); res.expect("REASON").get(); //~^ ERROR no method named `get` found for enum `Option` in the current scope - //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is `None` + //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None` } fn main() {} diff --git a/src/test/ui/suggestions/enum-method-probe.rs b/src/test/ui/suggestions/enum-method-probe.rs index 6270fa9fea5..18ea8ed8a58 100644 --- a/src/test/ui/suggestions/enum-method-probe.rs +++ b/src/test/ui/suggestions/enum-method-probe.rs @@ -1,4 +1,6 @@ +// compile-flags: --edition=2021 // run-rustfix + #![allow(unused)] struct Foo; @@ -17,11 +19,26 @@ fn test_result_in_result() -> Result<(), ()> { Ok(()) } -fn test_result_in_plain() { +async fn async_test_result_in_result() -> Result<(), ()> { let res: Result<_, ()> = Ok(Foo); res.get(); //~^ ERROR no method named `get` found for enum `Result` in the current scope - //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is an `Err` + //~| HELP use the `?` operator + Ok(()) +} + +fn test_result_in_unit_return() { + let res: Result<_, ()> = Ok(Foo); + res.get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` +} + +async fn async_test_result_in_unit_return() { + let res: Result<_, ()> = Ok(Foo); + res.get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` } fn test_option_in_option() -> Option<()> { @@ -32,11 +49,11 @@ fn test_option_in_option() -> Option<()> { Some(()) } -fn test_option_in_plain() { +fn test_option_in_unit_return() { let res: Option<_> = Some(Foo); res.get(); //~^ ERROR no method named `get` found for enum `Option` in the current scope - //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is `None` + //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None` } fn main() {} diff --git a/src/test/ui/suggestions/enum-method-probe.stderr b/src/test/ui/suggestions/enum-method-probe.stderr index 4af1775f66b..6ed14984f47 100644 --- a/src/test/ui/suggestions/enum-method-probe.stderr +++ b/src/test/ui/suggestions/enum-method-probe.stderr @@ -1,11 +1,11 @@ error[E0599]: no method named `get` found for enum `Result` in the current scope - --> $DIR/enum-method-probe.rs:14:9 + --> $DIR/enum-method-probe.rs:24:9 | LL | res.get(); | ^^^ method not found in `Result` | note: the method `get` exists on the type `Foo` - --> $DIR/enum-method-probe.rs:7:5 + --> $DIR/enum-method-probe.rs:9:5 | LL | fn get(&self) -> u8 { | ^^^^^^^^^^^^^^^^^^^ @@ -15,53 +15,85 @@ LL | res?.get(); | + error[E0599]: no method named `get` found for enum `Result` in the current scope - --> $DIR/enum-method-probe.rs:22:9 + --> $DIR/enum-method-probe.rs:39:9 | LL | res.get(); | ^^^ method not found in `Result` | note: the method `get` exists on the type `Foo` - --> $DIR/enum-method-probe.rs:7:5 + --> $DIR/enum-method-probe.rs:9:5 | LL | fn get(&self) -> u8 { | ^^^^^^^^^^^^^^^^^^^ -help: consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is an `Err` +help: consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` + | +LL | res.expect("REASON").get(); + | +++++++++++++++++ + +error[E0599]: no method named `get` found for enum `Result` in the current scope + --> $DIR/enum-method-probe.rs:16:9 + | +LL | res.get(); + | ^^^ method not found in `Result` + | +note: the method `get` exists on the type `Foo` + --> $DIR/enum-method-probe.rs:9:5 + | +LL | fn get(&self) -> u8 { + | ^^^^^^^^^^^^^^^^^^^ +help: use the `?` operator to extract the `Foo` value, propagating a `Result::Err` value to the caller + | +LL | res?.get(); + | + + +error[E0599]: no method named `get` found for enum `Result` in the current scope + --> $DIR/enum-method-probe.rs:32:9 + | +LL | res.get(); + | ^^^ method not found in `Result` + | +note: the method `get` exists on the type `Foo` + --> $DIR/enum-method-probe.rs:9:5 + | +LL | fn get(&self) -> u8 { + | ^^^^^^^^^^^^^^^^^^^ +help: consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` | LL | res.expect("REASON").get(); | +++++++++++++++++ error[E0599]: no method named `get` found for enum `Option` in the current scope - --> $DIR/enum-method-probe.rs:29:9 + --> $DIR/enum-method-probe.rs:46:9 | LL | res.get(); | ^^^ method not found in `Option` | note: the method `get` exists on the type `Foo` - --> $DIR/enum-method-probe.rs:7:5 + --> $DIR/enum-method-probe.rs:9:5 | LL | fn get(&self) -> u8 { | ^^^^^^^^^^^^^^^^^^^ -help: use the `?` operator to extract the `Foo` value, propagating a `None` to the caller +help: use the `?` operator to extract the `Foo` value, propagating an `Option::None` value to the caller | LL | res?.get(); | + error[E0599]: no method named `get` found for enum `Option` in the current scope - --> $DIR/enum-method-probe.rs:37:9 + --> $DIR/enum-method-probe.rs:54:9 | LL | res.get(); | ^^^ method not found in `Option` | note: the method `get` exists on the type `Foo` - --> $DIR/enum-method-probe.rs:7:5 + --> $DIR/enum-method-probe.rs:9:5 | LL | fn get(&self) -> u8 { | ^^^^^^^^^^^^^^^^^^^ -help: consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is `None` +help: consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None` | LL | res.expect("REASON").get(); | +++++++++++++++++ -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0599`.