Tracking issue for inherent associated types
When developing a type-parametric impl, I found myself writing code somewhat like this:
struct Grammar<T, NT> { ... }
impl<T:Clone,NT:Eq+Hash+Clone+Primable> Grammar<T,NT> {
fn to_nt_map(&self) -> HashMap<NT, ~[Prod<T,NT>]>
{
type Rules = ~[Prod<T,NT>];
type NTMap = HashMap<NT, Rules>;
...
}
fn from_nt_map(start: &NT, rules: &HashMap<NT, ~[Prod<T,NT>]>)
-> Grammar<T,NT>
{
type Rules = ~[Prod<T,NT>];
type NTMap = HashMap<NT, Rules>;
...
}
pub fn eliminate_left_recursion(&self) -> Grammar<T,NT>
{
...
}
...
}
I cannot make a type definition for HashMap<NT, ~[Prod<T,NT>]> outside of the impl because it then those free references to NT and T would be unbound.
And I cannot put a type definition within the impl, even an impl for a struct such as this (it simply does not parse with the current grammar).
(Being able to put type definitions within impls will probably arise naturally from #5033, when we get around to that. But that is nonetheless a separate issue from this: Associated Types (and Associated Items) are about enabling certain patterns for the user of a trait, while this ticket describes a convenience for the implementor of a struct.)
This is a tracking issue for the "inherent associate type" part of "inherent associated items" part of the RFC 195 "associated items"
About tracking issues
Tracking issues are used to record the overall progress of implementation. They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
Original description
(This code is written in ancient version of Rust, and is not meant to be used directly.)
When developing a type-parametric impl, I found myself writing code somewhat like this:
struct Grammar<T, NT> { ... } impl<T:Clone,NT:Eq+Hash+Clone+Primable> Grammar<T,NT> { fn to_nt_map(&self) -> HashMap<NT, ~[Prod<T,NT>]> { type Rules = ~[Prod<T,NT>]; type NTMap = HashMap<NT, Rules>; ... } fn from_nt_map(start: &NT, rules: &HashMap<NT, ~[Prod<T,NT>]>) -> Grammar<T,NT> { type Rules = ~[Prod<T,NT>]; type NTMap = HashMap<NT, Rules>; ... } pub fn eliminate_left_recursion(&self) -> Grammar<T,NT> { ... } ... }I cannot make a
typedefinition forHashMap<NT, ~[Prod<T,NT>]>outside of theimplbecause it then those free references toNTandTwould be unbound.And I cannot put a
typedefinition within the impl, even an impl for a struct such as this (it simply does not parse with the current grammar).(Being able to put type definitions within impls will probably arise naturally from #5033, when we get around to that. But that is nonetheless a separate issue from this: Associated Types (and Associated Items) are about enabling certain patterns for the user of a trait, while this ticket describes a convenience for the implementor of a struct.)
Steps
<!-- Include each step required to complete the feature. Typically this is a PR implementing a feature, followed by a PR that stabilises the feature. However for larger features an implementation could be broken up into multiple PRs. -->- [ ] Implement the RFC
- [ ] Adjust documentation (see instructions on rustc-dev-guide)
- [ ] Stabilization PR (see instructions on rustc-dev-guide)
Unresolved Questions
<!-- Include any open questions that need to be answered before the feature can be stabilised. -->Implementation history
- #82516
- #103621
- #104348
- #105224
- #105315
- #105768
- #105961
- #109410
- #110945
- #111486
- #114594
- #118118
- #118262
Felix S Klock II at 2019-01-31 10:43:11
Nominating; is backwards compatible. I can try and take this on if we decide we want it.
emberian at 2013-12-30 22:18:45
(type aliases would need to preceed all methods)
emberian at 2013-12-30 22:19:11
@cmr said "(type aliases would need to preceed all methods)"
why? To my knowledge there is no such ordering constraint for type aliases within a mod item, so why would an impl item require this?
Felix S Klock II at 2013-12-31 01:19:51
@pnkfelix yikes, you're right. I think they should be. Why? Because:
#[crate_type="lib"]; mod bar { fn foo() -> T { 32i } type T = int; }is crazy.
emberian at 2013-12-31 05:20:33
Why is that less crazy than
fn foo() { bar() } fn bar() {}?
Huon Wilson at 2013-12-31 06:05:32
I cede.
On Tue, Dec 31, 2013 at 1:05 AM, Huon Wilson notifications@github.comwrote:
Why is that less crazy than
fn foo() { bar() } fn bar() {}
?
— Reply to this email directly or view it on GitHubhttps://github.com/mozilla/rust/issues/8995#issuecomment-31385141 .
emberian at 2013-12-31 17:20:30
assigning P-low priority (is backwards compatible going foward, as cmr said).
Felix S Klock II at 2014-01-09 18:15:23
Triage: How does this interact with Associated Types? At least a new syntax would probably have to be chosen.
Jonathan Reem at 2014-09-15 21:14:20
I think that this feature request is actually satisfied by the Associated Items RFC.
In particular, the section "inherent associated items" of RFC 59 implies (to me) that you can write the exact example that I had asked for.
(I did write in the issue description that this feature request is distinct from associated types, but nonetheless, it seems that the author of RFC 59 decided that it was a natural feature to include.)
Felix S Klock II at 2014-10-06 15:41:16
So, this now seems to be a subissue of #17307.
I will change the title to "implement inherent associated items."
Felix S Klock II at 2014-10-06 15:44:38
Hello, I hope this the right place to ask for my request.
Associated types currently only work with traits. I think they are also useful for structs. Is there a reason for the current limitation ?
pub struct GenericStruct<A, B> { fa : A, fb : B, } struct GenericResult<A, B> { fa : A, fb : B, } impl <A, B> GenericStruct<A, B> { // I d like to write // type Result = Option<GenericResult<A, B>>; // and use it in the code fn new(a: A, b : B) -> Option<GenericResult<A, B>> { Some(GenericResult {fa: a, fb : b}) } }Michaël Melchiore at 2015-08-14 15:27:22
I'm going to tag this with the tags from https://github.com/rust-lang/rust/issues/8995 since it was closed without this being implemented.
Steve Klabnik at 2017-02-07 20:31:07
@steveklabnik I think you meant to reference #17307 rather than #8995, which is this issue.
Gabriel Smith at 2018-01-08 19:29:33
note that inherent associated consts work perfectly fine today
#[derive(Debug)] struct Vector { x: f32, y: f32, z: f32, } impl Vector { const ZERO: Self = Vector { x: 0.0, y: 0.0, z: 0.0 }; fn new(x: f32, y: f32, z: f32) -> Self { Vector { x, y, z } } }tinaun at 2018-01-22 03:09:31
@nikomatsakis Is it right to assume that this can't be implemented without lazy normalization?
Eduard-Mihai Burtescu at 2018-08-20 04:50:20
It would be good to link to this issue in the error message for https://doc.rust-lang.org/nightly/error-index.html#E0202, as it's not immediately clear that this is supposed to be supported.
varkor at 2019-01-08 18:17:01
Any developments on this lately?
Alexander Regueiro at 2019-01-28 16:54:51
~~Ran into this limitation today. A simplified example of what I'm trying to do:~~
trait GenericBackend { type ParentObject: GenericParentObject<Self>; type ChildObject: GenericChildObject<Self>; fn parent() -> Self::ParentObject; } trait GenericParentObject<Backend: GenericBackend> { fn get_children(&self) -> Vec<Backend::ChildObject>; } trait GenericChildObject<Backend: GenericBackend> { }~~Defining the traits works, but trying to impl them leads to an error referencing this issue.~~
~~Would like to see this implemented!~~
Nevermind. What I was trying to do works. I just put "impl MyStruct" instead of "impl MyTrait for MyStruct"...
Alex Parrill at 2019-05-04 04:51:47
Blocked on https://github.com/rust-lang/rust/issues/60471 (Lazy normalization).
Vadim Petrochenkov at 2019-05-04 08:57:36
Any updates?
Alexander Zaitsev at 2020-09-06 21:22:57
It would be great to get this in some form, it can make generic programming a lot easier.
Suppose I have a generic struct, and I need to implement several functions on it which all refer to the same "complex" type in their return parameters or arguments, and the type depends on generic parameters. This is a pretty common situation. Naturally I'd like to give that type a nice name and avoid typing it repeatedly.
But, there is no where for that declaration to go if it depends on the generic parameters of the struct.
- It cannot go in the
structdeclaration itself because type aliases in astructare not allowed. - It cannot go in the inherent impl, because of this issue.
- It cannot even be a type alias defined in a function body, "because it depends on an outer parameter"
It seems I have to either (1) Make an entirely new trait just for this, and make my type an associated type of that trait (2) Use a macro (3) Just give up and type it out repeatedly
It's frustrating because in other languages there are better ways
Chris Beck at 2020-09-15 00:20:14
- It cannot go in the
For the sake of updating status for people driving by, since it wasn't even linked to this issue at all, the latest progress I believe was made in #82516 which implemented the basics of defining inherent associated types but does not allow their use yet.
Gray Olson at 2022-10-14 11:51:46
Wow this issue is open since 2013. Does anyone know when it's going to make it to stable?
chichid at 2022-10-23 04:15:09
For the sake of updating status for people driving by, since it wasn't even linked to this issue at all, the latest progress I believe was made in #82516 which implemented the basics of defining inherent associated types but does not allow their use yet.
Well it is :) that PR has
F-inherent_associated_typeslabel and this tracking issue listed it in the "Implementation History" section.Does anyone know when it's going to make it to stable?
It's not yet implemented :(
Charles Lew at 2022-10-23 04:21:55
This feature could use a form of
doc(inline)for rustdoc, so when defining associated types that are only reachable from there, the documentation for the type would still be accessible.crumblingstatue at 2022-11-10 15:12:35
For example, here is rendered documentation for "associated enums" for the C++ API,
sf::BlendMode:
The rendered documentation for the Rust binding, using the experimental associated_types feature:

Ideally, the type definition could be inlined when
doc(inline)attribute is present on the associated type item.Optionally, there could be an automatic inlining, similar to when re-exports re-export something that is only reachable through that re-export, the docs get inlined without having to do anything special.
crumblingstatue at 2022-11-10 15:16:07
Were there any changes made to this in one of last releases?
struct Foo { bar: Self::Bar, } impl Foo { pub type Bar = usize; }used to work a couple of nightly releases ago.
Now it fails to compile with error:
error[E0391]: cycle detected when computing predicates of `Foo` --> src\main.rs:5:1 | 5 | struct Foo { | ^^^^^^^^^^ | note: ...which requires computing predicates of `Foo`... --> src\main.rs:5:1 | 5 | struct Foo { | ^^^^^^^^^^ note: ...which requires computing inferred outlives predicates of `Foo`... --> src\main.rs:5:1 | 5 | struct Foo { | ^^^^^^^^^^ = note: ...which requires computing the inferred outlives predicates for items in this crate... note: ...which requires computing type of `Foo::bar`... --> src\main.rs:6:5 | 6 | bar: Self::Bar, | ^^^^^^^^^^^^^^ note: ...which requires computing normalized predicates of `Foo`... --> src\main.rs:5:1 | 5 | struct Foo { | ^^^^^^^^^^ = note: ...which again requires computing predicates of `Foo`, completing the cycle note: cycle used when collecting item types in top-level modulePaweł Kubrak at 2023-02-26 11:08:15
I am just curious about the status of this issue. Is someone working on this or has someone made any progress in this space?
Flouet at 2023-02-26 12:27:41
There's been a recent series of PRs that work towards fully implementing inherent associated types by @fee1-dead, @cjgillot and me.
- #103621
- #104348
- #105224
- #105315
- #105768
- #105961
I highly suspect that the last one on that list (#105961) broke the code posted above. @peku33, could you please open an issue for the cycle error and tag me? Thanks. Note however that
inherent_associated_typesis still an incomplete feature and thus it's likely to break every so often.Is someone working on this or has someone made any progress in this space?
@flouet-company, I'm assigned to several issues related to IATs and I'm in close contact with some members of T-types in order to properly implement inherent associated types.
León Orell Valerian Liehr at 2023-02-26 13:18:09
I'd just like to say thank you to you three for working on this feature! I know it's not simple, but it's something a lot of people will appreciate when it's eventually completed.
Jacob Pratt at 2023-02-26 19:55:22
This seems particularly important for resolving 'clippy::type_complexity' when using large types inside parameterized types with multiple arguments.
Normally we'd use a
type Foo = Bar<A, B, C>;but in a generic type, those types may not be accessible except via more type parameters, leading to new complex types.Keep to hear more about blockers :)
Jay Pratt at 2023-05-30 12:32:57
Keep to hear more about blockers
The most recent major blocker is fixing #108491 which is not easy it seems. Basically, you cannot use inherent associated types inside of structs, enums, unions or where clauses (as opposed to function bodies, constants and type aliases) and some function signatures without encountering a cycle error first. According to my current understanding this is due to architectural limitations in the compiler (see this semi-related Zulip topic, cc #22519 the equivalent for trait assoc tys).
Since #109410 got merged, I'm investigating approaches to solve this in a proper way without too much rework.
León Orell Valerian Liehr at 2023-05-30 22:26:32