Skip to content

Commit a323ff2

Browse files
Implement RFC 2532 – Associated Type Defaults
1 parent 187f3d7 commit a323ff2

15 files changed

+247
-151
lines changed

src/librustc_infer/traits/project.rs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,25 +1054,40 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
10541054
// an error when we confirm the candidate
10551055
// (which will ultimately lead to `normalize_to_error`
10561056
// being invoked).
1057-
node_item.item.defaultness.has_value()
1057+
false
10581058
} else {
1059+
// If we're looking at a trait *impl*, the item is
1060+
// specializable if the impl or the item are marked
1061+
// `default`.
10591062
node_item.item.defaultness.is_default()
10601063
|| super::util::impl_is_default(selcx.tcx(), node_item.node.def_id())
10611064
};
10621065

1063-
// Only reveal a specializable default if we're past type-checking
1064-
// and the obligations is monomorphic, otherwise passes such as
1065-
// transmute checking and polymorphic MIR optimizations could
1066-
// get a result which isn't correct for all monomorphizations.
1067-
if !is_default {
1068-
true
1069-
} else if obligation.param_env.reveal == Reveal::All {
1070-
// NOTE(eddyb) inference variables can resolve to parameters, so
1071-
// assume `poly_trait_ref` isn't monomorphic, if it contains any.
1072-
let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(&poly_trait_ref);
1073-
!poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst()
1074-
} else {
1075-
false
1066+
match is_default {
1067+
// Non-specializable items are always projectable
1068+
false => true,
1069+
1070+
// Only reveal a specializable default if we're past type-checking
1071+
// and the obligation is monomorphic, otherwise passes such as
1072+
// transmute checking and polymorphic MIR optimizations could
1073+
// get a result which isn't correct for all monomorphizations.
1074+
true if obligation.param_env.reveal == Reveal::All => {
1075+
// NOTE(eddyb) inference variables can resolve to parameters, so
1076+
// assume `poly_trait_ref` isn't monomorphic, if it contains any.
1077+
let poly_trait_ref =
1078+
selcx.infcx().resolve_vars_if_possible(&poly_trait_ref);
1079+
!poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst()
1080+
}
1081+
1082+
true => {
1083+
debug!(
1084+
"assemble_candidates_from_impls: not eligible due to default: \
1085+
assoc_ty={} predicate={}",
1086+
selcx.tcx().def_path_str(node_item.item.def_id),
1087+
obligation.predicate,
1088+
);
1089+
false
1090+
}
10761091
}
10771092
}
10781093
super::VtableParam(..) => {

src/librustc_typeck/check/mod.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,7 +1964,6 @@ fn check_impl_items_against_trait<'tcx>(
19641964

19651965
// Locate trait definition and items
19661966
let trait_def = tcx.trait_def(impl_trait_ref.def_id);
1967-
let mut overridden_associated_type = None;
19681967

19691968
let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
19701969

@@ -2046,9 +2045,6 @@ fn check_impl_items_against_trait<'tcx>(
20462045
hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(_) => {
20472046
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
20482047
if ty_trait_item.kind == ty::AssocKind::Type {
2049-
if ty_trait_item.defaultness.has_value() {
2050-
overridden_associated_type = Some(impl_item);
2051-
}
20522048
compare_ty_impl(
20532049
tcx,
20542050
&ty_impl_item,
@@ -2082,8 +2078,6 @@ fn check_impl_items_against_trait<'tcx>(
20822078

20832079
// Check for missing items from trait
20842080
let mut missing_items = Vec::new();
2085-
let mut invalidated_items = Vec::new();
2086-
let associated_type_overridden = overridden_associated_type.is_some();
20872081
for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
20882082
let is_implemented = trait_def
20892083
.ancestors(tcx, impl_id)
@@ -2094,28 +2088,13 @@ fn check_impl_items_against_trait<'tcx>(
20942088
if !is_implemented && !traits::impl_is_default(tcx, impl_id) {
20952089
if !trait_item.defaultness.has_value() {
20962090
missing_items.push(*trait_item);
2097-
} else if associated_type_overridden {
2098-
invalidated_items.push(trait_item.ident);
20992091
}
21002092
}
21012093
}
21022094

21032095
if !missing_items.is_empty() {
21042096
missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
21052097
}
2106-
2107-
if !invalidated_items.is_empty() {
2108-
let invalidator = overridden_associated_type.unwrap();
2109-
struct_span_err!(
2110-
tcx.sess,
2111-
invalidator.span,
2112-
E0399,
2113-
"the following trait items need to be reimplemented as `{}` was overridden: `{}`",
2114-
invalidator.ident,
2115-
invalidated_items.iter().map(|name| name.to_string()).collect::<Vec<_>>().join("`, `")
2116-
)
2117-
.emit();
2118-
}
21192098
}
21202099

21212100
fn missing_items_err(

src/test/ui/associated-types/associated-types-overridden-default.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// check-pass
2+
3+
// Before RFC 2532, overriding one assoc. type default required overriding all
4+
// provided defaults.
5+
16
#![feature(associated_type_defaults)]
27

38
pub trait Tr {
@@ -9,7 +14,6 @@ pub trait Tr {
914

1015
impl Tr for () {
1116
type Assoc = ();
12-
//~^ ERROR need to be reimplemented as `Assoc` was overridden: `Assoc2`, `C`, `foo`
1317
}
1418

1519
fn main() {}

src/test/ui/associated-types/associated-types-overridden-default.stderr

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#![feature(associated_type_defaults)]
2+
3+
// Having a cycle in assoc. type defaults is okay...
4+
trait Tr {
5+
type A = Self::B;
6+
type B = Self::A;
7+
}
8+
9+
// ...but is an error in any impl that doesn't override at least one of the defaults
10+
impl Tr for () {}
11+
//~^ ERROR overflow evaluating the requirement
12+
13+
// As soon as at least one is redefined, it works:
14+
impl Tr for u8 {
15+
type A = u8;
16+
}
17+
18+
impl Tr for u32 {
19+
type A = ();
20+
type B = u8;
21+
}
22+
23+
// ...but only if this actually breaks the cycle
24+
impl Tr for bool {
25+
//~^ ERROR overflow evaluating the requirement
26+
type A = Box<Self::B>;
27+
//~^ ERROR overflow evaluating the requirement
28+
}
29+
// (the error is shown twice for some reason)
30+
31+
fn main() {
32+
// Check that the overridden type propagates to the other
33+
let _a: <u8 as Tr>::A = 0u8;
34+
let _b: <u8 as Tr>::B = 0u8;
35+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0275]: overflow evaluating the requirement `<() as Tr>::B`
2+
--> $DIR/defaults-cyclic-fail.rs:10:6
3+
|
4+
LL | impl Tr for () {}
5+
| ^^
6+
7+
error[E0275]: overflow evaluating the requirement `<bool as Tr>::B`
8+
--> $DIR/defaults-cyclic-fail.rs:24:6
9+
|
10+
LL | impl Tr for bool {
11+
| ^^
12+
13+
error[E0275]: overflow evaluating the requirement `<bool as Tr>::B`
14+
--> $DIR/defaults-cyclic-fail.rs:26:5
15+
|
16+
LL | type A = Box<Self::B>;
17+
| ^^^^^^^^^^^^^^^^^^^^^^
18+
19+
error: aborting due to 3 previous errors
20+
21+
For more information about this error, try `rustc --explain E0275`.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// check-pass
2+
3+
#![feature(associated_type_defaults)]
4+
5+
trait Tr {
6+
type Item = u8;
7+
type Container = Vec<Self::Item>;
8+
}
9+
10+
impl Tr for () {}
11+
12+
impl Tr for u16 {
13+
type Item = u16;
14+
}
15+
16+
fn main() {
17+
let _container: <() as Tr>::Container = Vec::<u8>::new();
18+
let _item: <() as Tr>::Item = 0u8;
19+
20+
let _container: <u16 as Tr>::Container = Vec::<u16>::new();
21+
let _item: <u16 as Tr>::Item = 0u16;
22+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#![feature(associated_type_defaults)]
2+
3+
// Associated type defaults may not be assumed inside the trait defining them.
4+
// ie. they only resolve to `<Self as Tr>::A`, not the actual type `()`
5+
trait Tr {
6+
type A = ();
7+
8+
fn f(p: Self::A) {
9+
let () = p;
10+
//~^ ERROR mismatched types
11+
//~| NOTE expected associated type, found `()`
12+
//~| NOTE expected associated type `<Self as Tr>::A`
13+
//~| NOTE consider constraining
14+
//~| NOTE for more information, visit
15+
}
16+
}
17+
18+
// An impl that doesn't override the type *can* assume the default.
19+
impl Tr for () {
20+
fn f(p: Self::A) {
21+
let () = p;
22+
}
23+
}
24+
25+
impl Tr for u8 {
26+
type A = ();
27+
28+
fn f(p: Self::A) {
29+
let () = p;
30+
}
31+
}
32+
33+
trait AssocConst {
34+
type Ty = u8;
35+
36+
// Assoc. consts also cannot assume that default types hold
37+
const C: Self::Ty = 0u8;
38+
//~^ ERROR mismatched types
39+
//~| NOTE expected associated type, found `u8`
40+
//~| NOTE expected associated type `<Self as AssocConst>::Ty`
41+
//~| NOTE consider constraining
42+
//~| NOTE for more information, visit
43+
}
44+
45+
// An impl can, however
46+
impl AssocConst for () {
47+
const C: Self::Ty = 0u8;
48+
}
49+
50+
fn main() {}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/defaults-in-other-trait-items.rs:9:13
3+
|
4+
LL | let () = p;
5+
| ^^ expected associated type, found `()`
6+
|
7+
= note: expected associated type `<Self as Tr>::A`
8+
found unit type `()`
9+
= note: consider constraining the associated type `<Self as Tr>::A` to `()` or calling a method that returns `<Self as Tr>::A`
10+
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
11+
12+
error[E0308]: mismatched types
13+
--> $DIR/defaults-in-other-trait-items.rs:37:25
14+
|
15+
LL | const C: Self::Ty = 0u8;
16+
| ^^^ expected associated type, found `u8`
17+
|
18+
= note: expected associated type `<Self as AssocConst>::Ty`
19+
found type `u8`
20+
= note: consider constraining the associated type `<Self as AssocConst>::Ty` to `u8` or calling a method that returns `<Self as AssocConst>::Ty`
21+
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/privacy/associated-item-privacy-trait.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ mod priv_trait {
2323
<Pub as PrivTr>::CONST;
2424
//~^ ERROR associated constant `PrivTr::CONST` is private
2525
let _: <Pub as PrivTr>::AssocTy;
26-
//~^ ERROR trait `priv_trait::PrivTr` is private
27-
//~| ERROR trait `priv_trait::PrivTr` is private
26+
//~^ ERROR associated type `PrivTr::AssocTy` is private
2827
pub type InSignatureTy = <Pub as PrivTr>::AssocTy;
2928
//~^ ERROR trait `priv_trait::PrivTr` is private
3029
pub trait InSignatureTr: PrivTr {}
@@ -116,15 +115,11 @@ mod priv_parent_substs {
116115
<Priv as PubTr<_>>::CONST;
117116
//~^ ERROR type `priv_parent_substs::Priv` is private
118117

119-
let _: <Pub as PubTr>::AssocTy;
120-
//~^ ERROR type `priv_parent_substs::Priv` is private
121-
//~| ERROR type `priv_parent_substs::Priv` is private
118+
let _: <Pub as PubTr>::AssocTy; // FIXME no longer an error?!
122119
let _: <Pub as PubTr<_>>::AssocTy;
123120
//~^ ERROR type `priv_parent_substs::Priv` is private
124-
//~| ERROR type `priv_parent_substs::Priv` is private
125121
let _: <Priv as PubTr<_>>::AssocTy;
126122
//~^ ERROR type `priv_parent_substs::Priv` is private
127-
//~| ERROR type `priv_parent_substs::Priv` is private
128123

129124
pub type InSignatureTy1 = <Pub as PubTr>::AssocTy;
130125
//~^ ERROR type `priv_parent_substs::Priv` is private

0 commit comments

Comments
 (0)