Skip to content

Self as default type isnt typechecked #61631

Description

@DutchGhost

The following code compiles:

struct B<P: Sized = [Self]>(P);

but shouldn't, because [Self] is NOT Sized.

If we change [Self] with a [u8], like this:

struct B<P: Sized = [u8]>(P);

it fails to compile, because [u8] isnt sized.

Also note that if we would write impl B {} in the case of P being of default type [Self], we get an ICE:

Related to #59956 (comment)

Activity

  1. added
    C-bugCategory: This is a bug.
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    T-langRelevant to the language team
    and removed
    T-langRelevant to the language team
    on Jun 7, 2019
  2. DutchGhost commented on Jun 7, 2019

    @DutchGhost
    Author

    Using godbolt, this slipped in with 1.32, where Self is allowed in type defs: #56366

  3. Centril commented on Jun 7, 2019

    @Centril
    Contributor
  4. alexreg commented on Jun 7, 2019

    @alexreg
    Contributor

    Thanks for the report.

    @Centril I think the straightforward solution is to ban mentions of Self as type parameter defaults. After all, if you replace Self with B in the above example, you get:

    error[E0391]: cycle detected when processing `B::P`
    

    Sound fair?

  5. Centril commented on Jun 7, 2019

    @Centril
    Contributor

    That's a breaking change; consider e.g.:

    enum L<P = Self> {
        N,
        C(u8, Box<P>),
    }
    
    fn main() {
        L::C(0, Box::new(L::<()>::N));
    }

    I think the right thing to do is to account for Self when checking the bounds of a type definition.

  6. alexreg commented on Jun 7, 2019

    @alexreg
    Contributor

    Oh, I didn't realise Self was previously permitted...

  7. Centril commented on Jun 8, 2019

    @Centril
    Contributor

    This appears to be an instance of a wider problem:

    trait Foo<Bar: Sized = [Self]> {}

    Has compiled, but shouldn't have (?), since 1.0.

    cc @nikomatsakis

  8. alexreg commented on Jun 8, 2019

    @alexreg
    Contributor

    Thoughts after discussing this with @Centril: maybe we should be allowing this after all (or have no other choice due to the way the type system works), and should instead put in checks on things like imp B { ... } (with no binding for P) and possibly elsewhere.

  9. pnkfelix commented on Jun 13, 2019

    @pnkfelix
    Contributor

    triage: P-high. Leaving nominated for discussion at rustc meeting. Leaving unassigned for now.

  10. 20 remaining items

  11. DutchGhost commented on Jul 11, 2019

    @DutchGhost
    Author

    Discussed on discord with @alexreg I would make this comment to raise some awareness.

    As I showed in my comment here: #61631 (comment) , this issue isn't solely about the Self type being able to compile when it shouldn't, but also about reference types and wrapped references showing the exact same wrong behaviour.

    I'd argue the latter should get a fix as well.
    Imagine I make a library containing the code I wrote in that comment. For me it compiles, but anyone using it could get compile errors whenever they use my type with the defaults, since any usage of my type with the defaults still results in a compile error.

    So, being able to declare types with default parameters that don't satisfy the trait bounds seems wrong to me, because it would allow crates that compile on the crate author's side, but fail to compile on any user's side.

    cc @nikomatsakis @alexreg

  12. nikomatsakis commented on Jul 11, 2019

    @nikomatsakis
    Contributor

    Here is a summary comment from the last discussion we had on this topic. This comment then covers the lang-team reasoning about the rules and some specific examples. The TL;DR is that, while it is true that you can get errors at use-sites that could've been detected at the caller site, it's also possible to create constructs that are useful (an example is in the comment). Moreover, we are reluctant to break existing code in general, so becoming more strict is always a trade-off.

    In fact, the surprising behavior that you are pointing out, where changing from 'a to 'static starts to generate errors, is a result of the compromise we struck on our last foray here. In particular, we only check if the default has no generic parameters appearing in it. In this case, &'static str does not, so basically any use that leaves the default unspecified is known to be in error. In contrast, &'a str does have a parameter that is not yet known ('a), so we don't check it for consistency.

  13. nikomatsakis commented on Jul 11, 2019

    @nikomatsakis
    Contributor

    I opened rust-lang/reference#636 to document the intended behavior here -- this does not include the bugs around Self, though.

  14. removed
    T-langRelevant to the language team
    on Aug 1, 2019
  15. alexreg commented on Sep 7, 2019

    @alexreg
    Contributor

    So... is someone tackling this issue?

  16. pnkfelix commented on Sep 12, 2019

    @pnkfelix
    Contributor

    triage: changing assignee list to @alexreg and @pnkfelix rather than @eddyb and @pnkfelix

  17. pnkfelix commented on Sep 27, 2019

    @pnkfelix
    Contributor

    I think I have a patch for this. PR forthcoming.

  18. pnkfelix commented on Sep 27, 2019

    @pnkfelix
    Contributor

    @eddyb wrote:

    But note that this applies to struct, enum, union and impl.

    Hey @eddyb, what were you referring to when you said impl here?

    An impl<generics ...> Trait for Type (or impl Type) isn't an ADT definition, so I don't know where it would fall in your characterization of Self being an implicit type parameter (either the first one, in the case of trait, or the last one, in the case of ADT items).

    And also, that generics ... list isn't allowed to have type parameter defaults, according to #36887

    I would imagine that the generics ... in the impl definition could have defaults that refer to Self, no? (nevermind; previous sentence was written before I actually tried to make an example and discovered #36887.)

  19. added a commit that references this issue on Oct 3, 2019
    eb82e63
  20. added 2 commits that reference this issue on Oct 3, 2019
    4cc2872
    27c9052
  21. eddyb commented on Oct 4, 2019

    @eddyb
    Contributor

    An impl<generics ...> Trait for Type (or impl Type) isn't an ADT definition, so I don't know where it would fall in your characterization of Self being an implicit type parameter (either the first one, in the case of trait, or the last one, in the case of ADT items).

    I was talking about Self as an "alias" for Adt<generics...> or Type (in an impl), not an implicit parameter.

    The reason we should disallow it in ADTs' type parameter defaults is because it contains all the parameters by necessity and expanding it by hand would always produce an error anyway.

  22. pnkfelix commented on Oct 7, 2019

    @pnkfelix
    Contributor

    I was talking about Self as an "alias" for Adt<generics...> or Type (in an impl), not an implicit parameter.

    Ah okay. I was adopting a model based on @alexreg's comments on this issue, and I overlooked the point you made about what Self is "by definition."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

C-bugCategory: This is a bug.P-highHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions