Skip to content

Tracking issue for RFC 2532, "Associated type defaults" #29661

Open

Description

@aturon

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:

Unresolved questions:

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 u8 by invoking some method etc
      • 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 u8 by invoking some method etc
    • Mixed with type without a default (type Foo = u8; type Bar;)
      • where neither is specified (dyn Trait) -- error
      • where Foo is specified (dyn Trait<Foo = u16>) -- error
      • where Bar is specified (dyn Trait<Bar = u32>) -- ok, check Foo defaults to u8
      • where both are specified (dyn Trait<Foo = u16, Bar = u32>) -- ok
    • Dependent defaults (type Foo = u8; type Bar = Vec<Self::Foo>)
      • where neither is specified (dyn Trait) -- error
      • where Foo is specified (dyn Trait<Foo = u16>) -- unclear, maybe an error?
      • where Bar is specified (dyn Trait<Bar = u32>) -- unclear, maybe an error?
      • where both are specified (dyn Trait<Foo = u16, Bar = u32>) -- ok
    • Cyclic defaults (type Foo = Self::Bar; type Bar = Self::Foo)
      • where neither is specified (dyn Trait)
      • where Foo is specified (dyn Trait<Foo = u16>)
      • where Bar is specified (dyn Trait<Bar = u32>)
      • where both are specified (dyn Trait<Foo = u16, Bar = u32>)
    • Non-trivial recursive defaults (type Foo = Vec<Self::Bar>; type Bar = Box<Self::Foo>;)
      • where neither is specified (dyn Trait)
      • where Foo is specified (dyn Trait<Foo = u16>)
      • where Bar is specified (dyn Trait<Bar = u32>)
      • where both are specified (dyn Trait<Foo = u16, Bar = u32>)
  • 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)
    • Mixed with type without a default (type Foo = u8; type Bar;)
      • where neither is specified (impl Trait { }) -- error
      • where Foo is specified (impl Trait { type Foo = u16; }) -- error
      • where Bar is specified (impl Trait { type Bar = u32; }) -- ok
      • where both are specified (impl Trait { type Foo = u16; type Bar = u32; }) -- ok
    • 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 Foo is specified (impl Trait { type Foo = u16; })
      • where Bar is specified (impl Trait { type Bar = u32; })
      • where both are specified (impl Trait { type Foo = u16; type Bar = u32; })
    • 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 Foo is specified (impl Trait { type Foo = u16; })
      • where Bar is specified (impl Trait { type Bar = u32; })
      • where both are specified (impl Trait { type Foo = u16; type Bar = u32; })
    • Non-trivial recursive defaults (type Foo = Vec<Self::Bar>; type Bar = Box<Self::Foo>;)
      • where neither is specified (impl Trait { })
      • where Foo is specified (impl Trait { type Foo = u16; })
      • where Bar is specified (impl Trait { type Bar = u32; })
      • where both are specified (impl Trait { type Foo = u16; type Bar = u32; })
  • Correct defaults in impls (const)
    • Independent defaults
      • where not specified
      • where specified
    • Mixed with type without a default
      • where neither is specified
      • where Foo is specified
      • where Bar is specified
      • where both are specified
    • Dependent defaults
      • where neither is specified
      • where Foo is specified
      • where Bar is 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 Foo is specified
      • where Bar is specified
      • where both are specified
    • Non-trivial recursive defaults
      • where neither is specified
      • where Foo is specified
      • where Bar is specified
      • where both are specified
  • 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 Foo is specified
      • where Bar is specified
      • where both are specified
  • WF checking (defaults-suitability.rs)
    • requires that defaults meet WF check requirements (is this what we want?)
    • type in trait body, bound appears on the item
    • type in trait body, type not wf
    • type in trait body, bound appears as trait where clause
    • default type in impl, bound appears on the item
    • type in impl, bound appears on the item
    • type in default impl, bound appears on the item
    • type in trait body, conditionally wf depending on another default
      • currently gives an error (is this what we want?)
    • type in trait body, depends on another default whose bounds suffice

Activity

  1. added
    T-langRelevant to the language team
    B-unstableBlocker: Implemented in the nightly compiler and unstable.
    on Nov 6, 2015
  2. SimonSapin commented on Jan 25, 2016

    @SimonSapin
  3. aturon commented on Jan 28, 2016

    @aturon
    Author
  4. SimonSapin commented on Jan 28, 2016

    @SimonSapin
  5. aturon commented on Jan 29, 2016

    @aturon
    Author
  6. aturon commented on Jan 29, 2016

    @aturon
    Author
  7. nikomatsakis commented on Feb 1, 2016

    @nikomatsakis
  8. added
    B-RFC-implementedBlocker: Approved by a merged RFC and implemented but not stabilized.
    on Aug 29, 2016
  9. sunjay commented on Feb 19, 2017

    @sunjay
  10. nikomatsakis commented on Feb 21, 2017

    @nikomatsakis
  11. Kixunil commented on May 7, 2017

    @Kixunil
  12. dobkeratops commented on Jun 20, 2017

    @dobkeratops
  13. dobkeratops commented on Jun 20, 2017

    @dobkeratops
  14. added
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    on Jul 22, 2017
  15. 53 remaining items

  16. Veetaha commented on Nov 10, 2024

    @Veetaha
    Contributor

    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:

    • "10 structs with 50 fields" decreased from 2.096s to 0.878s (58% compilation perf. increase)
    • "100 structs with 10 fields" decreased from 2.340s to 1.961s (16% compilation perf. increase)

    I wonder if it would be possible to stabilize a conservative MVP subset of this feature that assumes:

    • non-object-safe traits
    • definition-site checks for defaults suitability
    • definition-site checks for cycles

    This would still bring these compilation time improvements to stable

  17. ohsayan commented on Jun 14, 2025

    @ohsayan
    Contributor
  18. mqudsi commented on Nov 1, 2025

    @mqudsi
    Contributor

    Does the current syntax rob us of a way to use trait-defined types? Take a look at this sample:

    trait Foo { 
        type Foo: Constraint;
        type Bar: Constraint;
        ...
        type Baz: Constraint;
    
        type Sender = std::sync::mpsc::Sender<long type declaration here, that mixes and matches between other associated types of trait Foo>;
    }

    that could be used by users of implementations of Foo as type aliases to simplify interacting with Foo types.

    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?

  19. added
    T-typesRelevant to the types team, which will review and decide on the PR/issue.
    on Feb 14, 2026
  20. added 3 commits that reference this issue on Feb 22, 2026
  21. added a commit that references this issue on Feb 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-associated-itemsArea: Associated items (types, constants & functions)B-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.B-unstableBlocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCF-associated_type_defaults`#![feature(associated_type_defaults)]`S-tracking-needs-summaryStatus: It's hard to tell what's been done and what hasn't! Someone should do some investigation.T-langRelevant to the language teamT-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions