diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7b0138d50baed..6c4eb5d570519 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1154,6 +1154,7 @@ symbols! { offset_of, offset_of_enum, offset_of_nested, + ok_or, ok_or_else, omit_gdb_pretty_printer_section, on, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 149dcffe333de..7d371a4226193 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1155,6 +1155,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } + if path_segment.ident.name == sym::ok_or && is_diagnostic_item(sym::Option, next_ty) { + err.span_suggestion( + path_segment.ident.span, + format!( + "`?` expected `{}` for `Err` variant but found `{:?}`. Use the `ok_or_else` method to pass a closure", + self_ty, + get_e_type(prev_ty).unwrap().to_string(), + ), + "ok_or_else", + Applicability::MachineApplicable, + ); + } + prev_ty = next_ty; if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind diff --git a/tests/ui/closures/closure-ok-or.fixed b/tests/ui/closures/closure-ok-or.fixed new file mode 100644 index 0000000000000..2ebe4fcab003f --- /dev/null +++ b/tests/ui/closures/closure-ok-or.fixed @@ -0,0 +1,8 @@ +// run-rustfix + +// issue #119765 + +fn main() -> Result<(), bool> { + None.ok_or_else(|| true)? + //~^ ERROR `?` couldn't convert the error to `bool` [E0277] +} diff --git a/tests/ui/closures/closure-ok-or.rs b/tests/ui/closures/closure-ok-or.rs new file mode 100644 index 0000000000000..6b0c8abfe0498 --- /dev/null +++ b/tests/ui/closures/closure-ok-or.rs @@ -0,0 +1,8 @@ +// run-rustfix + +// issue #119765 + +fn main() -> Result<(), bool> { + None.ok_or(|| true)? + //~^ ERROR `?` couldn't convert the error to `bool` [E0277] +} diff --git a/tests/ui/closures/closure-ok-or.stderr b/tests/ui/closures/closure-ok-or.stderr new file mode 100644 index 0000000000000..2584d2c489f9c --- /dev/null +++ b/tests/ui/closures/closure-ok-or.stderr @@ -0,0 +1,23 @@ +error[E0277]: `?` couldn't convert the error to `bool` + --> $DIR/closure-ok-or.rs:6:24 + | +LL | fn main() -> Result<(), bool> { + | ---------------- expected `bool` because of this +LL | None.ok_or(|| true)? + | --------------^ the trait `From<{closure@$DIR/closure-ok-or.rs:6:16: 6:18}>` is not implemented for `bool` + | | + | this can't be annotated with `?` because it has type `Result<_, {closure@$DIR/closure-ok-or.rs:6:16: 6:18}>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = help: the following other types implement trait `FromResidual`: + as FromResidual>> + as FromResidual>> + = note: required for `Result<(), bool>` to implement `FromResidual>` +help: `?` expected `bool` for `Err` variant but found `"{closure@$DIR/closure-ok-or.rs:6:16: 6:18}"`. Use the `ok_or_else` method to pass a closure + | +LL | None.ok_or_else(|| true)? + | ~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.