Skip to content

Classify various const generics bugs #68400

Closed
@varkor

Description

@varkor
Member

@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.

Activity

added
metabugIssues about issues themselves ("bugs about bugs")
A-const-genericsArea: const generics (parameters and arguments)
on Jan 20, 2020
varkor

varkor commented on Jan 20, 2020

@varkor
MemberAuthor
eddyb

eddyb commented on Apr 8, 2020

@eddyb
Member

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

lcnr commented on Apr 9, 2020

@lcnr
Contributor

#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

eddyb commented on Apr 9, 2020

@eddyb
Member

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

varkor commented on Apr 9, 2020

@varkor
MemberAuthor

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

lcnr commented on Apr 9, 2020

@lcnr
Contributor

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

eddyb commented on Apr 9, 2020

@eddyb
Member

@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?

lcnr

lcnr commented on Apr 9, 2020

@lcnr
Contributor

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:

struct A<const N: usize>;

impl A<7> {
    fn test<const M: bool>() {}
}

impl A<42> {
    fn test<const M: 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 🤔

eddyb

eddyb commented on Apr 9, 2020

@eddyb
Member

true is in another body. You can't type-check while type-checking the parent function.

It's like this:

const main_ANON0: ??? = true;
fn main() {
    // ...
    a.test::<main_ANON0>();
}

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.

varkor

varkor commented on Apr 9, 2020

@varkor
MemberAuthor

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.

lcnr

lcnr commented on Apr 9, 2020

@lcnr
Contributor

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.

8 remaining items

lcnr

lcnr commented on Apr 29, 2020

@lcnr
Contributor

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

added a commit that references this issue on Jul 15, 2020

Auto merge of rust-lang#74113 - lcnr:type-dependent-consts-2, r=eddyb

varkor

varkor commented on Sep 13, 2020

@varkor
MemberAuthor

I think the issues raised here specifically have been addressed now that #74113 has been merged.

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

    A-const-genericsArea: const generics (parameters and arguments)C-bugCategory: This is a bug.F-const_generics`#![feature(const_generics)]`metabugIssues about issues themselves ("bugs about bugs")

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @eddyb@crlf0710@varkor@lcnr

        Issue actions

          Classify various const generics bugs · Issue #68400 · rust-lang/rust