From 02b3ae63e2d3fd2fe7496eaa8b6862322aaf38b3 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 31 Aug 2017 00:12:34 +0300 Subject: [PATCH] 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! --- src/libcore/ops/try.rs | 12 +++++-- src/librustc/traits/error_reporting.rs | 18 +++++++++- src/libsyntax_pos/lib.rs | 12 +++++++ .../ui/suggestions/try-operator-on-main.rs | 6 ++++ .../suggestions/try-operator-on-main.stderr | 35 +++++++++++++++---- 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 { + 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() {} 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 | -12 | std::fs::File::open("foo")?; +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() {} + | ^^^ + | + = 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