Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make traits with GATs not object safe #84622

Merged
merged 1 commit into from
Apr 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,9 @@ pub enum ObjectSafetyViolation {

/// Associated const.
AssocConst(Symbol, Span),

/// GAT
GAT(Symbol, Span),
}

impl ObjectSafetyViolation {
Expand Down Expand Up @@ -715,6 +718,9 @@ impl ObjectSafetyViolation {
format!("it contains associated `const` `{}`", name).into()
}
ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(),
ObjectSafetyViolation::GAT(name, _) => {
format!("it contains the generic associated type `{}`", name).into()
}
}
}

Expand Down Expand Up @@ -773,6 +779,7 @@ impl ObjectSafetyViolation {
);
}
ObjectSafetyViolation::AssocConst(name, _)
| ObjectSafetyViolation::GAT(name, _)
| ObjectSafetyViolation::Method(name, ..) => {
err.help(&format!("consider moving `{}` to another trait", name));
}
Expand All @@ -786,6 +793,7 @@ impl ObjectSafetyViolation {
ObjectSafetyViolation::SupertraitSelf(spans)
| ObjectSafetyViolation::SizedSelf(spans) => spans.clone(),
ObjectSafetyViolation::AssocConst(_, span)
| ObjectSafetyViolation::GAT(_, span)
| ObjectSafetyViolation::Method(_, _, span)
if *span != DUMMY_SP =>
{
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_trait_selection/src/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ fn object_safety_violations_for_trait(
.map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)),
);

violations.extend(
tcx.associated_items(trait_def_id)
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
.map(|item| ObjectSafetyViolation::GAT(item.ident.name, item.ident.span)),
);

