From edba0c92de737ff6d65255865366e0fddf76780c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 4 Sep 2022 02:10:31 +0000 Subject: [PATCH] Address nits, rename enclosing_scope => parent_label --- compiler/rustc_span/src/symbol.rs | 2 +- .../src/traits/error_reporting/mod.rs | 10 +-- .../src/traits/on_unimplemented.rs | 24 +++--- library/core/src/ops/try_trait.rs | 84 ++++++++++++++++++- .../ui/on-unimplemented/enclosing-scope.rs | 27 ------ src/test/ui/on-unimplemented/parent-label.rs | 27 ++++++ ...osing-scope.stderr => parent-label.stderr} | 32 +++---- 7 files changed, 141 insertions(+), 65 deletions(-) delete mode 100644 src/test/ui/on-unimplemented/enclosing-scope.rs create mode 100644 src/test/ui/on-unimplemented/parent-label.rs rename src/test/ui/on-unimplemented/{enclosing-scope.stderr => parent-label.stderr} (67%) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 64b919587e8..1da8c69490b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -661,7 +661,6 @@ symbols! { emit_struct, emit_struct_field, enable, - enclosing_scope, encode, end, env, @@ -1063,6 +1062,7 @@ symbols! { panic_unwind, panicking, param_attrs, + parent_label, partial_cmp, partial_ord, passes, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 8fd2e1de7a1..6ebadb42d9e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -349,7 +349,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { message, label, note, - enclosing_scope, + parent_label, append_const_msg, } = self.on_unimplemented_note(trait_ref, &obligation); let have_alt_message = message.is_some() || label.is_some(); @@ -515,7 +515,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If it has a custom `#[rustc_on_unimplemented]` note, let's display it err.note(s.as_str()); } - if let Some(ref s) = enclosing_scope { + if let Some(ref s) = parent_label { let body = tcx .hir() .opt_local_def_id(obligation.cause.body_id) @@ -524,11 +524,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { hir_id: obligation.cause.body_id, }) }); - - let enclosing_scope_span = - tcx.hir().span(tcx.hir().local_def_id_to_hir_id(body)); - - err.span_label(enclosing_scope_span, s); + err.span_label(tcx.def_span(body), s); } self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index 3d8840e9e74..4a4f34b7680 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -22,7 +22,7 @@ pub struct OnUnimplementedDirective { pub message: Option, pub label: Option, pub note: Option, - pub enclosing_scope: Option, + pub parent_label: Option, pub append_const_msg: Option>, } @@ -31,7 +31,7 @@ pub struct OnUnimplementedNote { pub message: Option, pub label: Option, pub note: Option, - pub enclosing_scope: Option, + pub parent_label: Option, /// Append a message for `~const Trait` errors. `None` means not requested and /// should fallback to a generic message, `Some(None)` suggests using the default /// appended message, `Some(Some(s))` suggests use the `s` message instead of the @@ -74,7 +74,7 @@ impl<'tcx> OnUnimplementedDirective { let mut message = None; let mut label = None; let mut note = None; - let mut enclosing_scope = None; + let mut parent_label = None; let mut subcommands = vec![]; let mut append_const_msg = None; @@ -94,9 +94,9 @@ impl<'tcx> OnUnimplementedDirective { note = parse_value(note_)?; continue; } - } else if item.has_name(sym::enclosing_scope) && enclosing_scope.is_none() { - if let Some(enclosing_scope_) = item.value_str() { - enclosing_scope = parse_value(enclosing_scope_)?; + } else if item.has_name(sym::parent_label) && parent_label.is_none() { + if let Some(parent_label_) = item.value_str() { + parent_label = parse_value(parent_label_)?; continue; } } else if item.has_name(sym::on) @@ -135,7 +135,7 @@ impl<'tcx> OnUnimplementedDirective { message, label, note, - enclosing_scope, + parent_label, append_const_msg, }) } @@ -160,7 +160,7 @@ impl<'tcx> OnUnimplementedDirective { attr.span, )?), note: None, - enclosing_scope: None, + parent_label: None, append_const_msg: None, })) } else { @@ -181,7 +181,7 @@ impl<'tcx> OnUnimplementedDirective { let mut message = None; let mut label = None; let mut note = None; - let mut enclosing_scope = None; + let mut parent_label = None; let mut append_const_msg = None; info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); @@ -217,8 +217,8 @@ impl<'tcx> OnUnimplementedDirective { note = Some(note_.clone()); } - if let Some(ref enclosing_scope_) = command.enclosing_scope { - enclosing_scope = Some(enclosing_scope_.clone()); + if let Some(ref parent_label_) = command.parent_label { + parent_label = Some(parent_label_.clone()); } append_const_msg = command.append_const_msg; @@ -228,7 +228,7 @@ impl<'tcx> OnUnimplementedDirective { label: label.map(|l| l.format(tcx, trait_ref, &options_map)), message: message.map(|m| m.format(tcx, trait_ref, &options_map)), note: note.map(|n| n.format(tcx, trait_ref, &options_map)), - enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options_map)), + parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)), append_const_msg, } } diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 02f7f62bfe2..10f04134409 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -222,7 +222,87 @@ pub trait Try: FromResidual { /// Every `Try` type needs to be recreatable from its own associated /// `Residual` type, but can also have additional `FromResidual` implementations /// to support interconversion with other `Try` types. -#[rustc_on_unimplemented( +#[cfg_attr(not(bootstrap), rustc_on_unimplemented( + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::result::Result", + R = "std::option::Option" + ), + message = "the `?` operator can only be used on `Result`s, not `Option`s, \ + in {ItemContext} that returns `Result`", + label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::result::Result", + ), + // There's a special error message in the trait selection code for + // `From` in `?`, so this is not shown for result-in-result errors, + // and thus it can be phrased more strongly than `ControlFlow`'s. + message = "the `?` operator can only be used on `Result`s \ + in {ItemContext} that returns `Result`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::option::Option", + R = "std::result::Result", + ), + message = "the `?` operator can only be used on `Option`s, not `Result`s, \ + in {ItemContext} that returns `Option`", + label = "use `.ok()?` if you want to discard the `{R}` error information", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::option::Option", + ), + // `Option`-in-`Option` always works, as there's only one possible + // residual, so this can also be phrased strongly. + message = "the `?` operator can only be used on `Option`s \ + in {ItemContext} that returns `Option`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::ops::ControlFlow", + R = "std::ops::ControlFlow", + ), + message = "the `?` operator in {ItemContext} that returns `ControlFlow` \ + can only be used on other `ControlFlow`s (with the same Break type)", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::ops::ControlFlow", + // `R` is not a `ControlFlow`, as that case was matched previously + ), + message = "the `?` operator can only be used on `ControlFlow`s \ + in {ItemContext} that returns `ControlFlow`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + ), + on( + all(from_desugaring = "QuestionMark"), + message = "the `?` operator can only be used in {ItemContext} \ + that returns `Result` or `Option` \ + (or another type that implements `{FromResidual}`)", + label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", + parent_label = "this function should return `Result` or `Option` to accept `?`" + ), +))] +#[cfg_attr(bootstrap, rustc_on_unimplemented( on( all( from_desugaring = "QuestionMark", @@ -301,7 +381,7 @@ pub trait Try: FromResidual { label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", enclosing_scope = "this function should return `Result` or `Option` to accept `?`" ), -)] +))] #[rustc_diagnostic_item = "FromResidual"] #[unstable(feature = "try_trait_v2", issue = "84277")] pub trait FromResidual::Residual> { diff --git a/src/test/ui/on-unimplemented/enclosing-scope.rs b/src/test/ui/on-unimplemented/enclosing-scope.rs deleted file mode 100644 index 881bff63f5f..00000000000 --- a/src/test/ui/on-unimplemented/enclosing-scope.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Test scope annotations from `enclosing_scope` parameter - -#![feature(rustc_attrs)] - -#[rustc_on_unimplemented(enclosing_scope="in this scope")] -trait Trait{} - -struct Foo; - -fn f(x: T) {} - -fn main() { - let x = || { - f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied - let y = || { - f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied - }; - }; - - { - { - f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied - } - } - - f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied -} diff --git a/src/test/ui/on-unimplemented/parent-label.rs b/src/test/ui/on-unimplemented/parent-label.rs new file mode 100644 index 00000000000..b65f6496831 --- /dev/null +++ b/src/test/ui/on-unimplemented/parent-label.rs @@ -0,0 +1,27 @@ +// Test scope annotations from `parent_label` parameter + +#![feature(rustc_attrs)] + +#[rustc_on_unimplemented(parent_label = "in this scope")] +trait Trait {} + +struct Foo; + +fn f(x: T) {} + +fn main() { + let x = || { + f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied + let y = || { + f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied + }; + }; + + { + { + f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied + } + } + + f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied +} diff --git a/src/test/ui/on-unimplemented/enclosing-scope.stderr b/src/test/ui/on-unimplemented/parent-label.stderr similarity index 67% rename from src/test/ui/on-unimplemented/enclosing-scope.stderr rename to src/test/ui/on-unimplemented/parent-label.stderr index 4fe2ecd1e38..8cd7412fd9d 100644 --- a/src/test/ui/on-unimplemented/enclosing-scope.stderr +++ b/src/test/ui/on-unimplemented/parent-label.stderr @@ -1,65 +1,65 @@ error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/enclosing-scope.rs:14:11 + --> $DIR/parent-label.rs:14:11 | LL | let x = || { | -- in this scope -LL | f(Foo{}); - | - ^^^^^ the trait `Trait` is not implemented for `Foo` +LL | f(Foo {}); + | - ^^^^^^ the trait `Trait` is not implemented for `Foo` | | | required by a bound introduced by this call | note: required by a bound in `f` - --> $DIR/enclosing-scope.rs:10:9 + --> $DIR/parent-label.rs:10:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/enclosing-scope.rs:16:15 + --> $DIR/parent-label.rs:16:15 | LL | let y = || { | -- in this scope -LL | f(Foo{}); - | - ^^^^^ the trait `Trait` is not implemented for `Foo` +LL | f(Foo {}); + | - ^^^^^^ the trait `Trait` is not implemented for `Foo` | | | required by a bound introduced by this call | note: required by a bound in `f` - --> $DIR/enclosing-scope.rs:10:9 + --> $DIR/parent-label.rs:10:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/enclosing-scope.rs:22:15 + --> $DIR/parent-label.rs:22:15 | LL | fn main() { | --------- in this scope ... -LL | f(Foo{}); - | - ^^^^^ the trait `Trait` is not implemented for `Foo` +LL | f(Foo {}); + | - ^^^^^^ the trait `Trait` is not implemented for `Foo` | | | required by a bound introduced by this call | note: required by a bound in `f` - --> $DIR/enclosing-scope.rs:10:9 + --> $DIR/parent-label.rs:10:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/enclosing-scope.rs:26:7 + --> $DIR/parent-label.rs:26:7 | LL | fn main() { | --------- in this scope ... -LL | f(Foo{}); - | - ^^^^^ the trait `Trait` is not implemented for `Foo` +LL | f(Foo {}); + | - ^^^^^^ the trait `Trait` is not implemented for `Foo` | | | required by a bound introduced by this call | note: required by a bound in `f` - --> $DIR/enclosing-scope.rs:10:9 + --> $DIR/parent-label.rs:10:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f`