From 857cb4de20160ed8a4931a87ee1112aeb8c0d97e Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Tue, 27 Apr 2021 14:34:23 -0400 Subject: [PATCH] Make traits with GATs not object safe --- compiler/rustc_middle/src/traits/mod.rs | 8 ++++ .../src/traits/object_safety.rs | 8 ++++ .../src/traits/select/confirmation.rs | 7 ++-- .../gat-in-trait-path.rs | 3 +- .../gat-in-trait-path.stderr | 20 +++++++++- .../issue-67510-pass.rs | 3 +- .../issue-67510-pass.stderr | 20 +++++++++- .../generic-associated-types/issue-76535.rs | 2 + .../issue-76535.stderr | 37 +++++++++++++++++- .../generic-associated-types/issue-78671.rs | 1 + .../issue-78671.stderr | 20 +++++++++- .../generic-associated-types/issue-79422.rs | 3 +- .../issue-79422.stderr | 38 +++++++++++++++---- .../generic-associated-types/trait-objects.rs | 16 ++++++++ .../trait-objects.stderr | 18 +++++++++ 15 files changed, 179 insertions(+), 25 deletions(-) create mode 100644 src/test/ui/generic-associated-types/trait-objects.rs create mode 100644 src/test/ui/generic-associated-types/trait-objects.stderr diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 00dec3b355f8f..c9b73c682098b 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -670,6 +670,9 @@ pub enum ObjectSafetyViolation { /// Associated const. AssocConst(Symbol, Span), + + /// GAT + GAT(Symbol, Span), } impl ObjectSafetyViolation { @@ -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() + } } } @@ -773,6 +779,7 @@ impl ObjectSafetyViolation { ); } ObjectSafetyViolation::AssocConst(name, _) + | ObjectSafetyViolation::GAT(name, _) | ObjectSafetyViolation::Method(name, ..) => { err.help(&format!("consider moving `{}` to another trait", name)); } @@ -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 => { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index ac5ec24eeeeb5..d5e1bd3f9ea2e 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -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 diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 31685a012ca2f..e338a21b60308 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -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. diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.rs b/src/test/ui/generic-associated-types/gat-in-trait-path.rs index 2dbd1840dec55..6527eb4750455 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path.rs +++ b/src/test/ui/generic-associated-types/gat-in-trait-path.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(generic_associated_types)] //~^ WARNING: the feature `generic_associated_types` is incomplete #![feature(associated_type_defaults)] @@ -22,6 +20,7 @@ impl Foo for Fooer { } fn f(_arg : Box Foo = &'a ()>>) {} +//~^ the trait `Foo` cannot be made into an object fn main() { diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr index f3769827f04b2..49dfce8b4bd38 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr +++ b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr @@ -1,5 +1,5 @@ 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)] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,5 +7,21 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #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 Foo = &'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 + --> $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`. diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.rs b/src/test/ui/generic-associated-types/issue-67510-pass.rs index ff38b3e93eb1a..6ee865072aebf 100644 --- a/src/test/ui/generic-associated-types/issue-67510-pass.rs +++ b/src/test/ui/generic-associated-types/issue-67510-pass.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(generic_associated_types)] //~^ WARNING: the feature `generic_associated_types` is incomplete @@ -8,5 +6,6 @@ trait X { } fn _func1<'a>(_x: Box=&'a ()>>) {} +//~^ ERROR the trait `X` cannot be made into an object fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.stderr b/src/test/ui/generic-associated-types/issue-67510-pass.stderr index 0fbf704df76a1..65998afa7f914 100644 --- a/src/test/ui/generic-associated-types/issue-67510-pass.stderr +++ b/src/test/ui/generic-associated-types/issue-67510-pass.stderr @@ -1,5 +1,5 @@ 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)] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,5 +7,21 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #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=&'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 + --> $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`. diff --git a/src/test/ui/generic-associated-types/issue-76535.rs b/src/test/ui/generic-associated-types/issue-76535.rs index 5e73a88298622..9643c82db7732 100644 --- a/src/test/ui/generic-associated-types/issue-76535.rs +++ b/src/test/ui/generic-associated-types/issue-76535.rs @@ -36,4 +36,6 @@ impl SuperTrait for SuperStruct { fn main() { let sub: Box> = 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 } diff --git a/src/test/ui/generic-associated-types/issue-76535.stderr b/src/test/ui/generic-associated-types/issue-76535.stderr index 17661e0d90a4a..d31560f12f0bb 100644 --- a/src/test/ui/generic-associated-types/issue-76535.stderr +++ b/src/test/ui/generic-associated-types/issue-76535.stderr @@ -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> = 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 + --> $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> = 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 + --> $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>>>` for `Box` + = note: required by cast to type `Box>>` + +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`. diff --git a/src/test/ui/generic-associated-types/issue-78671.rs b/src/test/ui/generic-associated-types/issue-78671.rs index 1b02aac8bcb24..4e47d3c665505 100644 --- a/src/test/ui/generic-associated-types/issue-78671.rs +++ b/src/test/ui/generic-associated-types/issue-78671.rs @@ -7,6 +7,7 @@ trait CollectionFamily { } fn floatify() { Box::new(Family) as &dyn CollectionFamily + //~^ the trait `CollectionFamily` cannot be made into an object } struct Family; diff --git a/src/test/ui/generic-associated-types/issue-78671.stderr b/src/test/ui/generic-associated-types/issue-78671.stderr index 7a9aced5beab8..c9febfb59af62 100644 --- a/src/test/ui/generic-associated-types/issue-78671.stderr +++ b/src/test/ui/generic-associated-types/issue-78671.stderr @@ -14,6 +14,22 @@ help: use angle brackets to add missing type argument LL | type Member; | ^^^ -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 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `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 + --> $DIR/issue-78671.rs:5:10 + | +LL | trait CollectionFamily { + | ---------------- this trait cannot be made into an object... +LL | type Member; + | ^^^^^^ ...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`. diff --git a/src/test/ui/generic-associated-types/issue-79422.rs b/src/test/ui/generic-associated-types/issue-79422.rs index aeb33ca54641c..b2ba3c24abbe1 100644 --- a/src/test/ui/generic-associated-types/issue-79422.rs +++ b/src/test/ui/generic-associated-types/issue-79422.rs @@ -42,5 +42,6 @@ impl MapLike for Source { fn main() { let m = Box::new(std::collections::BTreeMap::::new()) as Box>>; - //~^^ ERROR type mismatch resolving + //~^^ the trait `MapLike` cannot be made into an object + //~^^ the trait `MapLike` cannot be made into an object } diff --git a/src/test/ui/generic-associated-types/issue-79422.stderr b/src/test/ui/generic-associated-types/issue-79422.stderr index a119bff03e290..4973ae19729ac 100644 --- a/src/test/ui/generic-associated-types/issue-79422.stderr +++ b/src/test/ui/generic-associated-types/issue-79422.stderr @@ -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 ` as MapLike>::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>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `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 + --> $DIR/issue-79422.rs:21:10 + | +LL | trait MapLike { + | ------- 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::::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 + --> $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 + 'static)>` +LL | trait MapLike { + | ------- 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 + 'static)>>>` for `Box>` + = note: required by cast to type `Box + '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`. diff --git a/src/test/ui/generic-associated-types/trait-objects.rs b/src/test/ui/generic-associated-types/trait-objects.rs new file mode 100644 index 0000000000000..997a550b0effb --- /dev/null +++ b/src/test/ui/generic-associated-types/trait-objects.rs @@ -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); + // Uncommenting makes `StreamingIterator` not object safe +// fn next(&mut self) -> Self::Item<'_>; +} + +fn min_size(x: &mut dyn for<'a> StreamingIterator = &'a i32>) -> usize { + //~^ the trait `StreamingIterator` cannot be made into an object + x.size_hint().0 +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/trait-objects.stderr b/src/test/ui/generic-associated-types/trait-objects.stderr new file mode 100644 index 0000000000000..a8f1768ba2617 --- /dev/null +++ b/src/test/ui/generic-associated-types/trait-objects.stderr @@ -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 = &'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 + --> $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`.