debug!(
"object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
trait_def_id, violations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,12 +462,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

for assoc_type in assoc_types {
if !tcx.generics_of(assoc_type).params.is_empty() {
// FIXME(generic_associated_types) generate placeholders to
// extend the trait substs.
tcx.sess.span_fatal(
tcx.sess.delay_span_bug(
obligation.cause.span,
"generic associated types in trait objects are not supported yet",
"GATs in trait object shouldn't have been considered",
);
return Err(SelectionError::Unimplemented);
}
// This maybe belongs in wf, but that can't (doesn't) handle
// higher-ranked things.
Expand Down
3 changes: 1 addition & 2 deletions src/test/ui/generic-associated-types/gat-in-trait-path.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// check-pass

#![feature(generic_associated_types)]
//~^ WARNING: the feature `generic_associated_types` is incomplete
#![feature(associated_type_defaults)]
Expand All @@ -22,6 +20,7 @@ impl<T> Foo for Fooer<T> {
}

fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
//~^ the trait `Foo` cannot be made into an object


fn main() {
Expand Down
20 changes: 18 additions & 2 deletions src/test/ui/generic-associated-types/gat-in-trait-path.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/gat-in-trait-path.rs:3:12
--> $DIR/gat-in-trait-path.rs:1:12
|
LL | #![feature(generic_associated_types)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information

warning: 1 warning emitted
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/gat-in-trait-path.rs:22:13
|
LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
|
= help: consider moving `A` to another trait
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/gat-in-trait-path.rs:6:10
|
LL | trait Foo {
| --- this trait cannot be made into an object...
LL | type A<'a> where Self: 'a;
| ^ ...because it contains the generic associated type `A`

error: aborting due to previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0038`.
3 changes: 1 addition & 2 deletions src/test/ui/generic-associated-types/issue-67510-pass.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// check-pass

#![feature(generic_associated_types)]
//~^ WARNING: the feature `generic_associated_types` is incomplete

Expand All @@ -8,5 +6,6 @@ trait X {
}

fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
//~^ ERROR the trait `X` cannot be made into an object

fn main() {}
20 changes: 18 additions & 2 deletions src/test/ui/generic-associated-types/issue-67510-pass.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/issue-67510-pass.rs:3:12
--> $DIR/issue-67510-pass.rs:1:12
|
LL | #![feature(generic_associated_types)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information

warning: 1 warning emitted
error[E0038]: the trait `X` cannot be made into an object
--> $DIR/issue-67510-pass.rs:8:19
|
LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
|
= help: consider moving `Y` to another trait
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/issue-67510-pass.rs:5:10
|
LL | trait X {
| - this trait cannot be made into an object...
LL | type Y<'a>;
| ^ ...because it contains the generic associated type `Y`

error: aborting due to previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0038`.
2 changes: 2 additions & 0 deletions src/test/ui/generic-associated-types/issue-76535.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ impl SuperTrait for SuperStruct {

fn main() {
let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
//~^ ERROR the trait `SuperTrait` cannot be made into an object
//~^^ ERROR the trait `SuperTrait` cannot be made into an object
}
37 changes: 35 additions & 2 deletions src/test/ui/generic-associated-types/issue-76535.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,39 @@ help: use angle brackets to add missing lifetime argument
LL | type SubType<'a><'a>: SubTrait;
| ^^^^

error: aborting due to previous error; 1 warning emitted
error[E0038]: the trait `SuperTrait` cannot be made into an object
--> $DIR/issue-76535.rs:38:14
|
LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
|
= help: consider moving `SubType` to another trait
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/issue-76535.rs:7:10
|
LL | pub trait SuperTrait {
| ---------- this trait cannot be made into an object...
LL | type SubType<'a>: SubTrait;
| ^^^^^^^ ...because it contains the generic associated type `SubType`

error[E0038]: the trait `SuperTrait` cannot be made into an object
--> $DIR/issue-76535.rs:38:57
|
LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
|
= help: consider moving `SubType` to another trait
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/issue-76535.rs:7:10
|
LL | pub trait SuperTrait {
| ---------- this trait cannot be made into an object...
LL | type SubType<'a>: SubTrait;
| ^^^^^^^ ...because it contains the generic associated type `SubType`
= note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` for `Box<SuperStruct>`
= note: required by cast to type `Box<dyn SuperTrait<SubType = SubStruct<'_>>>`

error: aborting due to 3 previous errors; 1 warning emitted

For more information about this error, try `rustc --explain E0107`.
Some errors have detailed explanations: E0038, E0107.
For more information about an error, try `rustc --explain E0038`.
1 change: 1 addition & 0 deletions src/test/ui/generic-associated-types/issue-78671.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ trait CollectionFamily {
}
fn floatify() {
Box::new(Family) as &dyn CollectionFamily<Member=usize>
//~^ the trait `CollectionFamily` cannot be made into an object
}

struct Family;
Expand Down
20 changes: 18 additions & 2 deletions src/test/ui/generic-associated-types/issue-78671.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@ help: use angle brackets to add missing type argument
LL | type Member<T><T>;
| ^^^

error: aborting due to previous error
error[E0038]: the trait `CollectionFamily` cannot be made into an object
--> $DIR/issue-78671.rs:9:25
|
LL | Box::new(Family) as &dyn CollectionFamily<Member=usize>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object
|
= help: consider moving `Member` to another trait
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/issue-78671.rs:5:10
|
LL | trait CollectionFamily {
| ---------------- this trait cannot be made into an object...
LL | type Member<T>;
| ^^^^^^ ...because it contains the generic associated type `Member`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0107`.
Some errors have detailed explanations: E0038, E0107.
For more information about an error, try `rustc --explain E0038`.
3 changes: 2 additions & 1 deletion src/test/ui/generic-associated-types/issue-79422.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ impl<K, V: Default> MapLike<K, V> for Source {
fn main() {
let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
//~^^ ERROR type mismatch resolving
//~^^ the trait `MapLike` cannot be made into an object
//~^^ the trait `MapLike` cannot be made into an object
}
38 changes: 30 additions & 8 deletions src/test/ui/generic-associated-types/issue-79422.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,39 @@ help: use angle brackets to add missing lifetime argument
LL | type VRefCont<'a><'a>: RefCont<'a, V>;
| ^^^^

error[E0271]: type mismatch resolving `<BTreeMap<u8, u8> as MapLike<u8, u8>>::VRefCont<'static> == (dyn RefCont<'_, u8> + 'static)`
error[E0038]: the trait `MapLike` cannot be made into an object
--> $DIR/issue-79422.rs:44:12
|
LL | as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
|
= help: consider moving `VRefCont` to another trait
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/issue-79422.rs:21:10
|
LL | trait MapLike<K, V> {
| ------- this trait cannot be made into an object...
LL | type VRefCont<'a>: RefCont<'a, V>;
| ^^^^^^^^ ...because it contains the generic associated type `VRefCont`

error[E0038]: the trait `MapLike` cannot be made into an object
--> $DIR/issue-79422.rs:43:13
|
LL | let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn RefCont`, found reference
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
|
= help: consider moving `VRefCont` to another trait
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/issue-79422.rs:21:10
|
= note: expected trait object `(dyn RefCont<'_, u8> + 'static)`
found reference `&'static u8`
= note: required for the cast to the object type `dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>`
LL | trait MapLike<K, V> {
| ------- this trait cannot be made into an object...
LL | type VRefCont<'a>: RefCont<'a, V>;
| ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
= note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` for `Box<BTreeMap<u8, u8>>`
= note: required by cast to type `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`

error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0107, E0271.
For more information about an error, try `rustc --explain E0107`.
Some errors have detailed explanations: E0038, E0107.
For more information about an error, try `rustc --explain E0038`.
16 changes: 16 additions & 0 deletions src/test/ui/generic-associated-types/trait-objects.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#![feature(generic_associated_types)]
#![allow(incomplete_features)]

trait StreamingIterator {
type Item<'a> where Self: 'a;
fn size_hint(&self) -> (usize, Option<usize>);
// Uncommenting makes `StreamingIterator` not object safe
// fn next(&mut self) -> Self::Item<'_>;
}

fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize {
//~^ the trait `StreamingIterator` cannot be made into an object
x.size_hint().0
}

fn main() {}
18 changes: 18 additions & 0 deletions src/test/ui/generic-associated-types/trait-objects.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error[E0038]: the trait `StreamingIterator` cannot be made into an object
--> $DIR/trait-objects.rs:11:16
|
LL | fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object
|
= help: consider moving `Item` to another trait
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/trait-objects.rs:5:10
|
LL | trait StreamingIterator {
| ----------------- this trait cannot be made into an object...
LL | type Item<'a> where Self: 'a;
| ^^^^ ...because it contains the generic associated type `Item`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0038`.