Skip to content

Commit

Permalink
Auto merge of #94911 - jackh726:gats_extended_2, r=compiler-errors
Browse files Browse the repository at this point in the history
Make GATs object safe under generic_associated_types_extended feature

Based on #94869

Let's say we have
```rust
trait StreamingIterator {
    type Item<'a> where Self: 'a;
}
```
And `dyn for<'a> StreamingIterator<Item<'a> = &'a i32>`.

If we ask `(dyn for<'a> StreamingIterator<Item<'a> = &'a i32>): StreamingIterator`, then we have to prove that `for<'x> (&'x i32): Sized`. So, we generate *new* bound vars to subst for the GAT generics.

Importantly, this doesn't fully verify that these are usable and sound.

r? `@nikomatsakis`
  • Loading branch information
bors committed Apr 2, 2022
2 parents b6a34f3 + 52b00db commit 8f96ef4
Show file tree
Hide file tree
Showing 19 changed files with 240 additions and 44 deletions.
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 {
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

0 comments on commit 8f96ef4

Please sign in to comment.