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 GATs object safe under generic_associated_types_extended feature #94911

Merged
merged 1 commit into from
Apr 2, 2022
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
22 changes: 12 additions & 10 deletions compiler/rustc_trait_selection/src/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,18 @@ fn object_safety_violations_for_trait(
}),
);

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| {
let ident = item.ident(tcx);
ObjectSafetyViolation::GAT(ident.name, ident.span)
}),
);
if !tcx.features().generic_associated_types_extended {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to say that this should also deny GATs with type parameters, but it seems we already disallow those elsewhere: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1af97ded49aa74d43f72f0c3b70658e9

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| {
let ident = item.ident(tcx);
ObjectSafetyViolation::GAT(ident.name, ident.span)
}),
);
}

debug!(
"object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
Expand Down
70 changes: 66 additions & 4 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::GrowableBitSet;
use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
use rustc_middle::ty::{self, Ty};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, GenericParamDefKind, Ty};
use rustc_middle::ty::{ToPolyTraitRef, ToPredicate};
use rustc_span::def_id::DefId;

Expand Down Expand Up @@ -487,18 +487,80 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.collect();

for assoc_type in assoc_types {
if !tcx.generics_of(assoc_type).params.is_empty() {
let defs: &ty::Generics = tcx.generics_of(assoc_type);

if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended {
tcx.sess.delay_span_bug(
obligation.cause.span,
"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.
// Prevent, e.g., `dyn Iterator<Item = str>`.
for bound in self.tcx().item_bounds(assoc_type) {
let subst_bound = bound.subst(tcx, trait_predicate.trait_ref.substs);
let subst_bound =
if defs.count() == 0 {
bound.subst(tcx, trait_predicate.trait_ref.substs)
} else {
let mut substs = smallvec::SmallVec::with_capacity(defs.count());
substs.extend(trait_predicate.trait_ref.substs.iter());
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
smallvec::SmallVec::with_capacity(
bound.kind().bound_vars().len() + defs.count(),
);
bound_vars.extend(bound.kind().bound_vars().into_iter());
InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param
.kind
{
GenericParamDefKind::Type { .. } => {
let kind = ty::BoundTyKind::Param(param.name);
let bound_var = ty::BoundVariableKind::Ty(kind);
bound_vars.push(bound_var);
tcx.mk_ty(ty::Bound(
ty::INNERMOST,
ty::BoundTy {
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
kind,
},
))
.into()
}
GenericParamDefKind::Lifetime => {
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Region(kind);
bound_vars.push(bound_var);
tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
ty::BoundRegion {
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
kind,
},
))
.into()
}
GenericParamDefKind::Const { .. } => {
let bound_var = ty::BoundVariableKind::Const;
bound_vars.push(bound_var);
tcx.mk_const(ty::ConstS {
ty: tcx.type_of(param.def_id),
val: ty::ConstKind::Bound(
ty::INNERMOST,
ty::BoundVar::from_usize(bound_vars.len() - 1),
),
})
.into()
}
});
let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
let assoc_ty_substs = tcx.intern_substs(&substs);

let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
let bound = bound.kind().skip_binder().subst(tcx, assoc_ty_substs);
tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars))
};
let normalized_bound = normalize_with_depth_to(
self,
obligation.param_env,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/gat-in-trait-path.rs:21:17
--> $DIR/gat-in-trait-path.rs:27:17
|
LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
|
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:5:10
--> $DIR/gat-in-trait-path.rs:11:10
|
LL | trait Foo {
| --- this trait cannot be made into an object...
Expand Down
8 changes: 7 additions & 1 deletion src/test/ui/generic-associated-types/gat-in-trait-path.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
// revisions: base extended
//[base] check-fail
//[extended] check-pass

#![feature(generic_associated_types)]
#![feature(associated_type_defaults)]
#![cfg_attr(extended, feature(generic_associated_types_extended))]
#![cfg_attr(extended, allow(incomplete_features))]

trait Foo {
type A<'a> where Self: 'a;
Expand All @@ -19,7 +25,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
//[base]~^ the trait `Foo` cannot be made into an object


fn main() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0038]: the trait `X` cannot be made into an object
--> $DIR/issue-67510-pass.rs:7:23
--> $DIR/issue-67510-pass.rs:13:23
|
LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
| ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
|
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:4:10
--> $DIR/issue-67510-pass.rs:10:10
|
LL | trait X {
| - this trait cannot be made into an object...
Expand Down
8 changes: 7 additions & 1 deletion src/test/ui/generic-associated-types/issue-67510-pass.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
// revisions: base extended
//[base] check-fail
//[extended] check-pass

#![feature(generic_associated_types)]
#![cfg_attr(extended, feature(generic_associated_types_extended))]
#![cfg_attr(extended, allow(incomplete_features))]

trait X {
type Y<'a>;
}

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

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0107]: missing generics for associated type `SuperTrait::SubType`
--> $DIR/issue-76535.rs:36:33
--> $DIR/issue-76535.rs:40:33
|
LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
| ^^^^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-76535.rs:6:10
--> $DIR/issue-76535.rs:10:10
|
LL | type SubType<'a>: SubTrait where Self: 'a;
| ^^^^^^^ --
Expand All @@ -15,13 +15,13 @@ LL | let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperS
| ~~~~~~~~~~~

error[E0038]: the trait `SuperTrait` cannot be made into an object
--> $DIR/issue-76535.rs:36:14
--> $DIR/issue-76535.rs:40:14
|
LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
|
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:6:10
--> $DIR/issue-76535.rs:10:10
|
LL | pub trait SuperTrait {
| ---------- this trait cannot be made into an object...
Expand All @@ -30,13 +30,13 @@ LL | type SubType<'a>: SubTrait where Self: 'a;
= help: consider moving `SubType` to another trait

error[E0038]: the trait `SuperTrait` cannot be made into an object
--> $DIR/issue-76535.rs:36:57
--> $DIR/issue-76535.rs:40:57
|
LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
|
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:6:10
--> $DIR/issue-76535.rs:10:10
|
LL | pub trait SuperTrait {
| ---------- this trait cannot be made into an object...
Expand Down
19 changes: 19 additions & 0 deletions src/test/ui/generic-associated-types/issue-76535.extended.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0107]: missing generics for associated type `SuperTrait::SubType`
--> $DIR/issue-76535.rs:40:33
|
LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
| ^^^^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-76535.rs:10:10
|
LL | type SubType<'a>: SubTrait where Self: 'a;
| ^^^^^^^ --
help: add missing lifetime argument
|
LL | let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperStruct::new(0));
| ~~~~~~~~~~~

error: aborting due to previous error

For more information about this error, try `rustc --explain E0107`.
8 changes: 6 additions & 2 deletions src/test/ui/generic-associated-types/issue-76535.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
// revisions: base extended

#![feature(generic_associated_types)]
#![cfg_attr(extended, feature(generic_associated_types_extended))]
#![cfg_attr(extended, allow(incomplete_features))]

pub trait SubTrait {}

Expand Down Expand Up @@ -35,6 +39,6 @@ impl SuperTrait for SuperStruct {
fn main() {
let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
//~^ ERROR missing generics for associated type
//~^^ ERROR the trait
//~| ERROR the trait
//[base]~^^ ERROR the trait
//[base]~| ERROR the trait
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0107]: missing generics for associated type `CollectionFamily::Member`
--> $DIR/issue-78671.rs:7:47
--> $DIR/issue-78671.rs:11:47
|
LL | Box::new(Family) as &dyn CollectionFamily<Member=usize>
| ^^^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-78671.rs:4:10
--> $DIR/issue-78671.rs:8:10
|
LL | type Member<T>;
| ^^^^^^ -
Expand All @@ -15,13 +15,13 @@ LL | Box::new(Family) as &dyn CollectionFamily<Member<T>=usize>
| ~~~~~~~~~

error[E0038]: the trait `CollectionFamily` cannot be made into an object
--> $DIR/issue-78671.rs:7:25
--> $DIR/issue-78671.rs:11:25
|
LL | Box::new(Family) as &dyn CollectionFamily<Member=usize>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object
|
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:4:10
--> $DIR/issue-78671.rs:8:10
|
LL | trait CollectionFamily {
| ---------------- this trait cannot be made into an object...
Expand Down
19 changes: 19 additions & 0 deletions src/test/ui/generic-associated-types/issue-78671.extended.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0107]: missing generics for associated type `CollectionFamily::Member`
--> $DIR/issue-78671.rs:11:47
|
LL | Box::new(Family) as &dyn CollectionFamily<Member=usize>
| ^^^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-78671.rs:8:10
|
LL | type Member<T>;
| ^^^^^^ -
help: add missing generic argument
|
LL | Box::new(Family) as &dyn CollectionFamily<Member<T>=usize>
| ~~~~~~~~~

error: aborting due to previous error

For more information about this error, try `rustc --explain E0107`.
6 changes: 5 additions & 1 deletion src/test/ui/generic-associated-types/issue-78671.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// revisions: base extended

#![feature(generic_associated_types)]
#![cfg_attr(extended, feature(generic_associated_types_extended))]
#![cfg_attr(extended, allow(incomplete_features))]

trait CollectionFamily {
type Member<T>;
}
fn floatify() {
Box::new(Family) as &dyn CollectionFamily<Member=usize>
//~^ ERROR: missing generics for associated type
//~| ERROR: the trait `CollectionFamily` cannot be made into an object
//[base]~^^ ERROR: the trait `CollectionFamily` cannot be made into an object
}

struct Family;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0107]: missing generics for associated type `MapLike::VRefCont`
--> $DIR/issue-79422.rs:42:36
--> $DIR/issue-79422.rs:48:36
|
LL | as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
| ^^^^^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-79422.rs:20:10
--> $DIR/issue-79422.rs:24:10
|
LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
| ^^^^^^^^ --
Expand All @@ -15,13 +15,13 @@ LL | as Box<dyn MapLike<u8, u8, VRefCont<'a> = dyn RefCont<'_, u8>>>;
| ~~~~~~~~~~~~

error[E0038]: the trait `MapLike` cannot be made into an object
--> $DIR/issue-79422.rs:42:12
--> $DIR/issue-79422.rs:48:12
|
LL | as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
|
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:20:10
--> $DIR/issue-79422.rs:24:10
|
LL | trait MapLike<K, V> {
| ------- this trait cannot be made into an object...
Expand All @@ -30,13 +30,13 @@ LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
= help: consider moving `VRefCont` to another trait

error[E0038]: the trait `MapLike` cannot be made into an object
--> $DIR/issue-79422.rs:41:13
--> $DIR/issue-79422.rs:45:13
|
LL | let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
|
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:20:10
--> $DIR/issue-79422.rs:24:10
|
LL | trait MapLike<K, V> {
| ------- this trait cannot be made into an object...
Expand Down
Loading