Skip to content

Commit 1736f20

Browse files
committed
Support assoc type defaults for assoc type constraints for trait objects
1 parent 3fc3732 commit 1736f20

3 files changed

Lines changed: 75 additions & 6 deletions

File tree

compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
234234
.filter(|item| item.is_type() || item.is_const())
235235
// Traits with RPITITs are simply not dyn compatible (for now).
236236
.filter(|item| !item.is_impl_trait_in_trait())
237-
.map(|item| (item.def_id, trait_ref)),
237+
.map(|item| (item, trait_ref)),
238238
);
239239
}
240240
ty::ClauseKind::Projection(pred) => {
@@ -314,14 +314,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
314314
let mut missing_assoc_items = FxIndexSet::default();
315315
let projection_bounds: Vec<_> = ordered_associated_items
316316
.into_iter()
317-
.filter_map(|key @ (def_id, _)| {
318-
if let Some(&assoc) = projection_bounds.get(&key) {
317+
.filter_map(|(item, trait_ref)| {
318+
let def_id = item.def_id;
319+
let key = (def_id, trait_ref);
320+
if let Some(&(assoc, _)) = projection_bounds.get(&key) {
319321
return Some(assoc);
320322
}
321-
if !tcx.generics_require_sized_self(def_id) {
323+
let has_default = item.defaultness(tcx).has_value();
324+
if !has_default && !tcx.generics_require_sized_self(def_id) {
322325
missing_assoc_items.insert(key);
323326
}
324-
None
327+
if has_default {
328+
Some(trait_ref.map_bound(|trait_ref| ty::ProjectionPredicate {
329+
projection_term: ty::AliasTerm::new_from_args(tcx, def_id, trait_ref.args),
330+
term: tcx.type_of(def_id).instantiate(tcx, trait_ref.args).into(),
331+
}))
332+
} else {
333+
None
334+
}
325335
})
326336
.collect();
327337

@@ -394,7 +404,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
394404
})
395405
});
396406

397-
let existential_projections = projection_bounds.into_iter().map(|(bound, _)| {
407+
let existential_projections = projection_bounds.into_iter().map(|bound| {
398408
bound.map_bound(|mut b| {
399409
assert_eq!(b.projection_term.self_ty(), dummy_self);
400410

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#![feature(associated_type_defaults)]
2+
3+
trait Foo {
4+
type Assoc: Default = ();
5+
6+
fn foo(&self) -> Self::Assoc {
7+
Default::default()
8+
}
9+
}
10+
11+
// The assoc type constraint can be omitted for the assoc type with a default.
12+
type FooObj = Box<dyn Foo>;
13+
14+
trait Bar {
15+
type Assoc1 = i32;
16+
type Assoc2;
17+
}
18+
19+
// We can't omit assoc type constraints for an assoc type without a default value.
20+
type BarObj1 = Box<dyn Bar>;
21+
//~^ ERROR: the value of the associated type `Assoc2` in `Bar` must be specified
22+
23+
type BarObj2 = Box<dyn Bar<Assoc2 = ()>>;
24+
25+
type BarObj3 = Box<dyn Bar<Assoc1 = u32, Assoc2 = i32>>;
26+
27+
fn check_projs(foo1: &dyn Foo, foo2: &dyn Foo<Assoc = bool>) {
28+
let _: () = foo1.foo();
29+
let _: () = foo2.foo();
30+
//~^ ERROR: mismatched types
31+
}
32+
33+
fn main() {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error[E0191]: the value of the associated type `Assoc2` in `Bar` must be specified
2+
--> $DIR/defaults-on-trait-object.rs:20:24
3+
|
4+
LL | type Assoc2;
5+
| ----------- `Assoc2` defined here
6+
...
7+
LL | type BarObj1 = Box<dyn Bar>;
8+
| ^^^
9+
|
10+
help: specify the associated type
11+
|
12+
LL | type BarObj1 = Box<dyn Bar<Assoc2 = /* Type */>>;
13+
| +++++++++++++++++++++
14+
15+
error[E0308]: mismatched types
16+
--> $DIR/defaults-on-trait-object.rs:29:17
17+
|
18+
LL | let _: () = foo2.foo();
19+
| -- ^^^^^^^^^^ expected `()`, found `bool`
20+
| |
21+
| expected due to this
22+
23+
error: aborting due to 2 previous errors
24+
25+
Some errors have detailed explanations: E0191, E0308.
26+
For more information about an error, try `rustc --explain E0191`.

0 commit comments

Comments
 (0)