Skip to content

Commit 865216b

Browse files
committed
Point at reason in object unsafe trait with Self in supertraits or where-clause
1 parent 16d935e commit 865216b

8 files changed

+78
-30
lines changed

src/librustc/traits/object_safety.rs

+38-16
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub enum ObjectSafetyViolation {
3232

3333
/// Supertrait reference references `Self` an in illegal location
3434
/// (e.g., `trait Foo : Bar<Self>`).
35-
SupertraitSelf,
35+
SupertraitSelf(SmallVec<[Span; 1]>),
3636

3737
/// Method has something illegal.
3838
Method(ast::Name, MethodViolationCode, Span),
@@ -45,9 +45,13 @@ impl ObjectSafetyViolation {
4545
pub fn error_msg(&self) -> Cow<'static, str> {
4646
match *self {
4747
ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(),
48-
ObjectSafetyViolation::SupertraitSelf => {
49-
"it cannot use `Self` as a type parameter in the supertraits or `where`-clauses"
50-
.into()
48+
ObjectSafetyViolation::SupertraitSelf(ref spans) => {
49+
if spans.iter().any(|sp| *sp != DUMMY_SP) {
50+
"it uses `Self` as a type parameter in this".into()
51+
} else {
52+
"it cannot use `Self` as a type parameter in a supertrait or `where`-clause"
53+
.into()
54+
}
5155
}
5256
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
5357
format!("associated function `{}` has no `self` parameter", name).into()
@@ -87,7 +91,7 @@ impl ObjectSafetyViolation {
8791

8892
pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> {
8993
Some(match *self {
90-
ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf => {
94+
ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {
9195
return None;
9296
}
9397
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(sugg), _) => (
@@ -118,7 +122,8 @@ impl ObjectSafetyViolation {
118122
// When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so
119123
// diagnostics use a `note` instead of a `span_label`.
120124
match self {
121-
ObjectSafetyViolation::SizedSelf(spans) => spans.clone(),
125+
ObjectSafetyViolation::SupertraitSelf(spans)
126+
| ObjectSafetyViolation::SizedSelf(spans) => spans.clone(),
122127
ObjectSafetyViolation::AssocConst(_, span)
123128
| ObjectSafetyViolation::Method(_, _, span)
124129
if *span != DUMMY_SP =>
@@ -162,8 +167,9 @@ pub fn astconv_object_safety_violations(
162167
) -> Vec<ObjectSafetyViolation> {
163168
debug_assert!(tcx.generics_of(trait_def_id).has_self);
164169
let violations = traits::supertrait_def_ids(tcx, trait_def_id)
165-
.filter(|&def_id| predicates_reference_self(tcx, def_id, true))
166-
.map(|_| ObjectSafetyViolation::SupertraitSelf)
170+
.map(|def_id| predicates_reference_self(tcx, def_id, true))
171+
.filter(|spans| !spans.is_empty())
172+
.map(|spans| ObjectSafetyViolation::SupertraitSelf(spans))
167173
.collect();
168174

169175
debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations);
@@ -266,8 +272,9 @@ fn object_safety_violations_for_trait(
266272
let spans = get_sized_bounds(tcx, trait_def_id);
267273
violations.push(ObjectSafetyViolation::SizedSelf(spans));
268274
}
269-
if predicates_reference_self(tcx, trait_def_id, false) {
270-
violations.push(ObjectSafetyViolation::SupertraitSelf);
275+
let spans = predicates_reference_self(tcx, trait_def_id, false);
276+
if !spans.is_empty() {
277+
violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
271278
}
272279

273280
violations.extend(
@@ -337,7 +344,11 @@ fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]>
337344
.unwrap_or_else(SmallVec::new)
338345
}
339346

340-
fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_only: bool) -> bool {
347+
fn predicates_reference_self(
348+
tcx: TyCtxt<'_>,
349+
trait_def_id: DefId,
350+
supertraits_only: bool,
351+
) -> SmallVec<[Span; 1]> {
341352
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
342353
let predicates = if supertraits_only {
343354
tcx.super_predicates_of(trait_def_id)
@@ -349,12 +360,16 @@ fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_o
349360
predicates
350361
.predicates
351362
.iter()
352-
.map(|(predicate, _)| predicate.subst_supertrait(tcx, &trait_ref))
353-
.any(|predicate| {
363+
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
364+
.filter_map(|(predicate, &sp)| {
354365
match predicate {
355366
ty::Predicate::Trait(ref data, _) => {
356367
// In the case of a trait predicate, we can skip the "self" type.
357-
data.skip_binder().input_types().skip(1).any(has_self_ty)
368+
if data.skip_binder().input_types().skip(1).any(has_self_ty) {
369+
Some(sp)
370+
} else {
371+
None
372+
}
358373
}
359374
ty::Predicate::Projection(ref data) => {
360375
// And similarly for projections. This should be redundant with
@@ -369,22 +384,29 @@ fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_o
369384
//
370385
// This is ALT2 in issue #56288, see that for discussion of the
371386
// possible alternatives.
372-
data.skip_binder()
387+
if data
388+
.skip_binder()
373389
.projection_ty
374390
.trait_ref(tcx)
375391
.input_types()
376392
.skip(1)
377393
.any(has_self_ty)
394+
{
395+
Some(sp)
396+
} else {
397+
None
398+
}
378399
}
379400
ty::Predicate::WellFormed(..)
380401
| ty::Predicate::ObjectSafe(..)
381402
| ty::Predicate::TypeOutlives(..)
382403
| ty::Predicate::RegionOutlives(..)
383404
| ty::Predicate::ClosureKind(..)
384405
| ty::Predicate::Subtype(..)
385-
| ty::Predicate::ConstEvaluatable(..) => false,
406+
| ty::Predicate::ConstEvaluatable(..) => None,
386407
}
387408
})
409+
.collect()
388410
}
389411

390412
fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {

src/test/ui/issues/issue-26056.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
error[E0038]: the trait `Map` cannot be made into an object
22
--> $DIR/issue-26056.rs:20:13
33
|
4+
LL | trait Map: MapLookup<<Self as Map>::Key> {
5+
| --- ----------------------------- ...because it uses `Self` as a type parameter in this
6+
| |
7+
| this trait cannot be made into an object...
8+
...
49
LL | as &dyn Map<Key=u32,MapValue=u32>;
510
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Map` cannot be made into an object
6-
|
7-
= note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses
811

912
error: aborting due to previous error
1013

src/test/ui/issues/issue-28576.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
error[E0038]: the trait `Bar` cannot be made into an object
22
--> $DIR/issue-28576.rs:7:12
33
|
4+
LL | pub trait Bar: Foo<Assoc=()> {
5+
| --- -------------
6+
| | | |
7+
| | | ...because it uses `Self` as a type parameter in this
8+
| | ...because it uses `Self` as a type parameter in this
9+
| this trait cannot be made into an object...
10+
LL | fn new(&self, b: &
411
LL | / dyn Bar
512
LL | | <Assoc=()>
613
| |________________________^ the trait `Bar` cannot be made into an object
7-
|
8-
= note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses
914

1015
error: aborting due to previous error
1116

src/test/ui/issues/issue-38404.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
error[E0038]: the trait `B` cannot be made into an object
22
--> $DIR/issue-38404.rs:3:15
33
|
4+
LL | trait A<T>: std::ops::Add<Self> + Sized {}
5+
| ------------------- ...because it uses `Self` as a type parameter in this
6+
LL | trait B<T>: A<T> {}
7+
| - this trait cannot be made into an object...
48
LL | trait C<T>: A<dyn B<T, Output=usize>> {}
59
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `B` cannot be made into an object
6-
|
7-
= note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses
810

911
error: aborting due to previous error
1012

src/test/ui/issues/issue-38604.stderr

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
error[E0038]: the trait `Foo` cannot be made into an object
22
--> $DIR/issue-38604.rs:14:13
33
|
4+
LL | trait Foo where u32: Q<Self> {
5+
| --- ------- ...because it uses `Self` as a type parameter in this
6+
| |
7+
| this trait cannot be made into an object...
8+
...
49
LL | let _f: Box<dyn Foo> =
510
| ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
6-
|
7-
= note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses
811

912
error[E0038]: the trait `Foo` cannot be made into an object
1013
--> $DIR/issue-38604.rs:15:9
1114
|
15+
LL | trait Foo where u32: Q<Self> {
16+
| --- ------- ...because it uses `Self` as a type parameter in this
17+
| |
18+
| this trait cannot be made into an object...
19+
...
1220
LL | Box::new(());
1321
| ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
1422
|
15-
= note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses
1623
= note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<()>`
1724
= note: required by cast to type `std::boxed::Box<dyn Foo>`
1825

src/test/ui/object-safety/object-safety-issue-22040.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
error[E0038]: the trait `Expr` cannot be made into an object
22
--> $DIR/object-safety-issue-22040.rs:12:23
33
|
4+
LL | trait Expr: Debug + PartialEq {
5+
| ---- --------- ...because it uses `Self` as a type parameter in this
6+
| |
7+
| this trait cannot be made into an object...
8+
...
49
LL | elements: Vec<Box<dyn Expr + 'x>>,
510
| ^^^^^^^^^^^^^ the trait `Expr` cannot be made into an object
6-
|
7-
= note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses
811

912
error: aborting due to previous error
1013

src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
error[E0038]: the trait `Baz` cannot be made into an object
22
--> $DIR/object-safety-supertrait-mentions-Self.rs:15:31
33
|
4+
LL | trait Baz : Bar<Self> {
5+
| --- --------- ...because it uses `Self` as a type parameter in this
6+
| |
7+
| this trait cannot be made into an object...
8+
...
49
LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
510
| ^^^^^^^ the trait `Baz` cannot be made into an object
6-
|
7-
= note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses
811

912
error: aborting due to previous error
1013

src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ error[E0038]: the trait `std::cmp::Eq` cannot be made into an object
33
|
44
LL | let _: &dyn EqAlias = &123;
55
| ^^^^^^^^^^^ the trait `std::cmp::Eq` cannot be made into an object
6+
|
7+
::: $SRC_DIR/libcore/cmp.rs:LL:COL
68
|
7-
= note: the trait cannot be made into an object because it cannot use `Self` as a type parameter in the supertraits or `where`-clauses
9+
LL | pub trait Eq: PartialEq<Self> {
10+
| --------------- the trait cannot be made into an object because it uses `Self` as a type parameter in this
811

912
error[E0191]: the value of the associated type `Item` (from trait `std::iter::Iterator`) must be specified
1013
--> $DIR/trait-alias-object-fail.rs:9:17

0 commit comments

Comments
 (0)