From 5dee7dddf24a022184a743b714b5062e83516a87 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 21 Jan 2020 21:49:23 +0100 Subject: [PATCH 1/3] Handle methods in try diagnostic The diagnostic for diagnostic for methods and trait provided methods would only show the empty string: error[E0277]: the `?` operator can only be used in that returns `Result` or `Option` (or another type that implements `std::ops::Try`) Handle the missing cases so it reads ``a method'' / ``an async method'' / ``a trait method'' respectively. Signed-off-by: Philipp Gesang --- .../traits/error_reporting/on_unimplemented.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc/traits/error_reporting/on_unimplemented.rs index 9f3fc91548b21..8f55540cae38a 100644 --- a/src/librustc/traits/error_reporting/on_unimplemented.rs +++ b/src/librustc/traits/error_reporting/on_unimplemented.rs @@ -67,6 +67,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "a function" }) }) + } else if let hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)), + .. + }) = &node + { + self.describe_generator(*body_id).or_else(|| Some("a trait method")) + } else if let hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Method(sig, body_id), + .. + }) = &node + { + self.describe_generator(*body_id).or_else(|| { + Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { + "an async method" + } else { + "a method" + }) + }) } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), .. From 02e66baac6882ef30e607d2bca98929f01758957 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 21 Jan 2020 21:51:13 +0100 Subject: [PATCH 2/3] Test try diagnostics for impl and trait methods Signed-off-by: Philipp Gesang --- src/test/ui/try-on-option-diagnostics.rs | 29 ++++++++++++++++++++ src/test/ui/try-on-option-diagnostics.stderr | 28 ++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/test/ui/try-on-option-diagnostics.rs b/src/test/ui/try-on-option-diagnostics.rs index 65d5e29ec2f13..63d17414c313b 100644 --- a/src/test/ui/try-on-option-diagnostics.rs +++ b/src/test/ui/try-on-option-diagnostics.rs @@ -16,3 +16,32 @@ fn a_closure() -> u32 { }; a_closure() } + +fn a_method() -> u32 { + struct S; + + impl S { + fn a_method() { + let x: Option = None; + x?; //~ ERROR the `?` operator + } + } + + S::a_method(); + 22 +} + +fn a_trait_method() -> u32 { + struct S; + trait T { + fn a_trait_method() { + let x: Option = None; + x?; //~ ERROR the `?` operator + } + } + + impl T for S { } + + S::a_trait_method(); + 22 +} diff --git a/src/test/ui/try-on-option-diagnostics.stderr b/src/test/ui/try-on-option-diagnostics.stderr index ce3aca39fb8fb..c9dc3f1b87969 100644 --- a/src/test/ui/try-on-option-diagnostics.stderr +++ b/src/test/ui/try-on-option-diagnostics.stderr @@ -27,6 +27,32 @@ LL | | }; = help: the trait `std::ops::Try` is not implemented for `{integer}` = note: required by `std::ops::Try::from_error` -error: aborting due to 2 previous errors +error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `std::ops::Try`) + --> $DIR/try-on-option-diagnostics.rs:26:13 + | +LL | / fn a_method() { +LL | | let x: Option = None; +LL | | x?; + | | ^^ cannot use the `?` operator in a method that returns `()` +LL | | } + | |_________- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `std::ops::Try` is not implemented for `()` + = note: required by `std::ops::Try::from_error` + +error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `std::ops::Try`) + --> $DIR/try-on-option-diagnostics.rs:39:13 + | +LL | / fn a_trait_method() { +LL | | let x: Option = None; +LL | | x?; + | | ^^ cannot use the `?` operator in a trait method that returns `()` +LL | | } + | |_________- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `std::ops::Try` is not implemented for `()` + = note: required by `std::ops::Try::from_error` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. From db3b40c2a1fe6129a7bbc12df6260b7197731153 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 21 Jan 2020 21:46:38 +0100 Subject: [PATCH 3/3] Cleanup: rewrite conditional as match As suggested by @Centril. Signed-off-by: Philipp Gesang --- .../error_reporting/on_unimplemented.rs | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc/traits/error_reporting/on_unimplemented.rs index 8f55540cae38a..2ba12baaf6d6e 100644 --- a/src/librustc/traits/error_reporting/on_unimplemented.rs +++ b/src/librustc/traits/error_reporting/on_unimplemented.rs @@ -59,49 +59,45 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> { let hir = &self.tcx.hir(); let node = hir.find(hir_id)?; - if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = &node { - self.describe_generator(*body_id).or_else(|| { - Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { - "an async function" - } else { - "a function" + match &node { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => { + self.describe_generator(*body_id).or_else(|| { + Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { + "an async function" + } else { + "a function" + }) }) - }) - } else if let hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)), - .. - }) = &node - { - self.describe_generator(*body_id).or_else(|| Some("a trait method")) - } else if let hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Method(sig, body_id), - .. - }) = &node - { - self.describe_generator(*body_id).or_else(|| { + } + hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)), + .. + }) => self.describe_generator(*body_id).or_else(|| Some("a trait method")), + hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Method(sig, body_id), + .. + }) => self.describe_generator(*body_id).or_else(|| { Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { "an async method" } else { "a method" }) - }) - } else if let hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), - .. - }) = &node - { - self.describe_generator(*body_id).or_else(|| { + }), + hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), + .. + }) => self.describe_generator(*body_id).or_else(|| { Some(if gen_movability.is_some() { "an async closure" } else { "a closure" }) - }) - } else if let hir::Node::Expr(hir::Expr { .. }) = &node { - let parent_hid = hir.get_parent_node(hir_id); - if parent_hid != hir_id { - return self.describe_enclosure(parent_hid); - } else { - None + }), + hir::Node::Expr(hir::Expr { .. }) => { + let parent_hid = hir.get_parent_node(hir_id); + if parent_hid != hir_id { + return self.describe_enclosure(parent_hid); + } else { + None + } } - } else { - None + _ => None, } }