Skip to content

Tracking issue for Self and associated types in struct expressions and patterns #37544

Description

@petrochenkov

I'm going to add a feature gate according to #37035 (comment), this is a corresponding tracking issue.

Activity

  1. crumblingstatue commented on Nov 3, 2016

    @crumblingstatue
    Contributor

    This doesn't feel complete to me without also allowing Self for tuple and unit-like struct, and enum expressions. It just feels very inconsistent being able to do fn new() -> Self { Self { ... } }, but not fn new() -> Self { Self(...) }, fn new() -> Self { Self }, and fn new() -> Self { Self::Variant }.

    I was looking forward to this feature, so I don't have to repeat type names in as many places, but in its current state this is too inconsistent to be widely applicable.

  2. petrochenkov commented on Nov 3, 2016

    @petrochenkov
    ContributorAuthor

    Self::Variant (and Alias::Variant in general) is in the queue (#26264), it's just not implemented yet.

    Self(..) for struct S(); or Self for struct S; would be some kind of new language entity, value alias (different from just a constant) referring to the original value - struct constructor. It's certainly can be hacked into the compiler, but I'd like to have some more foundation under it and see wider picture - how else these value aliases can be used, how they are related to possible pattern aliases, etc.

  3. crumblingstatue commented on Nov 3, 2016

    @crumblingstatue
    Contributor

    Self::Variant (and Alias::Variant in general) is in the queue (#26264), it's just not implemented yet.

    👍

    Self(..) for struct S(); or Self for struct S; would be some kind of new language entity, value alias...

    I don't want to get off-topic here, but I find it odd that a type alias does not give you the full capabilities that you can do when using the original type name.

    When one says struct Foo, does that not only create a new type, but also some kind of special entity that allows value construction that is different than a type, and these two things are under the same name? Is there a fundamental reason why a type itself cannot be used for these purposes? If this is too complicated to answer here, that's okay. I don't want to hijack this thread too much.

  4. petrochenkov commented on Nov 4, 2016

    @petrochenkov
    ContributorAuthor

    @crumblingstatue

    Is there a fundamental reason why a type itself cannot be used for these purposes?

    It's possible, just messy.
    Suppose, for example, that we have an expression

    A::B(0, 1)
    

    It may a function call, or it may be a tuple struct construction.
    We need to resolve A::B to understand what is it.
    Rust have two primary namespaces - one is for types, and the other is for values. This is pretty fundamental thing that can't be changed backward compatibly.
    Functions are defined in value namespace and types like structs are defined in type namespace.

    If the "type itself" is used for looking up tuple struct constructors, then we need:

    • Search A::B in both namespaces, this kind of contradicts to the point of namespaces.

    • Set up namespace priorities. What if both function A::B and struct A::B exist? Should we prefer one of them or report an error?

    • Ok, suppose we prefer a function. Now we need to resolve A::B in value namespace and if this resolution fails, then we need to resolve it again in type namespace.
      Name resolution happens in two phases:

      • Primary resolution pass, based only on names, used for everything except for associated items.
      • Resolution in type checking, used for associated items (method resolution, etc.), this jumps through various type checking hoops (trait selection, inherent impls, parameter substitution, autoderef for methods) to find the correct resolution.

      If A::B is not resolved in value namespace during the first pass, then we can't simply search type namespace, because A::B may be, for example, a method. We need to record partial resolutions in both namespaces and proceed to type checking when full resolution is completed and we select a function if it's found and a type otherwise.

    Instead of doing all this, tuple/unit structs define additional function/constant-like items in value namespace which then used during resolution of A::B(0, 1), but can also be used in other ways like normal functions/constants. So, namespaces stay clearly separated and there's no need to disambiguate between types and values and keep both resolutions until type checking. But it's still possible to implement this fall back to types backward compatibly, even now.

  5. added a commit that references this issue on Nov 5, 2016
  6. added
    B-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.
    B-unstableBlocker: Implemented in the nightly compiler and unstable.
    T-langRelevant to the language team
    on Nov 14, 2016
  7. 4 remaining items

  8. nrc commented on Nov 15, 2016

    @nrc
    Member

    My main concern is that perhaps it is confusing to allow types (and not just structs) at all!

    This is my concern too, however, my understanding is that this ship sailed some time ago and we allow all sorts of things in the ident position of a struct literal.

  9. nikomatsakis commented on Nov 17, 2016

    @nikomatsakis
    Contributor

    @nrc

    This is my concern too, however, my understanding is that this ship sailed some time ago and we allow all sorts of things in the ident position of a struct literal.

    Off hand I'm not sure what you mean... have an example? Do we allow e.g. type aliases?

  10. nrc commented on Nov 20, 2016

    @nrc
    Member

    @nikomatsakis We do allow type aliases and this is what I had in mind. FWIW, we also allow, e.g., Foo::<u32> { ... }. However, associated types in that position do not work.

  11. nikomatsakis commented on Nov 29, 2016

    @nikomatsakis
    Contributor

    So in particular this does work:

    struct Foo<T> { x: T }
    
    type Bar = Foo<u32>;
    
    fn main() {
        let x = Bar { x: 22 };
    }
  12. withoutboats commented on Dec 1, 2016

    @withoutboats
    Contributor

    @rfcbot reviewed

  13. petrochenkov commented on Dec 19, 2016

    @petrochenkov
    ContributorAuthor

    ping @nikomatsakis
    I hoped to get this into the upcoming beta :(

  14. aturon commented on Dec 20, 2016

    @aturon
    Contributor

    @petrochenkov We can backport the stabilization. Looks like this was blocked on @pnkfelix who's been on vacation. I'll try to get a hold of him now.

  15. pnkfelix commented on Dec 20, 2016

    @pnkfelix
    Contributor

    @rfcbot reviewed

  16. rfcbot commented on Dec 20, 2016

    @rfcbot

    🔔 This is now entering its final comment period, as per the review above. 🔔

    psst @nikomatsakis, I wasn't able to add the final-comment-period label, please do so.

  17. added
    final-comment-periodIn the final comment period and will be merged soon unless new substantive objections are raised.
    on Dec 21, 2016
  18. rfcbot commented on Jan 23, 2017

    @rfcbot

    The final comment period is now complete.

  19. nikomatsakis commented on Jan 24, 2017

    @nikomatsakis
    Contributor

    @petrochenkov you want to prepare stabilization PR?

  20. nikomatsakis commented on Jan 24, 2017

    @nikomatsakis
    Contributor

    @petrochenkov you want to prepare stabilization PR?

  21. added a commit that references this issue on Jan 27, 2017
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

    B-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.B-RFC-implementedBlocker: Approved by a merged RFC and implemented but not stabilized.B-unstableBlocker: Implemented in the nightly compiler and unstable.T-langRelevant to the language teamfinal-comment-periodIn the final comment period and will be merged soon unless new substantive objections are raised.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions