Skip to content

Commit 8f96ef4

Browse files
committed
Auto merge of rust-lang#94911 - jackh726:gats_extended_2, r=compiler-errors
Make GATs object safe under generic_associated_types_extended feature Based on rust-lang#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`
2 parents b6a34f3 + 52b00db commit 8f96ef4

19 files changed

+240
-44
lines changed

compiler/rustc_trait_selection/src/traits/object_safety.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,18 @@ fn object_safety_violations_for_trait(
131131
}),
132132
);
133133

134-
violations.extend(
135-
tcx.associated_items(trait_def_id)
136-
.in_definition_order()
137-
.filter(|item| item.kind == ty::AssocKind::Type)
138-
.filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
139-
.map(|item| {
140-
let ident = item.ident(tcx);
141-
ObjectSafetyViolation::GAT(ident.name, ident.span)
142-
}),
143-
);
134+
if !tcx.features().generic_associated_types_extended {
135+
violations.extend(
136+
tcx.associated_items(trait_def_id)
137+
.in_definition_order()
138+
.filter(|item| item.kind == ty::AssocKind::Type)
139+
.filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
140+
.map(|item| {
141+
let ident = item.ident(tcx);
142+
ObjectSafetyViolation::GAT(ident.name, ident.span)
143+
}),
144+
);
145+
}
144146

