You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@eddyb identified several bugs in Playground examples on Discord, starting here. We should classify them and make sure we have representative edge cases for each when they've fixed.
I'm going to use this issue to make note of existing cost generic issues that I think may not require lazy normalisation to fix. The rest are probably blocked on #67890.
Please cc me on each fix for anything const-generics-related.
I don't have the time to go through all the issues right now but a "make things work" approach to bugfixing is likely to lead to unsoundness.
A very important milestone is #70107, anything that it creates errors in (without ICE-ing) should probably be considered "fixed as not-a-bug" or rather the bug was in the quality of diagnostics but the code was still wrong.
#69239 seems to be related to #69913, afaict the most useful way to fix this would be #70122 which we decided was not worth it.
#70507, #69816, #63695, #61936 something something const args in methods, if I remember correctly these can't be fixed easily rn, @eddyb I can't find where you mentioned this. (maybe #70167 (comment))
@lcnr Types don't have types (or more correctly, the type of all types is the same, some hypothetical Type that you can't refer to inside the Rust language).
Furthermore, the constant expression is a separate body that has to be fully type-checked before it can be evaluated.
So you have to compute the type before you type-check the constant expression, before you can evaluate it, before you can use it in the original body, which is the only one that knows the type.
You could bypass this with lazy normalization, maybe, but it's too easy to end up with a cyclic dependency between the constant expression and the surrounding body.
Maybe we could type-check the constant expression and get the type from there without having an expected type? And only use it if the type is correct?
But then x.method::<0>() would never work as we can't infer what type that is from just 0.
They should work. This would be an unnatural restriction, even a temporary one. That said, I'm not sure how to type-check them yet either.
Disallowing impossible to implement features is not really unnatural.
We also ban specifying generics when impl Trait is used, or specifying lifetimes when some are late-bound, I think?
While this makes sense, do we even want to know the type/value of the generic argument before the relevant parameters are known? I still think that I am missing something here, as it seems easily solvable for me. 😐
Looking at this example:
structA<constN:usize>;implA<7>{fntest<constM:bool>(){}}implA<42>{fntest<constM:Option<()>>(){}}let a = A::<7>;
a.test::<true>();
Due to type inference, we should know that a is A<7>, which means that we know that M = bool.
This allows us to then type check true without even being able to cause cycles.
I would not expect, or want, the following to compile for example
let a = A;
a.test::<true>();// we could infer from `true` that we require a method// `test<const _: bool>()` which means that `N` must be `7`.
This seems really fragile and causes the problems mentioned by @eddyb.
I don't yet see how my approach can lead to cycle errors 🤔
You can infer the type main_ANON0 from the body (true), but I would suggest avoiding strawmans like true which is clearly bool: unsuffixed integer literals are more interesting because 0 infers as i32.
The cycle would be if type_of(main_ANON0) looked up the type in typeck_tables_of(main).
That's theoretically fine, but typeck_tables_of(main) (i.e. type-checking main) might try to evaluate the constant which will call const_eval(main_ANON0) which will call build_mir(main_ANON0) which will call typeck_tables_of(main_ANON0) which will need type_of(main_ANON0) in order to check if the body ("true") matches the type.
Disallowing impossible to implement features is not really unnatural.
From a user's perspective, there's no reason this shouldn't work. It's unnatural from a language POV. This is theoretically possible to implement. If the existing infrastructure in rustc makes that difficult, then something should change there.
I never want to infer the type of main_ANON0 from its body. I should have probably used Default::default() as an argument in my example.
My expectation is that we never actually need type_of(main_ANON0). I only want to evaluate const args after the corresponding parameter is known(which means that the type of main_ANON0 is also known).
Once we know that main_ANON0 corresponds to const N: bool, type_of(main_ANON0) can be set to bool and checked without relying on main.
Taken from zulip, the following issues are not blocked at the moment:
Bastian Kauschke: #70507 (comment) should be doable at the moment, but I don't know how difficult this will be.
^ done
Bastian Kauschke: this is a spurious warning which is related, I looked into this and at least to me the problem was not directly obvious so it is probably also not that easy to fix #70225
Bastian Kauschke: #68104 is also unrelated, but is also not that easy
Bastian Kauschke: #66451 is both fairly self contained and helpful
This also seems like it requires an unrelated fix: #71611
Activity
varkor commentedon Jan 20, 2020
Most of the issues are probably #68398, but there's also https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=8fb424e1ae41c73a264e7ad1c991686d.
varkor commentedon Apr 8, 2020
I'm going to use this issue to make note of existing cost generic issues that I think may not require lazy normalisation to fix. The rest are probably blocked on #67890.
[type error]
: #70507[i32; _]
#61936eddyb commentedon Apr 8, 2020
Please cc me on each fix for anything const-generics-related.
I don't have the time to go through all the issues right now but a "make things work" approach to bugfixing is likely to lead to unsoundness.
A very important milestone is #70107, anything that it creates errors in (without ICE-ing) should probably be considered "fixed as not-a-bug" or rather the bug was in the quality of diagnostics but the code was still wrong.
lcnr commentedon Apr 9, 2020
#69239 seems to be related to #69913, afaict the most useful way to fix this would be #70122 which we decided was not worth it.
#70507, #69816, #63695, #61936 something something const args in methods, if I remember correctly these can't be fixed easily rn, @eddyb I can't find where you mentioned this. (maybe #70167 (comment))
eddyb commentedon Apr 9, 2020
Yeah we should just ban const args on
TypeRelative
segments and method calls.Unless someone has a clever idea about how to type-check them.
varkor commentedon Apr 9, 2020
They should work. This would be an unnatural restriction, even a temporary one. That said, I'm not sure how to type-check them yet either.
lcnr commentedon Apr 9, 2020
Afaik type args work with TypeRelative segments, which means that I am missing a crucial difference between const and type args. :/
Can you explain this to me/guide me to some relevant ressources?
eddyb commentedon Apr 9, 2020
@lcnr Types don't have types (or more correctly, the type of all types is the same, some hypothetical
Type
that you can't refer to inside the Rust language).Furthermore, the constant expression is a separate body that has to be fully type-checked before it can be evaluated.
So you have to compute the type before you type-check the constant expression, before you can evaluate it, before you can use it in the original body, which is the only one that knows the type.
You could bypass this with lazy normalization, maybe, but it's too easy to end up with a cyclic dependency between the constant expression and the surrounding body.
Maybe we could type-check the constant expression and get the type from there without having an expected type? And only use it if the type is correct?
But then
x.method::<0>()
would never work as we can't infer what type that is from just0
.Disallowing impossible to implement features is not really unnatural.
We also ban specifying generics when
impl Trait
is used, or specifying lifetimes when some are late-bound, I think?lcnr commentedon Apr 9, 2020
While this makes sense, do we even want to know the type/value of the generic argument before the relevant parameters are known? I still think that I am missing something here, as it seems easily solvable for me. 😐
Looking at this example:
Due to type inference, we should know that
a
isA<7>
, which means that we know thatM = bool
.This allows us to then type check
true
without even being able to cause cycles.I would not expect, or want, the following to compile for example
This seems really fragile and causes the problems mentioned by @eddyb.
I don't yet see how my approach can lead to cycle errors 🤔
eddyb commentedon Apr 9, 2020
true
is in another body. You can't type-check while type-checking the parent function.It's like this:
You can infer the type
main_ANON0
from the body (true
), but I would suggest avoiding strawmans liketrue
which is clearlybool
: unsuffixed integer literals are more interesting because0
infers asi32
.The cycle would be if
type_of(main_ANON0)
looked up the type intypeck_tables_of(main)
.That's theoretically fine, but
typeck_tables_of(main)
(i.e. type-checkingmain
) might try to evaluate the constant which will callconst_eval(main_ANON0)
which will callbuild_mir(main_ANON0)
which will calltypeck_tables_of(main_ANON0)
which will needtype_of(main_ANON0)
in order to check if the body ("true
") matches the type.varkor commentedon Apr 9, 2020
From a user's perspective, there's no reason this shouldn't work. It's unnatural from a language POV. This is theoretically possible to implement. If the existing infrastructure in rustc makes that difficult, then something should change there.
lcnr commentedon Apr 9, 2020
I never want to infer the type of
main_ANON0
from its body. I should have probably usedDefault::default()
as an argument in my example.My expectation is that we never actually need
type_of(main_ANON0)
. I only want to evaluate const args after the corresponding parameter is known(which means that the type ofmain_ANON0
is also known).Once we know that
main_ANON0
corresponds toconst N: bool
,type_of(main_ANON0)
can be set tobool
and checked without relying onmain
.8 remaining items
lcnr commentedon Apr 29, 2020
Taken from zulip, the following issues are not blocked at the moment:
^ done
This also seems like it requires an unrelated fix: #71611
Auto merge of rust-lang#74113 - lcnr:type-dependent-consts-2, r=eddyb
varkor commentedon Sep 13, 2020
I think the issues raised here specifically have been addressed now that #74113 has been merged.