From c31bde8d6d6e44e277f1760499331a0f94cecd7a Mon Sep 17 00:00:00 2001 From: Hunter Praska Date: Sat, 19 Aug 2017 00:32:10 -0500 Subject: [PATCH 1/3] Make Try a lang item --- src/libcore/ops/try.rs | 1 + src/librustc/middle/lang_items.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index 78326c3e6391a..41d0a6992b26e 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -14,6 +14,7 @@ /// in terms of a success/failure dichotomy. This trait allows both /// extracting those success or failure values from an existing instance and /// creating a new instance from a success or failure value. +#[cfg_attr(not(stage0), lang = "try")] #[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}`)"] diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 01ed79096b101..ad1339843cbfe 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -320,6 +320,8 @@ language_item_table! { StrEqFnLangItem, "str_eq", str_eq_fn; + TryTraitLangItem, "try", try_trait; + // A number of panic-related lang items. The `panic` item corresponds to // divide-by-zero and various panic cases with `match`. The // `panic_bounds_check` item is for indexing arrays. From f83b4d1a9f78d6a43d1be663ca2d4bf288ad0e4b Mon Sep 17 00:00:00 2001 From: Hunter Praska Date: Sat, 19 Aug 2017 05:21:47 -0500 Subject: [PATCH 2/3] Work on error handling for `?` This commit implements the `Source type does not implement Try` situation of RFC 1859. --- src/librustc/traits/error_reporting.rs | 27 ++++++++++++------- src/test/ui/suggestions/try-unimplemented.rs | 22 +++++++++++++++ .../ui/suggestions/try-unimplemented.stderr | 26 ++++++++++++++++++ 3 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/suggestions/try-unimplemented.rs create mode 100644 src/test/ui/suggestions/try-unimplemented.stderr diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index c04d448716c5b..438b5953b982d 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -33,6 +33,7 @@ use infer::type_variable::TypeVariableOrigin; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; use syntax::ast; +use syntax::codemap::CompilerDesugaringKind; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; use ty::fast_reject; @@ -585,21 +586,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trait_ref.to_predicate(), post_message); + let is_desugaring = span + .is_compiler_desugaring(CompilerDesugaringKind::QuestionMark); + let def_id = trait_predicate.skip_binder().def_id(); let unimplemented_note = self.on_unimplemented_note(trait_ref, obligation); - if let Some(ref s) = unimplemented_note { + let help_msg = format!("{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_ref, + trait_ref.self_ty()); + + if is_desugaring && Some(def_id) == self.tcx.lang_items.try_trait() { + err.span_label(span, + format!("`?` cannot be applied to a value of type `{}`", + trait_ref.self_ty())); + err.help(&help_msg); + } else if let Some(ref s) = unimplemented_note { // If it has a custom "#[rustc_on_unimplemented]" // error message, let's display it as the label! err.span_label(span, s.as_str()); - err.help(&format!("{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty())); + err.help(&help_msg); } else { - err.span_label(span, - &*format!("{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty())); + err.span_label(span, help_msg); } // Try to report a help message diff --git a/src/test/ui/suggestions/try-unimplemented.rs b/src/test/ui/suggestions/try-unimplemented.rs new file mode 100644 index 0000000000000..b5806febb9b2d --- /dev/null +++ b/src/test/ui/suggestions/try-unimplemented.rs @@ -0,0 +1,22 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + source(); + ret(); +} + +fn source() -> u32 { + 3u32? +} + +fn ret() { + Ok(3u32)?; +} diff --git a/src/test/ui/suggestions/try-unimplemented.stderr b/src/test/ui/suggestions/try-unimplemented.stderr new file mode 100644 index 0000000000000..b35d119a5c4e6 --- /dev/null +++ b/src/test/ui/suggestions/try-unimplemented.stderr @@ -0,0 +1,26 @@ +error[E0277]: the trait bound `u32: std::ops::Try` is not satisfied + --> $DIR/try-unimplemented.rs:17:5 + | +17 | 3u32? + | ----- + | | + | `?` cannot be applied to a value of type `u32` + | in this macro invocation + | + = help: the trait `std::ops::Try` is not implemented for `u32` + = note: required by `std::ops::Try::into_result` + +error[E0277]: the trait bound `(): std::ops::Try` is not satisfied + --> $DIR/try-unimplemented.rs:21:5 + | +21 | Ok(3u32)?; + | --------- + | | + | cannot use the `?` operator in a function that returns `()` + | 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 2 previous errors + From 272eb29aa1b6a7c2e78aef7a1a5514972c464e35 Mon Sep 17 00:00:00 2001 From: Hunter Praska Date: Mon, 28 Aug 2017 20:39:42 -0500 Subject: [PATCH 3/3] Remove macro error msg for `?` --- src/librustc_errors/emitter.rs | 6 ++++-- src/test/ui/suggestions/try-operator-on-main.stderr | 1 - src/test/ui/suggestions/try-unimplemented.stderr | 10 ++-------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 3b1414ef83a69..748f46025e6e2 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -10,7 +10,7 @@ use self::Destination::*; -use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; +use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan, CharPos, CompilerDesugaringKind}; use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper}; use RenderSpan::*; @@ -724,7 +724,9 @@ impl EmitterWriter { // First, find all the spans in <*macros> and point instead at their use site for sp in span.primary_spans() { - if *sp == DUMMY_SP { + if *sp == DUMMY_SP || + sp.is_compiler_desugaring(CompilerDesugaringKind::QuestionMark) + { continue; } let call_sp = cm.call_span_if_macro(*sp); diff --git a/src/test/ui/suggestions/try-operator-on-main.stderr b/src/test/ui/suggestions/try-operator-on-main.stderr index cf0481bdab772..10d6c1207786f 100644 --- a/src/test/ui/suggestions/try-operator-on-main.stderr +++ b/src/test/ui/suggestions/try-operator-on-main.stderr @@ -5,7 +5,6 @@ error[E0277]: the trait bound `(): std::ops::Try` is not satisfied | --------------------------- | | | the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`) - | in this macro invocation | = help: the trait `std::ops::Try` is not implemented for `()` = note: required by `std::ops::Try::from_error` diff --git a/src/test/ui/suggestions/try-unimplemented.stderr b/src/test/ui/suggestions/try-unimplemented.stderr index b35d119a5c4e6..a8d269bb7e45b 100644 --- a/src/test/ui/suggestions/try-unimplemented.stderr +++ b/src/test/ui/suggestions/try-unimplemented.stderr @@ -2,10 +2,7 @@ error[E0277]: the trait bound `u32: std::ops::Try` is not satisfied --> $DIR/try-unimplemented.rs:17:5 | 17 | 3u32? - | ----- - | | - | `?` cannot be applied to a value of type `u32` - | in this macro invocation + | ^^^^^ `?` cannot be applied to a value of type `u32` | = help: the trait `std::ops::Try` is not implemented for `u32` = note: required by `std::ops::Try::into_result` @@ -14,10 +11,7 @@ error[E0277]: the trait bound `(): std::ops::Try` is not satisfied --> $DIR/try-unimplemented.rs:21:5 | 21 | Ok(3u32)?; - | --------- - | | - | cannot use the `?` operator in a function that returns `()` - | in this macro invocation + | ^^^^^^^^^ cannot use the `?` operator in a function that returns `()` | = help: the trait `std::ops::Try` is not implemented for `()` = note: required by `std::ops::Try::from_error`