about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTyler Mandry <tmandry@gmail.com>2020-01-22 16:02:17 -0800
committerGitHub <noreply@github.com>2020-01-22 16:02:17 -0800
commit1077adae129f140a98901f5c7fecf15f75bd8a4c (patch)
treee39c72e6a105c238f8377c2784c16d9484ac0c74
parent97ac2591480cd66e8b40b34420dd275235a80bd4 (diff)
parentdb3b40c2a1fe6129a7bbc12df6260b7197731153 (diff)
downloadrust-1077adae129f140a98901f5c7fecf15f75bd8a4c.tar.gz
rust-1077adae129f140a98901f5c7fecf15f75bd8a4c.zip
Rollup merge of #68425 - phi-gamma:try-method, r=varkor
Fix try-op diagnostic in E0277 for methods

For methods the try-op diagnostic displays the empty string where
it has more descriptive strings like “a function” otherwise:

    error[E0277]: the `?` operator can only be used in  that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
                                                      ^^
       | |             ^^ cannot use the `?` operator in  that returns `()`
                                                        ^^

I’m seeing this on nightly (rustc 1.42.0-nightly (b5a3341f1
2020-01-20)) and [on the playpen](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0e7ce7792c2aceb8056941710d539124).

The changeset add strings for impl methods and trait provided
methods and test cases for the option type.
-rw-r--r--src/librustc/traits/error_reporting/on_unimplemented.rs54
-rw-r--r--src/test/ui/try-on-option-diagnostics.rs29
-rw-r--r--src/test/ui/try-on-option-diagnostics.stderr28
3 files changed, 90 insertions, 21 deletions
diff --git a/src/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc/traits/error_reporting/on_unimplemented.rs
index 9f3fc91548b..2ba12baaf6d 100644
--- a/src/librustc/traits/error_reporting/on_unimplemented.rs
+++ b/src/librustc/traits/error_reporting/on_unimplemented.rs
@@ -59,31 +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(|| {
+        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"
+                    })
+                })
+            }
+            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 function"
+                    "an async method"
                 } else {
-                    "a function"
+                    "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,
         }
     }
 
diff --git a/src/test/ui/try-on-option-diagnostics.rs b/src/test/ui/try-on-option-diagnostics.rs
index 65d5e29ec2f..63d17414c31 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<u32> = 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<u32> = 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 ce3aca39fb8..c9dc3f1b879 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<u32> = 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<u32> = 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`.