145147
debug!(
146148
"object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+66-4
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use rustc_hir::lang_items::LangItem;
1111
use rustc_index::bit_set::GrowableBitSet;
1212
use rustc_infer::infer::InferOk;
1313
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
14-
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
15-
use rustc_middle::ty::{self, Ty};
14+
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
15+
use rustc_middle::ty::{self, GenericParamDefKind, Ty};
1616
use rustc_middle::ty::{ToPolyTraitRef, ToPredicate};
1717
use rustc_span::def_id::DefId;
1818

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

489489
for assoc_type in assoc_types {
490-
if !tcx.generics_of(assoc_type).params.is_empty() {
490+
let defs: &ty::Generics = tcx.generics_of(assoc_type);
491+
492+
if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended {
491493
tcx.sess.delay_span_bug(
492494
obligation.cause.span,
493495
"GATs in trait object shouldn't have been considered",
494496
);
495497
return Err(SelectionError::Unimplemented);
496498
}
499+
497500
// This maybe belongs in wf, but that can't (doesn't) handle
498501
// higher-ranked things.
499502
// Prevent, e.g., `dyn Iterator<Item = str>`.
500503
for bound in self.tcx().item_bounds(assoc_type) {
501-
let subst_bound = bound.subst(tcx, trait_predicate.trait_ref.substs);
504+
let subst_bound =
505+
if defs.count() == 0 {
506+
bound.subst(tcx, trait_predicate.trait_ref.substs)
507+
} else {
508+
let mut substs = smallvec::SmallVec::with_capacity(defs.count());
509+
substs.extend(trait_predicate.trait_ref.substs.iter());
510+
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
511+
smallvec::SmallVec::with_capacity(
512+
bound.kind().bound_vars().len() + defs.count(),
513+
);
514+
bound_vars.extend(bound.kind().bound_vars().into_iter());
515+
InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param
516+
.kind
517+
{
518+
GenericParamDefKind::Type { .. } => {
519+
let kind = ty::BoundTyKind::Param(param.name);
520+
let bound_var = ty::BoundVariableKind::Ty(kind);
521+
bound_vars.push(bound_var);
522+
tcx.mk_ty(ty::Bound(
523+
ty::INNERMOST,
524+
ty::BoundTy {
525+
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
526+
kind,
527+
},
528+
))
529+
.into()
530+
}
531+
GenericParamDefKind::Lifetime => {
532+
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
533+
let bound_var = ty::BoundVariableKind::Region(kind);
534+
bound_vars.push(bound_var);
535+
tcx.mk_region(ty::ReLateBound(
536+
ty::INNERMOST,
537+
ty::BoundRegion {
538+
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
539+
kind,
540+
},
541+
))
542+
.into()
543+
}
544+
GenericParamDefKind::Const { .. } => {
545+
let bound_var = ty::BoundVariableKind::Const;
546+
bound_vars.push(bound_var);
547+
tcx.mk_const(ty::ConstS {
548+
ty: tcx.type_of(param.def_id),
549+
val: ty::ConstKind::Bound(
550+
ty::INNERMOST,
551+
ty::BoundVar::from_usize(bound_vars.len() - 1),
552+
),
553+
})
554+
.into()
555+
}
556+
});
557+
let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
558+
let assoc_ty_substs = tcx.intern_substs(&substs);
559+
560+
let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
561+
let bound = bound.kind().skip_binder().subst(tcx, assoc_ty_substs);
562+
tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars))
563+
};
502564
let normalized_bound = normalize_with_depth_to(
503565
self,
504566
obligation.param_env,

src/test/ui/generic-associated-types/gat-in-trait-path.stderr src/test/ui/generic-associated-types/gat-in-trait-path.base.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0038]: the trait `Foo` cannot be made into an object
2-
--> $DIR/gat-in-trait-path.rs:21:17
2+
--> $DIR/gat-in-trait-path.rs:27:17
33
|
44
LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
66
|
77
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>
8-
--> $DIR/gat-in-trait-path.rs:5:10
8+
--> $DIR/gat-in-trait-path.rs:11:10
99
|
1010
LL | trait Foo {
1111
| --- this trait cannot be made into an object...

src/test/ui/generic-associated-types/gat-in-trait-path.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
// revisions: base extended
2+
//[base] check-fail
3+
//[extended] check-pass
4+
15
#![feature(generic_associated_types)]
26
#![feature(associated_type_defaults)]
7+
#![cfg_attr(extended, feature(generic_associated_types_extended))]
8+
#![cfg_attr(extended, allow(incomplete_features))]
39

410
trait Foo {
511
type A<'a> where Self: 'a;
@@ -19,7 +25,7 @@ impl<T> Foo for Fooer<T> {
1925
}
2026

2127
fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
22-
//~^ the trait `Foo` cannot be made into an object
28+
//[base]~^ the trait `Foo` cannot be made into an object
2329

2430

2531
fn main() {

src/test/ui/generic-associated-types/issue-67510-pass.stderr src/test/ui/generic-associated-types/issue-67510-pass.base.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0038]: the trait `X` cannot be made into an object
2-
--> $DIR/issue-67510-pass.rs:7:23
2+
--> $DIR/issue-67510-pass.rs:13:23
33
|
44
LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
55
| ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
66
|
77
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>
8-
--> $DIR/issue-67510-pass.rs:4:10
8+
--> $DIR/issue-67510-pass.rs:10:10
99
|
1010
LL | trait X {
1111
| - this trait cannot be made into an object...
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
// revisions: base extended
2+
//[base] check-fail
3+
//[extended] check-pass
4+
15
#![feature(generic_associated_types)]
6+
#![cfg_attr(extended, feature(generic_associated_types_extended))]
7+
#![cfg_attr(extended, allow(incomplete_features))]
28

39
trait X {
410
type Y<'a>;
511
}
612

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

1016
fn main() {}

src/test/ui/generic-associated-types/issue-76535.stderr src/test/ui/generic-associated-types/issue-76535.base.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0107]: missing generics for associated type `SuperTrait::SubType`
2-
--> $DIR/issue-76535.rs:36:33
2+
--> $DIR/issue-76535.rs:40:33
33
|
44
LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
55
| ^^^^^^^ expected 1 lifetime argument
66
|
77
note: associated type defined here, with 1 lifetime parameter: `'a`
8-
--> $DIR/issue-76535.rs:6:10
8+
--> $DIR/issue-76535.rs:10:10
99
|
1010
LL | type SubType<'a>: SubTrait where Self: 'a;
1111
| ^^^^^^^ --
@@ -15,13 +15,13 @@ LL | let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperS
1515
| ~~~~~~~~~~~
1616

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

3232
error[E0038]: the trait `SuperTrait` cannot be made into an object
33-
--> $DIR/issue-76535.rs:36:57
33+
--> $DIR/issue-76535.rs:40:57
3434
|
3535
LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
3636
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
3737
|
3838
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>
39-
--> $DIR/issue-76535.rs:6:10
39+
--> $DIR/issue-76535.rs:10:10
4040
|
4141
LL | pub trait SuperTrait {
4242
| ---------- this trait cannot be made into an object...
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0107]: missing generics for associated type `SuperTrait::SubType`
2+
--> $DIR/issue-76535.rs:40:33
3+
|
4+
LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
5+
| ^^^^^^^ expected 1 lifetime argument
6+
|
7+
note: associated type defined here, with 1 lifetime parameter: `'a`
8+
--> $DIR/issue-76535.rs:10:10
9+
|
10+
LL | type SubType<'a>: SubTrait where Self: 'a;
11+
| ^^^^^^^ --
12+
help: add missing lifetime argument
13+
|
14+
LL | let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperStruct::new(0));
15+
| ~~~~~~~~~~~
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0107`.

src/test/ui/generic-associated-types/issue-76535.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
// revisions: base extended
2+
13
#![feature(generic_associated_types)]
4+
#![cfg_attr(extended, feature(generic_associated_types_extended))]
5+
#![cfg_attr(extended, allow(incomplete_features))]
26

37
pub trait SubTrait {}
48

@@ -35,6 +39,6 @@ impl SuperTrait for SuperStruct {
3539
fn main() {
3640
let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
3741
//~^ ERROR missing generics for associated type
38-
//~^^ ERROR the trait
39-
//~| ERROR the trait
42+
//[base]~^^ ERROR the trait
43+
//[base]~| ERROR the trait
4044
}

src/test/ui/generic-associated-types/issue-78671.stderr src/test/ui/generic-associated-types/issue-78671.base.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0107]: missing generics for associated type `CollectionFamily::Member`
2-
--> $DIR/issue-78671.rs:7:47
2+
--> $DIR/issue-78671.rs:11:47
33
|
44
LL | Box::new(Family) as &dyn CollectionFamily<Member=usize>
55
| ^^^^^^ expected 1 generic argument
66
|
77
note: associated type defined here, with 1 generic parameter: `T`
8-
--> $DIR/issue-78671.rs:4:10
8+
--> $DIR/issue-78671.rs:8:10
99
|
1010
LL | type Member<T>;
1111
| ^^^^^^ -
@@ -15,13 +15,13 @@ LL | Box::new(Family) as &dyn CollectionFamily<Member<T>=usize>
1515
| ~~~~~~~~~
1616

1717
error[E0038]: the trait `CollectionFamily` cannot be made into an object
18-
--> $DIR/issue-78671.rs:7:25
18+
--> $DIR/issue-78671.rs:11:25
1919
|
2020
LL | Box::new(Family) as &dyn CollectionFamily<Member=usize>
2121
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object
2222
|
2323
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>
24-
--> $DIR/issue-78671.rs:4:10
24+
--> $DIR/issue-78671.rs:8:10
2525
|
2626
LL | trait CollectionFamily {
2727
| ---------------- this trait cannot be made into an object...
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0107]: missing generics for associated type `CollectionFamily::Member`
2+
--> $DIR/issue-78671.rs:11:47
3+
|
4+
LL | Box::new(Family) as &dyn CollectionFamily<Member=usize>
5+
| ^^^^^^ expected 1 generic argument
6+
|
7+
note: associated type defined here, with 1 generic parameter: `T`
8+
--> $DIR/issue-78671.rs:8:10
9+
|
10+
LL | type Member<T>;
11+
| ^^^^^^ -
12+
help: add missing generic argument
13+
|
14+
LL | Box::new(Family) as &dyn CollectionFamily<Member<T>=usize>
15+
| ~~~~~~~~~
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0107`.

src/test/ui/generic-associated-types/issue-78671.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
// revisions: base extended
2+
13
#![feature(generic_associated_types)]
4+
#![cfg_attr(extended, feature(generic_associated_types_extended))]
5+
#![cfg_attr(extended, allow(incomplete_features))]
26

37
trait CollectionFamily {
48
type Member<T>;
59
}
610
fn floatify() {
711
Box::new(Family) as &dyn CollectionFamily<Member=usize>
812
//~^ ERROR: missing generics for associated type
9-
//~| ERROR: the trait `CollectionFamily` cannot be made into an object
13+
//[base]~^^ ERROR: the trait `CollectionFamily` cannot be made into an object
1014
}
1115

1216
struct Family;

src/test/ui/generic-associated-types/issue-79422.stderr src/test/ui/generic-associated-types/issue-79422.base.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0107]: missing generics for associated type `MapLike::VRefCont`
2-
--> $DIR/issue-79422.rs:42:36
2+
--> $DIR/issue-79422.rs:48:36
33
|
44
LL | as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
55
| ^^^^^^^^ expected 1 lifetime argument
66
|
77
note: associated type defined here, with 1 lifetime parameter: `'a`
8-
--> $DIR/issue-79422.rs:20:10
8+
--> $DIR/issue-79422.rs:24:10
99
|
1010
LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
1111
| ^^^^^^^^ --
@@ -15,13 +15,13 @@ LL | as Box<dyn MapLike<u8, u8, VRefCont<'a> = dyn RefCont<'_, u8>>>;
1515
| ~~~~~~~~~~~~
1616

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

3232
error[E0038]: the trait `MapLike` cannot be made into an object
33-
--> $DIR/issue-79422.rs:41:13
33+
--> $DIR/issue-79422.rs:45:13
3434
|
3535
LL | let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
3636
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
3737
|
3838
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>
39-
--> $DIR/issue-79422.rs:20:10
39+
--> $DIR/issue-79422.rs:24:10
4040
|
4141
LL | trait MapLike<K, V> {
4242
| ------- this trait cannot be made into an object...

0 commit comments

Comments
 (0)