From 4b2f1db6e464b74067557b1748e79cb11a2c5e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 29 Jan 2020 12:59:04 -0800 Subject: [PATCH] Tweak `Self: Sized` restriction diagnostic output --- src/librustc/traits/error_reporting/mod.rs | 19 ++++-- src/librustc/traits/object_safety.rs | 63 ++++++++++--------- ...ature-gate-object_safe_for_dispatch.stderr | 4 -- src/test/ui/issues/issue-20692.rs | 2 +- src/test/ui/issues/issue-20692.stderr | 15 ++--- .../kindck-inherited-copy-bound.curr.stderr | 9 ++- ...copy-bound.object_safe_for_dispatch.stderr | 4 +- .../object-safety-sized.curr.stderr | 2 - ...fety-sized.object_safe_for_dispatch.stderr | 1 - ...object-unsafe-trait-should-use-self.stderr | 2 - .../wf/wf-convert-unsafe-trait-obj-box.stderr | 3 - .../ui/wf/wf-convert-unsafe-trait-obj.stderr | 3 - .../ui/wf/wf-unsafe-trait-obj-match.stderr | 2 - 13 files changed, 68 insertions(+), 61 deletions(-) diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs index 28084c9d4ac4..f15fa779534e 100644 --- a/src/librustc/traits/error_reporting/mod.rs +++ b/src/librustc/traits/error_reporting/mod.rs @@ -1046,11 +1046,22 @@ pub fn report_object_safety_error( let mut reported_violations = FxHashSet::default(); for violation in violations { + if let ObjectSafetyViolation::SizedSelf(sp) = &violation { + if !sp.is_empty() { + // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations + // with a `Span`. + reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); + } + } if reported_violations.insert(violation.clone()) { - match violation.span() { - Some(span) => err.span_label(span, violation.error_msg()), - None => err.note(&violation.error_msg()), - }; + let spans = violation.spans(); + if spans.is_empty() { + err.note(&violation.error_msg()); + } else { + for span in spans { + err.span_label(span, violation.error_msg()); + } + } } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index bca0ecb1e79d..8ceefb0abf03 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -18,15 +18,16 @@ use rustc_hir::def_id::DefId; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; +use smallvec::SmallVec; use syntax::ast; use std::borrow::Cow; use std::iter::{self}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ObjectSafetyViolation { /// `Self: Sized` declared on the trait. - SizedSelf(Span), + SizedSelf(SmallVec<[Span; 1]>), /// Supertrait reference references `Self` an in illegal location /// (e.g., `trait Foo : Bar`). @@ -75,18 +76,18 @@ impl ObjectSafetyViolation { } } - pub fn span(&self) -> Option { + pub fn spans(&self) -> SmallVec<[Span; 1]> { // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so // diagnostics use a `note` instead of a `span_label`. - match *self { + match self { + ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), ObjectSafetyViolation::AssocConst(_, span) - | ObjectSafetyViolation::SizedSelf(span) | ObjectSafetyViolation::Method(_, _, span) - if span != DUMMY_SP => + if *span != DUMMY_SP => { - Some(span) + vec![*span].into() } - _ => None, + _ => vec![].into(), } } } @@ -189,10 +190,14 @@ fn object_safety_violations_for_trait( tcx.def_path_str(trait_def_id) ), ); - match violation.span() { - Some(span) => err.span_label(span, violation.error_msg()), - None => err.note(&violation.error_msg()), - }; + let spans = violation.spans(); + if spans.is_empty() { + err.note(&violation.error_msg()); + } else { + for span in spans { + err.span_label(span, violation.error_msg()); + } + } err.emit(); false } else { @@ -203,8 +208,9 @@ fn object_safety_violations_for_trait( // Check the trait itself. if trait_has_sized_self(tcx, trait_def_id) { - let span = get_sized_bound(tcx, trait_def_id); - violations.push(ObjectSafetyViolation::SizedSelf(span)); + // We don't want to include the requirement from `Sized` itself to be `Sized` in the list. + let spans = get_sized_bounds(tcx, trait_def_id); + violations.push(ObjectSafetyViolation::SizedSelf(spans)); } if predicates_reference_self(tcx, trait_def_id, false) { violations.push(ObjectSafetyViolation::SupertraitSelf); @@ -224,25 +230,26 @@ fn object_safety_violations_for_trait( violations } -fn get_sized_bound(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Span { +fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { tcx.hir() .get_if_local(trait_def_id) .and_then(|node| match node { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., bounds, _), .. }) => bounds - .iter() - .filter_map(|b| match b { - hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None) - if Some(trait_ref.trait_ref.trait_def_id()) - == tcx.lang_items().sized_trait() => - { - Some(trait_ref.span) - } - _ => None, - }) - .next(), + hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., bounds, _), .. }) => Some( + bounds + .iter() + .filter_map(|b| match b { + hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None) + if trait_has_sized_self(tcx, trait_ref.trait_ref.trait_def_id()) => + { + Some(trait_ref.span) + } + _ => None, + }) + .collect::>(), + ), _ => None, }) - .unwrap_or(DUMMY_SP) + .unwrap_or_else(SmallVec::new) } fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_only: bool) -> bool { diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr index de362e1cef0f..237c22d3bf09 100644 --- a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr +++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr @@ -6,8 +6,6 @@ LL | trait NonObjectSafe1: Sized {} ... LL | fn takes_non_object_safe_ref(obj: &dyn NonObjectSafe1) { | ^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe1` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error[E0038]: the trait `NonObjectSafe2` cannot be made into an object --> $DIR/feature-gate-object_safe_for_dispatch.rs:22:36 @@ -44,8 +42,6 @@ LL | trait NonObjectSafe1: Sized {} ... LL | impl Trait for dyn NonObjectSafe1 {} | ^^^^^ the trait `NonObjectSafe1` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error: aborting due to 5 previous errors diff --git a/src/test/ui/issues/issue-20692.rs b/src/test/ui/issues/issue-20692.rs index 2a05bba7b163..1cb2d8c7302a 100644 --- a/src/test/ui/issues/issue-20692.rs +++ b/src/test/ui/issues/issue-20692.rs @@ -1,4 +1,4 @@ -trait Array: Sized {} +trait Array: Sized + Copy {} fn f(x: &T) { let _ = x diff --git a/src/test/ui/issues/issue-20692.stderr b/src/test/ui/issues/issue-20692.stderr index 4757742a707b..62efdfb2e91b 100644 --- a/src/test/ui/issues/issue-20692.stderr +++ b/src/test/ui/issues/issue-20692.stderr @@ -1,24 +1,25 @@ error[E0038]: the trait `Array` cannot be made into an object --> $DIR/issue-20692.rs:7:5 | -LL | trait Array: Sized {} - | ----- the trait cannot require that `Self : Sized` +LL | trait Array: Sized + Copy {} + | ----- ---- the trait cannot require that `Self : Sized` + | | + | the trait cannot require that `Self : Sized` ... LL | &dyn Array; | ^^^^^^^^^^ the trait `Array` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error[E0038]: the trait `Array` cannot be made into an object --> $DIR/issue-20692.rs:4:13 | -LL | trait Array: Sized {} - | ----- the trait cannot require that `Self : Sized` +LL | trait Array: Sized + Copy {} + | ----- ---- the trait cannot require that `Self : Sized` + | | + | the trait cannot require that `Self : Sized` ... LL | let _ = x | ^ the trait `Array` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Array>` for `&T` = note: required by cast to type `&dyn Array` diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr index da1a7a7520e0..a0ecca3020e1 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -12,18 +12,21 @@ LL | take_param(&x); error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:28:19 | +LL | trait Foo : Copy { + | ---- the trait cannot require that `Self : Sized` +... LL | let z = &x as &dyn Foo; | ^^^^^^^^ the trait `Foo` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:28:13 | +LL | trait Foo : Copy { + | ---- the trait cannot require that `Self : Sized` +... LL | let z = &x as &dyn Foo; | ^^ the trait `Foo` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box<{integer}>` = note: required by cast to type `&dyn Foo` diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr index f272f829ba60..5694150ed7cc 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr @@ -12,10 +12,12 @@ LL | take_param(&x); error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:28:13 | +LL | trait Foo : Copy { + | ---- the trait cannot require that `Self : Sized` +... LL | let z = &x as &dyn Foo; | ^^ the trait `Foo` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box` = note: required by cast to type `&dyn Foo` diff --git a/src/test/ui/object-safety/object-safety-sized.curr.stderr b/src/test/ui/object-safety/object-safety-sized.curr.stderr index be0a2519a469..473c8f8e6faa 100644 --- a/src/test/ui/object-safety/object-safety-sized.curr.stderr +++ b/src/test/ui/object-safety/object-safety-sized.curr.stderr @@ -6,8 +6,6 @@ LL | trait Bar : Sized { ... LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^^ the trait `Bar` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error: aborting due to previous error diff --git a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr index c20ddee54c07..217e2aa00da1 100644 --- a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr @@ -7,7 +7,6 @@ LL | trait Bar : Sized { LL | t | ^ the trait `Bar` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` diff --git a/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr b/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr index f1c1a6bb9728..91fa144032fc 100644 --- a/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr +++ b/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr @@ -18,8 +18,6 @@ LL | trait A: Sized { | ----- the trait cannot require that `Self : Sized` LL | fn f(a: A) -> A; | ^ the trait `A` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error: associated item referring to unboxed trait object for its own trait --> $DIR/object-unsafe-trait-should-use-self.rs:8:13 diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr index 4c033cfcd898..461ad97f2f0a 100644 --- a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr @@ -7,7 +7,6 @@ LL | trait Trait: Sized {} LL | let t_box: Box = Box::new(S); | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` = note: required by cast to type `std::boxed::Box` @@ -20,7 +19,6 @@ LL | trait Trait: Sized {} LL | takes_box(Box::new(S)); | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` = note: required by cast to type `std::boxed::Box<(dyn Trait + 'static)>` @@ -33,7 +31,6 @@ LL | trait Trait: Sized {} LL | Box::new(S) as Box; | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` = note: required by cast to type `std::boxed::Box` diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr index ba3792c362e8..6fc57369b4e7 100644 --- a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr @@ -7,7 +7,6 @@ LL | trait Trait: Sized {} LL | let t: &dyn Trait = &S; | ^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` @@ -20,7 +19,6 @@ LL | trait Trait: Sized {} LL | takes_trait(&S); | ^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` @@ -33,7 +31,6 @@ LL | trait Trait: Sized {} LL | &S as &dyn Trait; | ^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr index a0082578d4d0..36c60aefa6bb 100644 --- a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -21,7 +21,6 @@ LL | trait Trait: Sized {} LL | Some(()) => &S, | ^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` @@ -34,7 +33,6 @@ LL | trait Trait: Sized {} LL | let t: &dyn Trait = match opt() { | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&R` = note: required by cast to type `&dyn Trait`