Tweak Self: Sized restriction diagnostic output

This commit is contained in:
Esteban Küber 2020-01-29 12:59:04 -08:00
parent d137b7ac11
commit 4b2f1db6e4
13 changed files with 68 additions and 61 deletions

View File

@ -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());
}
}
}
}

View File

@ -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<Self>`).
@ -75,18 +76,18 @@ impl ObjectSafetyViolation {
}
}
pub fn span(&self) -> Option<Span> {
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::<SmallVec<[Span; 1]>>(),
),
_ => None,
})
.unwrap_or(DUMMY_SP)
.unwrap_or_else(SmallVec::new)
}
fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_only: bool) -> bool {

View File

@ -6,8 +6,6 @@ LL | trait NonObjectSafe1: Sized {}
...
LL | fn takes_non_object_safe_ref<T>(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

View File

@ -1,4 +1,4 @@
trait Array: Sized {}
trait Array: Sized + Copy {}
fn f<T: Array>(x: &T) {
let _ = x

View File

@ -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`

View File

@ -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`

View File

@ -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<i32>`
= note: required by cast to type `&dyn Foo`

View File

@ -6,8 +6,6 @@ LL | trait Bar : Sized {
...
LL | fn make_bar<T: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

View File

@ -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`

View File

@ -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

View File

@ -7,7 +7,6 @@ LL | trait Trait: Sized {}
LL | let t_box: Box<dyn Trait> = 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<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>`
= note: required by cast to type `std::boxed::Box<dyn Trait>`
@ -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<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>`
= 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<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<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>`
= note: required by cast to type `std::boxed::Box<dyn Trait>`

View File

@ -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`

View File

@ -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`