-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Self as default type isnt typechecked #61631
Comments
Using godbolt, this slipped in with 1.32, where |
cc @alexreg |
Thanks for the report. @Centril I think the straightforward solution is to ban mentions of
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 |
Oh, I didn't realise |
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 |
triage: P-high. Leaving nominated for discussion at rustc meeting. Leaving unassigned for now. |
I did some more playing around, and it's not just about the The following code compiles, but shouldn't: struct Bug<F: Fn(&u8) = fn() -> &'static u8> {
F: P,
} We only get a type error when we write: impl Bug {} or let _: Bug; |
ah, so is part of the issue that the type expression used as the default for the type parameter is not checked to actually meet its given trait bounds at its definition site. We wait until a usage site to do the check. |
That only seems to happen in some cases, eg. this example from the OP fails to compile despite being unused: struct B<P: Sized = [u8]>(P);
(the The same happens here, ruling out a special-cased sizedness check: struct B<P: Copy = String>(&'static P);
But for some reason @DutchGhost's example above is accepted, despite being clearly wrong: struct Bug<F: Fn(&u8) = fn() -> &'static u8> {
f: F,
} |
@jonas-schievink , I think it only works for:
Here I build an example playground to experiment: use core::marker::{
PhantomData,
PhantomPinned,
};
// !Send + !Sync + !Unpin.
// lacks Copy + Clone
struct NoAutoTrait<T> {
_mark: PhantomData<T>,
nosend: PhantomData<*mut ()>,
pinned: PhantomPinned,
}
struct Bug<'a, F: Copy + Send + Sync + Unpin = NoAutoTrait<&'a String>> {
mark: PhantomData<&'a F>
} However, if I changed |
Yes, exactly. And I think the way that type-checking is implemented, you'll always end up in cycles if you try to do it at definition-site, since you don't have a concrete type yet... which is why @Centril and I thought that maybe we should allow this and solve the use-site issues (e.g., the situation with impls). |
Discussed at T-compiler meeting. Sounds pretty thorny. @eddyb put forward the idea that we might at least try to emit warnings for these cases even if we cannot reliably do hard errors for them. In any case, needs further investigation before we'd commit to saying that we do not need to do it at the definition site. Assigning to @eddyb and myself. But also Cc'ing @nikomatsakis in the hopes that they will also chime in. |
To be clear, I was thinking of backwards-compatibility concerns, that would imply we might never be able to make something into a proper hard error, even if we have a reliable way to detect it. But I missed the fact that this is specifically about So here's what I think of rust/src/librustc_resolve/lib.rs Lines 895 to 944 in a6b5d22
Previous comments have mentioned this behavior, but I think it implies something stronger: But note that this applies to |
Well that's the whole point, surely? |
@alexreg Oops, that was meant to say "using a later parameter" (that is, we only allow earlier ones). |
@eddyb Ah, that makes sense then... in any case, maybe it makes sense to consider the |
Clarification question: When we last discussed this in the @rust-lang/lang meeting, the conclusion was that this was roughly the expected behavior -- except for the bug around In which case, what we need to do is fix the bug around |
@nikomatsakis What exactly are you referring to as "expected behaviour" here? That using later type params in defaults for earlier ones is disallowed? [EDIT: Ah, are you referring to @DutchGhost's case of (wrapped) references being okay?] For sure, there's a bug with |
@eddyb left some general guidance for me on Discord, which may be enough for me to tackle this along with his above comment:
|
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 I'd argue the latter should get a fix as well. 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 |
I opened rust-lang/reference#636 to document the intended behavior here -- this does not include the bugs around |
So... is someone tackling this issue? |
I think I have a patch for this. PR forthcoming. |
Hey @eddyb, what were you referring to when you said An And also, that
|
…pe-param-default, r=alexreg Disallow Self in type param defaults of ADTs Fix rust-lang#61631 (also includes a drive-by fix to a typo in some related diagnostic output.)
…pe-param-default, r=alexreg Disallow Self in type param defaults of ADTs Fix rust-lang#61631 (also includes a drive-by fix to a typo in some related diagnostic output.)
I was talking about 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. |
Ah okay. I was adopting a model based on @alexreg's comments on this issue, and I overlooked the point you made about what |
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)
The text was updated successfully, but these errors were encountered: