about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-08-31 21:46:03 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-09-03 13:10:54 +0300
commitefa09ea554575cd0b4ce01ada44fce730c0f7ac4 (patch)
tree896816568ac690f302bad2440a353a0f13eb91ad /src
parent6dec953c5ad7357a9f2d90626e56bc0dc30127a9 (diff)
downloadrust-efa09ea554575cd0b4ce01ada44fce730c0f7ac4.tar.gz
rust-efa09ea554575cd0b4ce01ada44fce730c0f7ac4.zip
on_unimplemented: add method-name checks and use them in Try
Diffstat (limited to 'src')
-rw-r--r--src/libcore/ops/try.rs4
-rw-r--r--src/librustc/traits/error_reporting.rs20
-rw-r--r--src/librustc/traits/on_unimplemented.rs11
-rw-r--r--src/test/ui/suggestions/try-operator-on-main.rs14
-rw-r--r--src/test/ui/suggestions/try-operator-on-main.stderr32
5 files changed, 69 insertions, 12 deletions
diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs
index 6e330f538a8..28e84d2fba6 100644
--- a/src/libcore/ops/try.rs
+++ b/src/libcore/ops/try.rs
@@ -21,7 +21,9 @@
                                      (or another type that implements `{Try}`)")]
 #[cfg_attr(not(stage0),
            rustc_on_unimplemented(
-               on(all(direct, from_desugaring="?"),
+               on(all(
+                   any(from_method="from_error", from_method="from_ok"),
+                   from_desugaring="?"),
                   message="the `?` operator can only be used in a \
                            function that returns `Result` \
                            (or another type that implements `{Try}`)",
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 509f3420628..ce6da55fec3 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -327,7 +327,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             .unwrap_or(trait_ref.def_id());
         let trait_ref = *trait_ref.skip_binder();
 
-        let s;
+        let desugaring;
+        let method;
         let mut flags = vec![];
         let direct = match obligation.cause.code {
             ObligationCauseCode::BuiltinDerivedObligation(..) |
@@ -340,10 +341,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             flags.push(("direct", None));
         }
 
+        if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
+            // FIXME: maybe also have some way of handling methods
+            // from other traits? That would require name resolution,
+            // which we might want to be some sort of hygienic.
+            //
+            // Currently I'm leaving it for what I need for `try`.
+            if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
+                method = self.tcx.item_name(item).as_str();
+                flags.push(("from_method", None));
+                flags.push(("from_method", Some(&*method)));
+            }
+        }
+
         if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
-            s = k.as_symbol().as_str();
+            desugaring = k.as_symbol().as_str();
             flags.push(("from_desugaring", None));
-            flags.push(("from_desugaring", Some(&*s)));
+            flags.push(("from_desugaring", Some(&*desugaring)));
         }
 
         if let Ok(Some(command)) = OnUnimplementedDirective::of_item(
diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs
index 2cfee21936c..7dd3fc70b1e 100644
--- a/src/librustc/traits/on_unimplemented.rs
+++ b/src/librustc/traits/on_unimplemented.rs
@@ -176,6 +176,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
     {
         let mut message = None;
         let mut label = None;
+        info!("evaluate({:?}, trait_ref={:?}, options={:?})",
+              self, trait_ref, options);
 
         for command in self.subcommands.iter().chain(Some(self)).rev() {
             if let Some(ref condition) = command.condition {
@@ -191,8 +193,13 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
                 }
             }
             debug!("evaluate: {:?} succeeded", command);
-            message = command.message.clone();
-            label = command.label.clone();
+            if let Some(ref message_) = command.message {
+                message = Some(message_.clone());
+            }
+
+            if let Some(ref label_) = command.label {
+                label = Some(label_.clone());
+            }
         }
 
         OnUnimplementedNote {
diff --git a/src/test/ui/suggestions/try-operator-on-main.rs b/src/test/ui/suggestions/try-operator-on-main.rs
index d81f773442c..473efea54de 100644
--- a/src/test/ui/suggestions/try-operator-on-main.rs
+++ b/src/test/ui/suggestions/try-operator-on-main.rs
@@ -13,9 +13,21 @@
 use std::ops::Try;
 
 fn main() {
+    // error for a `Try` type on a non-`Try` fn
     std::fs::File::open("foo")?;
 
+    // a non-`Try` type on a `Try` fn
+    ()?;
+
+    // an unrelated use of `Try`
     try_trait_generic::<()>();
 }
 
-fn try_trait_generic<T: Try>() {}
+
+
+fn try_trait_generic<T: Try>() -> T {
+    // and a non-`Try` object on a `Try` fn.
+    ()?;
+
+    loop {}
+}
diff --git a/src/test/ui/suggestions/try-operator-on-main.stderr b/src/test/ui/suggestions/try-operator-on-main.stderr
index 0d3e67e99a8..5fc24e46fa7 100644
--- a/src/test/ui/suggestions/try-operator-on-main.stderr
+++ b/src/test/ui/suggestions/try-operator-on-main.stderr
@@ -1,7 +1,7 @@
 error[E0277]: the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`)
-  --> $DIR/try-operator-on-main.rs:16:5
+  --> $DIR/try-operator-on-main.rs:17:5
    |
-16 |     std::fs::File::open("foo")?;
+17 |     std::fs::File::open("foo")?;
    |     ---------------------------
    |     |
    |     cannot use the `?` operator in a function that returns `()`
@@ -11,12 +11,34 @@ error[E0277]: the `?` operator can only be used in a function that returns `Resu
    = note: required by `std::ops::Try::from_error`
 
 error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
-  --> $DIR/try-operator-on-main.rs:18:5
+  --> $DIR/try-operator-on-main.rs:20:5
    |
-18 |     try_trait_generic::<()>();
+20 |     ()?;
+   |     ---
+   |     |
+   |     the trait `std::ops::Try` is not implemented for `()`
+   |     in this macro invocation
+   |
+   = note: required by `std::ops::Try::into_result`
+
+error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
+  --> $DIR/try-operator-on-main.rs:23:5
+   |
+23 |     try_trait_generic::<()>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Try` is not implemented for `()`
    |
    = note: required by `try_trait_generic`
 
-error: aborting due to 2 previous errors
+error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
+  --> $DIR/try-operator-on-main.rs:30:5
+   |
+30 |     ()?;
+   |     ---
+   |     |
+   |     the trait `std::ops::Try` is not implemented for `()`
+   |     in this macro invocation
+   |
+   = note: required by `std::ops::Try::into_result`
+
+error: aborting due to 4 previous errors