]> git.lizzy.rs Git - rust.git/commitdiff
Point at reason in object unsafe trait with `Self` in supertraits or `where`-clause
authorEsteban Küber <esteban@kuber.com.ar>
Sun, 2 Feb 2020 20:51:30 +0000 (12:51 -0800)
committerEsteban Küber <esteban@kuber.com.ar>
Sun, 2 Feb 2020 21:45:41 +0000 (13:45 -0800)
src/librustc/traits/object_safety.rs
src/test/ui/issues/issue-26056.stderr
src/test/ui/issues/issue-28576.stderr
src/test/ui/issues/issue-38404.stderr
src/test/ui/issues/issue-38604.stderr
src/test/ui/object-safety/object-safety-issue-22040.stderr
src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr
src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr

index efb46a1b8d3eebfdbabb5d9e80f3e51b043c0237..2745d3205dec0b1787ee8efcab770ad4f5e50f29 100644 (file)
@@ -32,7 +32,7 @@ pub enum ObjectSafetyViolation {
 
     /// Supertrait reference references `Self` an in illegal location
     /// (e.g., `trait Foo : Bar<Self>`).
-    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<ObjectSafetyViolation> {
     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 {
index 2744fb91d6fe1c4278c2a18ef180ad3d65f2a064..be438ef9ac7bacb0f03f1a5e9666da7facb9da6e 100644 (file)
@@ -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<<Self as Map>::Key> {
+   |       ---  ----------------------------- ...because it uses `Self` as a type parameter in this
+   |       |
+   |       this trait cannot be made into an object...
+...
 LL |         as &dyn Map<Key=u32,MapValue=u32>;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
 
index 5bed9a77d1891adf10441307b4bdfad88194d471..658199003c18d472a0cf20c5976207a355902069 100644 (file)
@@ -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<Assoc=()> {
+   |             ---  -------------
+   |             |    |   |
+   |             |    |   ...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 | |               <Assoc=()>
    | |________________________^ 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
 
index 613888758cab44dd61bf6982782c2b6d0e0de05f..50c5195dc93b08613db2acfb63653706f5b878c2 100644 (file)
@@ -1,10 +1,12 @@
 error[E0038]: the trait `B` cannot be made into an object
   --> $DIR/issue-38404.rs:3:15
    |
+LL | trait A<T>: std::ops::Add<Self> + Sized {}
+   |             ------------------- ...because it uses `Self` as a type parameter in this
+LL | trait B<T>: A<T> {}
+   |       - this trait cannot be made into an object...
 LL | trait C<T>: A<dyn B<T, Output=usize>> {}
    |               ^^^^^^^^^^^^^^^^^^^^^^ 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
 
index b3ad71e174a977ad2b3b1a049562b3cd6ca54533..2bba50e1f41c8c90ca9e2c2252e263863ab17121 100644 (file)
@@ -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<Self> {
+   |       ---            ------- ...because it uses `Self` as a type parameter in this
+   |       |
+   |       this trait cannot be made into an object...
+...
 LL |     let _f: Box<dyn Foo> =
    |             ^^^^^^^^^^^^ 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<Self> {
+   |       ---            ------- ...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<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<()>`
    = note: required by cast to type `std::boxed::Box<dyn Foo>`
 
index 55baf69401b0aa9d96c756ee3d5fbb8fc80d0b93..fe9ca5b6fa4b7d2076c6e73b4e082e62f3d72155 100644 (file)
@@ -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<Box<dyn Expr + 'x>>,
    |                       ^^^^^^^^^^^^^ 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
 
index 04f630d5dacb73f653bef5b16116ebdcca0e8fb3..ef7f6bacd1233793eecaa510d0821bf2e2e6302e 100644 (file)
@@ -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<Self> {
+   |       ---   --------- ...because it uses `Self` as a type parameter in this
+   |       |
+   |       this trait cannot be made into an object...
+...
 LL | fn make_baz<T: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
 
index 1f9ffb6a4cfbf0b69cc61f432ed95bb7e096a075..56ecb7256f8cde343effcbf6909f2b09a901f338 100644 (file)
@@ -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<Self> {
+   |               --------------- 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