From 865216b3ad4158e31d583f5f3cae12afe91c52d0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Esteban=20K=C3=BCber?= Date: Sun, 2 Feb 2020 12:51:30 -0800 Subject: [PATCH] Point at reason in object unsafe trait with `Self` in supertraits or `where`-clause --- src/librustc/traits/object_safety.rs | 54 +++++++++++++------ src/test/ui/issues/issue-26056.stderr | 7 ++- src/test/ui/issues/issue-28576.stderr | 9 +++- src/test/ui/issues/issue-38404.stderr | 6 ++- src/test/ui/issues/issue-38604.stderr | 13 +++-- .../object-safety-issue-22040.stderr | 7 ++- ...ect-safety-supertrait-mentions-Self.stderr | 7 ++- .../trait-alias-object-fail.stderr | 5 +- 8 files changed, 78 insertions(+), 30 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index efb46a1b8d3..2745d3205de 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -32,7 +32,7 @@ pub enum ObjectSafetyViolation { /// Supertrait reference references `Self` an in illegal location /// (e.g., `trait Foo : Bar`). - SupertraitSelf, + SupertraitSelf(SmallVec<[Span; 1]>), /// Method has something illegal. Method(ast::Name, MethodViolationCode, Span), @@ -45,9 +45,13 @@ impl ObjectSafetyViolation { pub fn error_msg(&self) -> Cow<'static, str> { match *self { ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), - ObjectSafetyViolation::SupertraitSelf => { - "it cannot use `Self` as a type parameter in the supertraits or `where`-clauses" - .into() + ObjectSafetyViolation::SupertraitSelf(ref spans) => { + if spans.iter().any(|sp| *sp != DUMMY_SP) { + "it uses `Self` as a type parameter in this".into() + } else { + "it cannot use `Self` as a type parameter in a supertrait or `where`-clause" + .into() + } } ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { format!("associated function `{}` has no `self` parameter", name).into() @@ -87,7 +91,7 @@ pub fn error_msg(&self) -> Cow<'static, str> { pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> { Some(match *self { - ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf => { + ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => { return None; } ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(sugg), _) => ( @@ -118,7 +122,8 @@ pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> { // 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 { - ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), + ObjectSafetyViolation::SupertraitSelf(spans) + | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), ObjectSafetyViolation::AssocConst(_, span) | ObjectSafetyViolation::Method(_, _, span) if *span != DUMMY_SP => @@ -162,8 +167,9 @@ pub fn astconv_object_safety_violations( ) -> Vec { debug_assert!(tcx.generics_of(trait_def_id).has_self); let violations = traits::supertrait_def_ids(tcx, trait_def_id) - .filter(|&def_id| predicates_reference_self(tcx, def_id, true)) - .map(|_| ObjectSafetyViolation::SupertraitSelf) + .map(|def_id| predicates_reference_self(tcx, def_id, true)) + .filter(|spans| !spans.is_empty()) + .map(|spans| ObjectSafetyViolation::SupertraitSelf(spans)) .collect(); debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations); @@ -266,8 +272,9 @@ fn object_safety_violations_for_trait( 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); + let spans = predicates_reference_self(tcx, trait_def_id, false); + if !spans.is_empty() { + violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); } violations.extend( @@ -337,7 +344,11 @@ fn object_safety_violations_for_trait( .unwrap_or_else(SmallVec::new) } -fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_only: bool) -> bool { +fn predicates_reference_self( + tcx: TyCtxt<'_>, + trait_def_id: DefId, + supertraits_only: bool, +) -> SmallVec<[Span; 1]> { let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); let predicates = if supertraits_only { tcx.super_predicates_of(trait_def_id) @@ -349,12 +360,16 @@ fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_o predicates .predicates .iter() - .map(|(predicate, _)| predicate.subst_supertrait(tcx, &trait_ref)) - .any(|predicate| { + .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) + .filter_map(|(predicate, &sp)| { match predicate { ty::Predicate::Trait(ref data, _) => { // In the case of a trait predicate, we can skip the "self" type. - data.skip_binder().input_types().skip(1).any(has_self_ty) + if data.skip_binder().input_types().skip(1).any(has_self_ty) { + Some(sp) + } else { + None + } } ty::Predicate::Projection(ref data) => { // And similarly for projections. This should be redundant with @@ -369,12 +384,18 @@ fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_o // // This is ALT2 in issue #56288, see that for discussion of the // possible alternatives. - data.skip_binder() + if data + .skip_binder() .projection_ty .trait_ref(tcx) .input_types() .skip(1) .any(has_self_ty) + { + Some(sp) + } else { + None + } } ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) @@ -382,9 +403,10 @@ fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_o | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => false, + | ty::Predicate::ConstEvaluatable(..) => None, } }) + .collect() } fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { diff --git a/src/test/ui/issues/issue-26056.stderr b/src/test/ui/issues/issue-26056.stderr index 2744fb91d6f..be438ef9ac7 100644 --- a/src/test/ui/issues/issue-26056.stderr +++ b/src/test/ui/issues/issue-26056.stderr @@ -1,10 +1,13 @@ error[E0038]: the trait `Map` cannot be made into an object --> $DIR/issue-26056.rs:20:13 | +LL | trait Map: MapLookup<::Key> { + | --- ----------------------------- ...because it uses `Self` as a type parameter in this + | | + | this trait cannot be made into an object... +... LL | as &dyn Map; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Map` cannot be made into an object - | - = note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses error: aborting due to previous error diff --git a/src/test/ui/issues/issue-28576.stderr b/src/test/ui/issues/issue-28576.stderr index 5bed9a77d18..658199003c1 100644 --- a/src/test/ui/issues/issue-28576.stderr +++ b/src/test/ui/issues/issue-28576.stderr @@ -1,11 +1,16 @@ error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/issue-28576.rs:7:12 | +LL | pub trait Bar: Foo { + | --- ------------- + | | | | + | | | ...because it uses `Self` as a type parameter in this + | | ...because it uses `Self` as a type parameter in this + | this trait cannot be made into an object... +LL | fn new(&self, b: & LL | / dyn Bar LL | | | |________________________^ the trait `Bar` cannot be made into an object - | - = note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses error: aborting due to previous error diff --git a/src/test/ui/issues/issue-38404.stderr b/src/test/ui/issues/issue-38404.stderr index 613888758ca..50c5195dc93 100644 --- a/src/test/ui/issues/issue-38404.stderr +++ b/src/test/ui/issues/issue-38404.stderr @@ -1,10 +1,12 @@ error[E0038]: the trait `B` cannot be made into an object --> $DIR/issue-38404.rs:3:15 | +LL | trait A: std::ops::Add + Sized {} + | ------------------- ...because it uses `Self` as a type parameter in this +LL | trait B: A {} + | - this trait cannot be made into an object... LL | trait C: A> {} | ^^^^^^^^^^^^^^^^^^^^^^ the trait `B` cannot be made into an object - | - = note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses error: aborting due to previous error diff --git a/src/test/ui/issues/issue-38604.stderr b/src/test/ui/issues/issue-38604.stderr index b3ad71e174a..2bba50e1f41 100644 --- a/src/test/ui/issues/issue-38604.stderr +++ b/src/test/ui/issues/issue-38604.stderr @@ -1,18 +1,25 @@ error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/issue-38604.rs:14:13 | +LL | trait Foo where u32: Q { + | --- ------- ...because it uses `Self` as a type parameter in this + | | + | this trait cannot be made into an object... +... LL | let _f: Box = | ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object - | - = note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/issue-38604.rs:15:9 | +LL | trait Foo where u32: Q { + | --- ------- ...because it uses `Self` as a type parameter in this + | | + | this trait cannot be made into an object... +... LL | Box::new(()); | ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses = 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/object-safety/object-safety-issue-22040.stderr b/src/test/ui/object-safety/object-safety-issue-22040.stderr index 55baf69401b..fe9ca5b6fa4 100644 --- a/src/test/ui/object-safety/object-safety-issue-22040.stderr +++ b/src/test/ui/object-safety/object-safety-issue-22040.stderr @@ -1,10 +1,13 @@ error[E0038]: the trait `Expr` cannot be made into an object --> $DIR/object-safety-issue-22040.rs:12:23 | +LL | trait Expr: Debug + PartialEq { + | ---- --------- ...because it uses `Self` as a type parameter in this + | | + | this trait cannot be made into an object... +... LL | elements: Vec>, | ^^^^^^^^^^^^^ the trait `Expr` cannot be made into an object - | - = note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses error: aborting due to previous error diff --git a/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr b/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr index 04f630d5dac..ef7f6bacd12 100644 --- a/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr +++ b/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr @@ -1,10 +1,13 @@ error[E0038]: the trait `Baz` cannot be made into an object --> $DIR/object-safety-supertrait-mentions-Self.rs:15:31 | +LL | trait Baz : Bar { + | --- --------- ...because it uses `Self` as a type parameter in this + | | + | this trait cannot be made into an object... +... LL | fn make_baz(t: &T) -> &dyn Baz { | ^^^^^^^ the trait `Baz` cannot be made into an object - | - = note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses error: aborting due to previous error diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr index 1f9ffb6a4cf..56ecb7256f8 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr @@ -3,8 +3,11 @@ error[E0038]: the trait `std::cmp::Eq` cannot be made into an object | LL | let _: &dyn EqAlias = &123; | ^^^^^^^^^^^ the trait `std::cmp::Eq` cannot be made into an object + | + ::: $SRC_DIR/libcore/cmp.rs:LL:COL | - = note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses +LL | pub trait Eq: PartialEq { + | --------------- the trait cannot be made into an object because it uses `Self` as a type parameter in this error[E0191]: the value of the associated type `Item` (from trait `std::iter::Iterator`) must be specified --> $DIR/trait-alias-object-fail.rs:9:17 -- 2.44.0