Skip to content

Implement RFC 2532 – Associated Type Defaults #61812

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

Merged
merged 31 commits into from
Feb 26, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a323ff2
Implement RFC 2532 – Associated Type Defaults
jonas-schievink Jun 13, 2019
a549bbd
Add regression test for #54182
jonas-schievink Jun 13, 2019
37686ed
Add comments and assertions to tests
jonas-schievink Jun 13, 2019
de447eb
Add tests for assoc. const defaults
jonas-schievink Jun 13, 2019
1e3c020
Test interactions with specialization
jonas-schievink Jun 14, 2019
d3be26d
Improve test
jonas-schievink Jun 14, 2019
c73ee98
Check suitability of the provided default
jonas-schievink Jun 15, 2019
f403882
Add a `Self: Sized` bound
jonas-schievink Jun 15, 2019
5e9317a
Put the check into its own function
jonas-schievink Jun 15, 2019
ff5d11e
Add comments and tests explaining the shallow substitution rule
jonas-schievink Jun 16, 2019
07ad64f
Add tests for #62211
jonas-schievink Jun 28, 2019
fead458
Fix tests after rebase
jonas-schievink Aug 29, 2019
485111c
Add regression tests for issues
jonas-schievink Aug 29, 2019
1f61f36
Add comment about the shallow subst rule
jonas-schievink Aug 29, 2019
fd28614
Add regression test for #26681
jonas-schievink Sep 14, 2019
c964520
Update tests after compiletest changes
jonas-schievink Sep 15, 2019
3f03d95
Improve associated-types-overridden-default.rs
jonas-schievink Sep 15, 2019
f408794
Improve defaults-in-other-trait-items-pass
jonas-schievink Sep 15, 2019
fbcd136
Improve the cycle tests
jonas-schievink Sep 14, 2019
c8da9ee
Improve specialization test
jonas-schievink Sep 15, 2019
24ec364
Test mixed default and non-default
jonas-schievink Sep 15, 2019
f94eaea
Fix rebase damage
jonas-schievink Oct 7, 2019
708f053
Add test for #65774
jonas-schievink Nov 24, 2019
a01846f
appease tidy
jonas-schievink Nov 24, 2019
ec50190
Bless test output
jonas-schievink Dec 8, 2019
232c1f3
Format code
jonas-schievink Jan 5, 2020
9930e1f
Fix tests that fail with `--emit metadata`
jonas-schievink Jan 5, 2020
4d4da92
Fix rebase damage
jonas-schievink Feb 15, 2020
af2931b
Mark E0399 test as obsolete
jonas-schievink Feb 21, 2020
c605831
Fix rebase fallout
jonas-schievink Feb 21, 2020
6cc268b
Mark E0399.md as obsolete
jonas-schievink Feb 21, 2020
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
Next Next commit
Implement RFC 2532 – Associated Type Defaults
  • Loading branch information
jonas-schievink committed Feb 21, 2020
commit a323ff2c864801fdc8e044e88f11efb49a565ed1
43 changes: 29 additions & 14 deletions src/librustc_infer/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,25 +1054,40 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// an error when we confirm the candidate
// (which will ultimately lead to `normalize_to_error`
// being invoked).
node_item.item.defaultness.has_value()
false
} else {
// If we're looking at a trait *impl*, the item is
// specializable if the impl or the item are marked
// `default`.
node_item.item.defaultness.is_default()
|| super::util::impl_is_default(selcx.tcx(), node_item.node.def_id())
};

