Repository navigation
Description
This is a tracking issue for the RFC "Associated type defaults" (rust-lang/rfcs#2532) under the feature gate #![feature(associated_type_defaults)].
The associated item RFC included the ability to provide defaults for associated types, with some tricky rules about how that would influence defaulted methods.
The early implementation of this feature was gated, because there is a widespread feeling that we want a different semantics from the RFC -- namely, that default methods should not be able to assume anything about associated types. This is especially true given the specialization RFC, which provides a much cleaner way of tailoring default implementations.
The new RFC, rust-lang/rfcs#2532, specifies that this should be the new semantics but has not been implemented yet. The existing behavior under #![feature(associated_type_defaults)] is buggy and does not conform to the new RFC. Consult it for a discussion on changes that will be made.
Steps:
- Implement RFC: Associated type defaults rfcs#2532 (cc @rust-lang/wg-traits @rust-lang/compiler)
- Implement RFC 2532 – Associated Type Defaults #61812
- handle
associated_type_defaultsare unsound in the new solver trait-system-refactor-initiative#46 - Implement the changes to object types specified in the RFC
- Improve type mismatch errors when an associated type default can not be projected (Implement RFC 2532 – Associated Type Defaults #61812 (comment))
- Adjust documentation (see instructions on forge)
- Stabilization PR (see instructions on forge)
Unresolved questions:
- 1. When do suitability of defaults need to be proven?
- 2. Where are cycles checked?
- How do associated types interact with supertrait shadowing? (Since stabilizing associated type defaults would make adding associated types a non-breaking change.)
Test checklist
Originally created as a comment on #61812
- Trait objects and defaults
- Independent defaults (
type Foo = u8;)- where not specified (
dyn Trait)- show that it's an error to coerce from
dyn Trait<Foo = u16>to that - show that we assume it is
u8by invoking some method etc
- show that it's an error to coerce from
- where specified (
dyn Trait<Foo = u16>)- show that it's an error to coerce from
dyn Trait<Foo = u16>to that - show that we assume it is
u8by invoking some method etc
- show that it's an error to coerce from
- where not specified (
- Mixed with type without a default (
type Foo = u8; type Bar;)- where neither is specified (
dyn Trait) -- error - where
Foois specified (dyn Trait<Foo = u16>) -- error - where
Baris specified (dyn Trait<Bar = u32>) -- ok, checkFoodefaults tou8 - where both are specified (
dyn Trait<Foo = u16, Bar = u32>) -- ok
- where neither is specified (
- Dependent defaults (
type Foo = u8; type Bar = Vec<Self::Foo>)- where neither is specified (
dyn Trait) -- error - where
Foois specified (dyn Trait<Foo = u16>) -- unclear, maybe an error? - where
Baris specified (dyn Trait<Bar = u32>) -- unclear, maybe an error? - where both are specified (
dyn Trait<Foo = u16, Bar = u32>) -- ok
- where neither is specified (
- Cyclic defaults (
type Foo = Self::Bar; type Bar = Self::Foo)- where neither is specified (
dyn Trait) - where
Foois specified (dyn Trait<Foo = u16>) - where
Baris specified (dyn Trait<Bar = u32>) - where both are specified (
dyn Trait<Foo = u16, Bar = u32>)
- where neither is specified (
- Non-trivial recursive defaults (
type Foo = Vec<Self::Bar>; type Bar = Box<Self::Foo>;)- where neither is specified (
dyn Trait) - where
Foois specified (dyn Trait<Foo = u16>) - where
Baris specified (dyn Trait<Bar = u32>) - where both are specified (
dyn Trait<Foo = u16, Bar = u32>)
- where neither is specified (
- Independent defaults (
- Specialization
- Default values unknown in traits
- trait definition cannot rely on
type Foo = u8;(defaults-in-other-trait-items.rs) - impl for trait that manually specifies can rely
- also, can rely on it from outside the impl
- impl for trait that does not specify can rely
- impl with
default type Foo = u8, cannot rely on that internally (defaults-specialization.rs) - default impl with
type Foo = u8, cannot rely on that internally (defaults-specialization.rs) - impl that specializes but manually specifies can rely
- impl that specializes but does not specify can rely
- right? want also a test that this impl cannot be further specialized -- is "default" inherited, in other words?
- Correct defaults in impls (type)
- Independent defaults (
type Foo = u8;)- overriding one default does not require overriding the others (
associated-types/associated-types-overridden-default.rs)- (does not test that the projections are as expected)
- where not specified (
impl Trait { }) (associated-types/issue-54182-2.rs) - where specified (
impl Trait { type Foo = u16; }) (issue-54182-1.rs)
- overriding one default does not require overriding the others (
- Mixed with type without a default (
type Foo = u8; type Bar;)- where neither is specified (
impl Trait { }) -- error - where
Foois specified (impl Trait { type Foo = u16; }) -- error - where
Baris specified (impl Trait { type Bar = u32; }) -- ok - where both are specified (
impl Trait { type Foo = u16; type Bar = u32; }) -- ok
- where neither is specified (
- Dependent defaults (
type Foo = u8; type Bar = Vec<Self::Foo>) --defaults-in-other-trait-items-pass.rs,defaults-in-other-trait-items-fail.rs- where neither is specified (
impl Trait { }) - where
Foois specified (impl Trait { type Foo = u16; }) - where
Baris specified (impl Trait { type Bar = u32; }) - where both are specified (
impl Trait { type Foo = u16; type Bar = u32; })
- where neither is specified (
- Cyclic defaults (
type Foo = Self::Bar; type Bar = Self::Foo) --defaults-cyclic-fail.rs,defaults-cyclic-pass.rs- where neither is specified (
impl Trait { })- considered to be an error only if a projection takes place (is this what we want?)
- where
Foois specified (impl Trait { type Foo = u16; }) - where
Baris specified (impl Trait { type Bar = u32; }) - where both are specified (
impl Trait { type Foo = u16; type Bar = u32; })
- where neither is specified (
- Non-trivial recursive defaults (
type Foo = Vec<Self::Bar>; type Bar = Box<Self::Foo>;)- where neither is specified (
impl Trait { }) - where
Foois specified (impl Trait { type Foo = u16; }) - where
Baris specified (impl Trait { type Bar = u32; }) - where both are specified (
impl Trait { type Foo = u16; type Bar = u32; })
- where neither is specified (
- Independent defaults (
- Correct defaults in impls (const)
- Independent defaults
- where not specified
- where specified
- Mixed with type without a default
- where neither is specified
- where
Foois specified - where
Baris specified - where both are specified
- Dependent defaults
- where neither is specified
- where
Foois specified - where
Baris specified - where both are specified
- Cyclic defaults --
defaults-cyclic-fail.rs,defaults-cyclic-pass.rs- where neither is specified (
impl Trait { })- considered to be an error only if a projection takes place (is this what we want?)
- where
Foois specified - where
Baris specified - where both are specified
- where neither is specified (
- Non-trivial recursive defaults
- where neither is specified
- where
Foois specified - where
Baris specified - where both are specified
- Independent defaults
- Overflow errors in const evaluation
- check that errors in evaluation do not occur based on default values, but only the final values
- Dependent defaults (defaults-not-assumed-fail, defaults-not-assumed-pass)
- where neither is specified
- where
Foois specified - where
Baris specified - where both are specified
- WF checking (
defaults-suitability.rs)- requires that defaults meet WF check requirements (is this what we want?)
-
typein trait body, bound appears on the item -
typein trait body, type not wf -
typein trait body, bound appears as trait where clause -
default typein impl, bound appears on the item -
typein impl, bound appears on the item -
typein default impl, bound appears on the item -
typein trait body, conditionally wf depending on another default- currently gives an error (is this what we want?)
-
typein trait body, depends on another default whose bounds suffice
Activity
SimonSapin commentedon Jan 25, 2016
aturon commentedon Jan 28, 2016
SimonSapin commentedon Jan 28, 2016
aturon commentedon Jan 29, 2016
aturon commentedon Jan 29, 2016
nikomatsakis commentedon Feb 1, 2016
sunjay commentedon Feb 19, 2017
nikomatsakis commentedon Feb 21, 2017
Kixunil commentedon May 7, 2017
dobkeratops commentedon Jun 20, 2017
dobkeratops commentedon Jun 20, 2017
53 remaining items
StarlarkTypeRepr::Canonical
StarlarkTypeRepr::Canonical
Veetaha commentedon Nov 10, 2024
I've just checked this feature against the compilation benchmarks of my proc-macro crate, that generates a big amount of repetitive trait implementations with associated types. The results of current benchmarks on stable are documented here.
After I updated the macro impl to use associated type defaults this has removed the quadratic growth of the generated source code, and the compilation time improved:
2.096sto0.878s(58% compilation perf. increase)2.340sto1.961s(16% compilation perf. increase)I wonder if it would be possible to stabilize a conservative MVP subset of this feature that assumes:
This would still bring these compilation time improvements to stable
ohsayan commentedon Jun 14, 2025
It seems like rust-lang/trait-system-refactor-initiative/issues/46 has been resolved.
mqudsi commentedon Nov 1, 2025
Does the current syntax rob us of a way to use trait-defined types? Take a look at this sample:
that could be used by users of implementations of
Fooas type aliases to simplify interacting withFootypes.That's still doable if the syntax is interpreted as "default type" instead of "type alias", but does it rob us of using it that way in the future? Would it require a different proposal to "lock down" the type definition or would you just be SOL if you tried to redefine the "default associated type" instead of going with what the default was?
Rollup merge of rust-lang#152385 - LaneAsade:gate-type-const-defaults…
Rollup merge of rust-lang#152385 - LaneAsade:gate-type-const-defaults…
Rollup merge of rust-lang#152385 - LaneAsade:gate-type-const-defaults…
Unrolled build for #152385
remove associated_type_defaults feature
Merge tock#2325 tock#2346
feat(actor): add FfiActor::Config delivered at init, symmetric with N…
feat(tools): typed tool-arg validation via TypedTool + self-correctio…
feat(rs)!: generated types are #[non_exhaustive] with builders, and a…