about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-08-31 00:12:34 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-09-03 13:10:54 +0300
commit02b3ae63e2d3fd2fe7496eaa8b6862322aaf38b3 (patch)
tree6e1a3525e66f0c7a6da07c26769bcda7d0eaf4d1
parent6866aea5af0cebe3c3a942585e36c9033e1122ef (diff)
downloadrust-02b3ae63e2d3fd2fe7496eaa8b6862322aaf38b3.tar.gz
rust-02b3ae63e2d3fd2fe7496eaa8b6862322aaf38b3.zip
enable desugaring-sensitive error messages and use them in Try
Maybe I should allow error messages to check the *specific* desugaring?
Thanks @huntiep for the idea!
-rw-r--r--src/libcore/ops/try.rs12
-rw-r--r--src/librustc/traits/error_reporting.rs18
-rw-r--r--src/libsyntax_pos/lib.rs12
-rw-r--r--src/test/ui/suggestions/try-operator-on-main.rs6
-rw-r--r--src/test/ui/suggestions/try-operator-on-main.stderr35
5 files changed, 74 insertions, 9 deletions
diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs
index 78326c3e639..694d5b8296f 100644
--- a/src/libcore/ops/try.rs
+++ b/src/libcore/ops/try.rs
@@ -15,8 +15,16 @@
 /// extracting those success or failure values from an existing instance and
 /// creating a new instance from a success or failure value.
 #[unstable(feature = "try_trait", issue = "42327")]
-#[rustc_on_unimplemented = "the `?` operator can only be used in a function that returns `Result` \
-                            (or another type that implements `{Try}`)"]
+#[cfg_attr(stage0,
+           rustc_on_unimplemented = "the `?` operator can only be used in a \
+                                     function that returns `Result` \
+                                     (or another type that implements `{Try}`)")]
+#[cfg_attr(not(stage0),
+           rustc_on_unimplemented(
+               on(all(direct, from_desugaring),
+                  message="the `?` operator can only be used in a \
+                           function that returns `Result` \
+                           (or another type that implements `{Try}`)")))]
 pub trait Try {
     /// The type of this value when viewed as successful.
     #[unstable(feature = "try_trait", issue = "42327")]
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 48cd0358591..b5f9f4d1436 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -327,10 +327,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             .unwrap_or(trait_ref.def_id());
         let trait_ref = *trait_ref.skip_binder();
 
+        let mut flags = vec![];
+        let direct = match obligation.cause.code {
+            ObligationCauseCode::BuiltinDerivedObligation(..) |
+            ObligationCauseCode::ImplDerivedObligation(..) => false,
+            _ => true
+        };
+        if direct {
+            // this is a "direct", user-specified, rather than derived,
+            // obligation.
+            flags.push("direct");
+        }
+
+        if let Some(_) = obligation.cause.span.compiler_desugaring_kind() {
+            flags.push("from_desugaring");
+        }
+
         if let Ok(Some(command)) = OnUnimplementedDirective::of_item(
             self.tcx, trait_ref.def_id, def_id
         ) {
-            command.evaluate(self.tcx, trait_ref, &[])
+            command.evaluate(self.tcx, trait_ref, &flags)
         } else {
             OnUnimplementedNote::empty()
         }
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 24842ff29d4..cba5c812b07 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -205,6 +205,18 @@ impl Span {
         }
     }
 
+    /// Return the compiler desugaring that created this span, or None
+    /// if this span is not from a desugaring.
+    pub fn compiler_desugaring_kind(&self) -> Option<CompilerDesugaringKind> {
+        match self.ctxt().outer().expn_info() {
+            Some(info) => match info.callee.format {
+                ExpnFormat::CompilerDesugaring(k) => Some(k),
+                _ => None
+            },
+            None => None
+        }
+    }
+
     /// Check if a span is "internal" to a macro in which `unsafe`
     /// can be used without triggering the `unsafe_code` lint
     //  (that is, a macro marked with `#[allow_internal_unsafe]`).
diff --git a/src/test/ui/suggestions/try-operator-on-main.rs b/src/test/ui/suggestions/try-operator-on-main.rs
index 55154e3507e..c6b4c091901 100644
--- a/src/test/ui/suggestions/try-operator-on-main.rs
+++ b/src/test/ui/suggestions/try-operator-on-main.rs
@@ -8,6 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::ops::Try;
+
 fn main() {
     std::fs::File::open("foo")?;
+
+    try_trait_generic::<()>();
 }
+
+fn try_trait_generic<T: Try>() {}
diff --git a/src/test/ui/suggestions/try-operator-on-main.stderr b/src/test/ui/suggestions/try-operator-on-main.stderr
index cf0481bdab7..66bd77bb690 100644
--- a/src/test/ui/suggestions/try-operator-on-main.stderr
+++ b/src/test/ui/suggestions/try-operator-on-main.stderr
@@ -1,14 +1,37 @@
-error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
-  --> $DIR/try-operator-on-main.rs:12:5
+error: use of unstable library feature 'try_trait' (see issue #42327)
+  --> $DIR/try-operator-on-main.rs:11:5
+   |
+11 | use std::ops::Try;
+   |     ^^^^^^^^^^^^^
+   |
+   = help: add #![feature(try_trait)] to the crate attributes to enable
+
+error: use of unstable library feature 'try_trait' (see issue #42327)
+  --> $DIR/try-operator-on-main.rs:19:25
+   |
+19 | fn try_trait_generic<T: Try>() {}
+   |                         ^^^
    |
-12 |     std::fs::File::open("foo")?;
+   = help: add #![feature(try_trait)] to the crate attributes to enable
+
+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:14:5
+   |
+14 |     std::fs::File::open("foo")?;
    |     ---------------------------
    |     |
-   |     the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`)
+   |     the trait `std::ops::Try` is not implemented for `()`
    |     in this macro invocation
    |
-   = help: the trait `std::ops::Try` is not implemented for `()`
    = note: required by `std::ops::Try::from_error`
 
-error: aborting due to previous error
+error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
+  --> $DIR/try-operator-on-main.rs:16:5
+   |
+16 |     try_trait_generic::<()>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Try` is not implemented for `()`
+   |
+   = note: required by `try_trait_generic`
+
+error: aborting due to 4 previous errors