// Only reveal a specializable default if we're past type-checking
// and the obligations is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
if !is_default {
true
} else if obligation.param_env.reveal == Reveal::All {
// NOTE(eddyb) inference variables can resolve to parameters, so
// assume `poly_trait_ref` isn't monomorphic, if it contains any.
let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(&poly_trait_ref);
!poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst()
} else {
false
match is_default {
// Non-specializable items are always projectable
false => true,

// Only reveal a specializable default if we're past type-checking
// and the obligation is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
true if obligation.param_env.reveal == Reveal::All => {
// NOTE(eddyb) inference variables can resolve to parameters, so
// assume `poly_trait_ref` isn't monomorphic, if it contains any.
let poly_trait_ref =
selcx.infcx().resolve_vars_if_possible(&poly_trait_ref);
!poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst()
}

true => {
debug!(
"assemble_candidates_from_impls: not eligible due to default: \
assoc_ty={} predicate={}",
selcx.tcx().def_path_str(node_item.item.def_id),
obligation.predicate,
);
false
}
}
}
super::VtableParam(..) => {
Expand Down
21 changes: 0 additions & 21 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1964,7 +1964,6 @@ fn check_impl_items_against_trait<'tcx>(

// Locate trait definition and items
let trait_def = tcx.trait_def(impl_trait_ref.def_id);
let mut overridden_associated_type = None;

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

Expand Down Expand Up @@ -2046,9 +2045,6 @@ fn check_impl_items_against_trait<'tcx>(
hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(_) => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
if ty_trait_item.kind == ty::AssocKind::Type {
if ty_trait_item.defaultness.has_value() {
overridden_associated_type = Some(impl_item);
}
compare_ty_impl(
tcx,
&ty_impl_item,
Expand Down Expand Up @@ -2082,8 +2078,6 @@ fn check_impl_items_against_trait<'tcx>(

// Check for missing items from trait
let mut missing_items = Vec::new();
let mut invalidated_items = Vec::new();
let associated_type_overridden = overridden_associated_type.is_some();
for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
let is_implemented = trait_def
.ancestors(tcx, impl_id)
Expand All @@ -2094,28 +2088,13 @@ fn check_impl_items_against_trait<'tcx>(
if !is_implemented && !traits::impl_is_default(tcx, impl_id) {
if !trait_item.defaultness.has_value() {
missing_items.push(*trait_item);
} else if associated_type_overridden {
invalidated_items.push(trait_item.ident);
}
}
}

if !missing_items.is_empty() {
missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
}

if !invalidated_items.is_empty() {
let invalidator = overridden_associated_type.unwrap();
struct_span_err!(
tcx.sess,
invalidator.span,
E0399,
"the following trait items need to be reimplemented as `{}` was overridden: `{}`",
invalidator.ident,
invalidated_items.iter().map(|name| name.to_string()).collect::<Vec<_>>().join("`, `")
)
.emit();
}
}

fn missing_items_err(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// check-pass

// Before RFC 2532, overriding one assoc. type default required overriding all
// provided defaults.

#![feature(associated_type_defaults)]

pub trait Tr {
Expand All @@ -9,7 +14,6 @@ pub trait Tr {

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

fn main() {}

This file was deleted.

35 changes: 35 additions & 0 deletions src/test/ui/associated-types/defaults-cyclic-fail.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#![feature(associated_type_defaults)]

// Having a cycle in assoc. type defaults is okay...
trait Tr {
type A = Self::B;
type B = Self::A;
}

// ...but is an error in any impl that doesn't override at least one of the defaults
impl Tr for () {}
//~^ ERROR overflow evaluating the requirement

// As soon as at least one is redefined, it works:
impl Tr for u8 {
type A = u8;
}

impl Tr for u32 {
type A = ();
type B = u8;
}

// ...but only if this actually breaks the cycle
impl Tr for bool {
//~^ ERROR overflow evaluating the requirement
type A = Box<Self::B>;
//~^ ERROR overflow evaluating the requirement
}
// (the error is shown twice for some reason)

fn main() {
// Check that the overridden type propagates to the other
let _a: <u8 as Tr>::A = 0u8;
let _b: <u8 as Tr>::B = 0u8;
}
21 changes: 21 additions & 0 deletions src/test/ui/associated-types/defaults-cyclic-fail.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0275]: overflow evaluating the requirement `<() as Tr>::B`
--> $DIR/defaults-cyclic-fail.rs:10:6
|
LL | impl Tr for () {}
| ^^

error[E0275]: overflow evaluating the requirement `<bool as Tr>::B`
--> $DIR/defaults-cyclic-fail.rs:24:6
|
LL | impl Tr for bool {
| ^^

error[E0275]: overflow evaluating the requirement `<bool as Tr>::B`
--> $DIR/defaults-cyclic-fail.rs:26:5
|
LL | type A = Box<Self::B>;
| ^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0275`.
22 changes: 22 additions & 0 deletions src/test/ui/associated-types/defaults-cyclic-pass.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// check-pass

#![feature(associated_type_defaults)]

trait Tr {
type Item = u8;
type Container = Vec<Self::Item>;
}

impl Tr for () {}

impl Tr for u16 {
type Item = u16;
}

fn main() {
let _container: <() as Tr>::Container = Vec::<u8>::new();
let _item: <() as Tr>::Item = 0u8;

let _container: <u16 as Tr>::Container = Vec::<u16>::new();
let _item: <u16 as Tr>::Item = 0u16;
}
50 changes: 50 additions & 0 deletions src/test/ui/associated-types/defaults-in-other-trait-items.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#![feature(associated_type_defaults)]

// Associated type defaults may not be assumed inside the trait defining them.
// ie. they only resolve to `<Self as Tr>::A`, not the actual type `()`
trait Tr {
type A = ();

fn f(p: Self::A) {
let () = p;
//~^ ERROR mismatched types
//~| NOTE expected associated type, found `()`
//~| NOTE expected associated type `<Self as Tr>::A`
//~| NOTE consider constraining
//~| NOTE for more information, visit
}
}

// An impl that doesn't override the type *can* assume the default.
impl Tr for () {
fn f(p: Self::A) {
let () = p;
}
}

impl Tr for u8 {
type A = ();

fn f(p: Self::A) {
let () = p;
}
}

trait AssocConst {
type Ty = u8;

// Assoc. consts also cannot assume that default types hold
const C: Self::Ty = 0u8;
//~^ ERROR mismatched types
//~| NOTE expected associated type, found `u8`
//~| NOTE expected associated type `<Self as AssocConst>::Ty`
//~| NOTE consider constraining
//~| NOTE for more information, visit
}

// An impl can, however
impl AssocConst for () {
const C: Self::Ty = 0u8;
}

fn main() {}
25 changes: 25 additions & 0 deletions src/test/ui/associated-types/defaults-in-other-trait-items.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
error[E0308]: mismatched types
--> $DIR/defaults-in-other-trait-items.rs:9:13
|
LL | let () = p;
| ^^ expected associated type, found `()`
|
= note: expected associated type `<Self as Tr>::A`
found unit type `()`
= note: consider constraining the associated type `<Self as Tr>::A` to `()` or calling a method that returns `<Self as Tr>::A`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error[E0308]: mismatched types
--> $DIR/defaults-in-other-trait-items.rs:37:25
|
LL | const C: Self::Ty = 0u8;
| ^^^ expected associated type, found `u8`
|
= note: expected associated type `<Self as AssocConst>::Ty`
found type `u8`
= note: consider constraining the associated type `<Self as AssocConst>::Ty` to `u8` or calling a method that returns `<Self as AssocConst>::Ty`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0308`.
9 changes: 2 additions & 7 deletions src/test/ui/privacy/associated-item-privacy-trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ mod priv_trait {
<Pub as PrivTr>::CONST;
//~^ ERROR associated constant `PrivTr::CONST` is private
let _: <Pub as PrivTr>::AssocTy;
//~^ ERROR trait `priv_trait::PrivTr` is private
//~| ERROR trait `priv_trait::PrivTr` is private
//~^ ERROR associated type `PrivTr::AssocTy` is private
pub type InSignatureTy = <Pub as PrivTr>::AssocTy;
//~^ ERROR trait `priv_trait::PrivTr` is private
pub trait InSignatureTr: PrivTr {}
Expand Down Expand Up @@ -116,15 +115,11 @@ mod priv_parent_substs {
<Priv as PubTr<_>>::CONST;
//~^ ERROR type `priv_parent_substs::Priv` is private

let _: <Pub as PubTr>::AssocTy;
//~^ ERROR type `priv_parent_substs::Priv` is private
//~| ERROR type `priv_parent_substs::Priv` is private
let _: <Pub as PubTr>::AssocTy; // FIXME no longer an error?!
let _: <Pub as PubTr<_>>::AssocTy;
//~^ ERROR type `priv_parent_substs::Priv` is private
//~| ERROR type `priv_parent_substs::Priv` is private
let _: <Priv as PubTr<_>>::AssocTy;
//~^ ERROR type `priv_parent_substs::Priv` is private
//~| ERROR type `priv_parent_substs::Priv` is private

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