Repository navigation
Self as default type isnt typechecked #61631
Description
Activity
- addedC-bugCategory: This is a bug.Category: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language teamRelevant to the language teamand removedT-langRelevant to the language teamRelevant to the language team
on Jun 7, 2019 Using godbolt, this slipped in with 1.32, where
Selfis allowed in type defs: #56366- addedregression-from-stable-to-stablePerformance or correctness regression from one stable version to another.Performance or correctness regression from one stable version to another.
on Jun 7, 2019 cc @alexreg
Thanks for the report.
@Centril I think the straightforward solution is to ban mentions of
Selfas type parameter defaults. After all, if you replaceSelfwithBin the above example, you get:error[E0391]: cycle detected when processing `B::P`Sound fair?
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
Selfwhen checking the bounds of a type definition.Oh, I didn't realise
Selfwas previously permitted...This appears to be an instance of a wider problem:
trait Foo<Bar: Sized = [Self]> {}
Has compiled, but shouldn't have (?), since 1.0.
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 forP) and possibly elsewhere.triage: P-high. Leaving nominated for discussion at rustc meeting. Leaving unassigned for now.
20 remaining items
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
Selftype 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.
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
'ato'staticstarts 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 strdoes not, so basically any use that leaves the default unspecified is known to be in error. In contrast,&'a strdoes have a parameter that is not yet known ('a), so we don't check it for consistency.I opened rust-lang/reference#636 to document the intended behavior here -- this does not include the bugs around
Self, though.So... is someone tackling this issue?
I think I have a patch for this. PR forthcoming.
But note that this applies to
struct,enum,unionandimpl.Hey @eddyb, what were you referring to when you said
implhere?An
impl<generics ...> Trait for Type(orimpl Type) isn't an ADT definition, so I don't know where it would fall in your characterization ofSelfbeing an implicit type parameter (either the first one, in the case oftrait, 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 #36887I would imagine that the(nevermind; previous sentence was written before I actually tried to make an example and discovered #36887.)generics ...in theimpldefinition could have defaults that refer toSelf, no?- added a commit that references this issue
on Oct 3, 2019 - added 2 commits that reference this issue
on Oct 3, 2019 An
impl<generics ...> Trait for Type(orimpl Type) isn't an ADT definition, so I don't know where it would fall in your characterization ofSelfbeing an implicit type parameter (either the first one, in the case oftrait, or the last one, in the case of ADT items).I was talking about
Selfas an "alias" forAdt<generics...>orType(in animpl), 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.
I was talking about
Selfas an "alias" forAdt<generics...>orType(in animpl), 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
Selfis "by definition."
The following code compiles:
but shouldn't, because
[Self]is NOT Sized.If we change
[Self]with a[u8], like this: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)