Skip to content
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

Fail relating constants of different types #125451

Merged
merged 2 commits into from
May 25, 2024

Conversation

oli-obk
Copy link
Contributor

@oli-obk oli-obk commented May 23, 2024

fixes #121585
fixes #121858
fixes #124151

I gave this several attempts before, but we lost too many important diagnostics until I managed to make compilation never bail out early. We have reached this point, so now we can finally fix all those ICEs by bubbling up an error instead of continueing when we encounter a bug.

@rustbot
Copy link
Collaborator

rustbot commented May 23, 2024

r? @michaelwoerister

rustbot has assigned @michaelwoerister.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 23, 2024
@rustbot
Copy link
Collaborator

rustbot commented May 23, 2024

changes to the core type system

cc @compiler-errors, @lcnr

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label May 23, 2024
@michaelwoerister
Copy link
Member

I don't think I'm a good reviewer for this.
r? types

@rustbot rustbot added the T-types Relevant to the types team, which will review and decide on the PR/issue. label May 23, 2024
Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^

Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops meant to request changes, see comment i left

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 23, 2024
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 23, 2024
@rust-log-analyzer

This comment has been minimized.

Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diagnostics changes here are meh, but I think we should fix those on the diagnostics side. Maybe we can relate a different TypeError kind for const kind mismatches that signal something is wrong in the source.

@compiler-errors
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented May 25, 2024

📌 Commit d5eb7a7 has been approved by compiler-errors

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 25, 2024
bors added a commit to rust-lang-ci/rust that referenced this pull request May 25, 2024
…iaskrgr

Rollup of 8 pull requests

Successful merges:

 - rust-lang#125271 (use posix_memalign on almost all Unix targets)
 - rust-lang#125451 (Fail relating constants of different types)
 - rust-lang#125478 (Bump bootstrap compiler to the latest beta compiler)
 - rust-lang#125498 (Stop using the avx512er and avx512pf x86 target features)
 - rust-lang#125510 (remove proof tree formatting, make em shallow)
 - rust-lang#125513 (Don't eagerly monomorphize drop for types that are impossible to instantiate)
 - rust-lang#125514 (Structurally resolve before `builtin_index` in EUV)
 - rust-lang#125527 (Add manual Sync impl for ReentrantLockGuard)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 7ea507e into rust-lang:master May 25, 2024
6 checks passed
@rustbot rustbot added this to the 1.80.0 milestone May 25, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request May 25, 2024
Rollup merge of rust-lang#125451 - oli-obk:const_type_mismatch, r=compiler-errors

Fail relating constants of different types

fixes rust-lang#121585
fixes rust-lang#121858
fixes rust-lang#124151

I gave this several attempts before, but we lost too many important diagnostics until I managed to make compilation never bail out early. We have reached this point, so now we can finally fix all those ICEs by bubbling up an error instead of continueing when we encounter a bug.
@BoxyUwU
Copy link
Member

BoxyUwU commented May 27, 2024

I don't feel great that we have this as a real eq now, it should not be necessary for soundness as types of consts being correct is checked elsewhere. Could you explain more about exactly why this should be necessary. It seems like in all test cases there are error messages so the delayed bug should not cause any ICE?

@BoxyUwU
Copy link
Member

BoxyUwU commented May 27, 2024

Can we just remove this eq entirely? The assertion was getting pretty convoluted and should not be required at all

@oli-obk oli-obk deleted the const_type_mismatch branch May 27, 2024 15:12
@oli-obk
Copy link
Contributor Author

oli-obk commented May 27, 2024

Without the check here, we'll end up not tainting the MIR and subsequently the MIR interpreter, causing the ICEs we've seen. The issue is that the only place that checks that the types are valid is wfcheck, and we can't make other code depend on wfcheck, as wfcheck itself will try to evaluate constants and prove predicates, causing cycles.

We can move some checks like the type checks out of wfcheck to typeck, then we may be able to remove this again, but it's not obvious yet to me how to do this in a way that isn't error prone

@oli-obk
Copy link
Contributor Author

oli-obk commented May 27, 2024

Also

const fn catone<const M: usize>(_a: &[u8; M]) -> [u8; M + 1]
suddenly passes if I just remove the eq check entirely. So even the wfchecks aren't waterproof.

fmease added a commit to fmease/rust that referenced this pull request May 30, 2024
…iler-errors

Do not equate `Const`'s ty in `super_combine_const`

Fixes rust-lang#114456

In rust-lang#125451 we started relating the `Const`'s tys outside of a probe so it was no longer simply an assertion to catch bugs.

This was done so that when we _do_ provide a wrongly typed const argument to an item if we wind up relating it with some other instantiation we'll have a `TypeError` we can bubble up and taint the resulting mir allowing const eval to skip evaluation.

In this PR I instead change `ConstArgHasType` to correctly handle checking the types of const inference variables. Previously if we had something like `impl<const N: u32> Trait for [(); N]`, when using the impl we would instantiate it with infer vars and then check that `?x: u32` is of type `u32` and succeed. Then later we would infer `?x` to some `Const` of type `usize`.

We now stall on `?x` in `ConstArgHasType` until it has a concrete value that we can determine the type of. This allows us to fail using the erroneous implementation of `Trait` which allows us to taint the mir.

Long term we intend to remove the `ty` field on `Const` so we would have no way of accessing the `ty` of a const inference variable anyway and would have to do this. I did not fully update `ConstArgHasType` to avoid using the `ty` field as it's not entirely possible right now- we would need to lookup `ConstArgHasType` candidates in the env.

---

As for _why_ I think we should do this, relating the types of const's is not necessary for soundness of the type system. Originally this check started off as a plain `==` in `super_relate_consts` and gradually has been growing in complexity as we support more complicated types. It was never actually required to ensure that const arguments are correctly typed for their parameters however.

The way we currently check that a const argument has the correct type is a little convoluted and confusing (and will hopefully be less weird as time goes on). Every const argument has an anon const with its return type set to type of the const parameter it is an argument to. When type checking the anon const regular type checking rules require that the expression is the same type as the return type. This effectively ensure that no matter what every const argument _always_ has the correct type.

An extra bit of complexity is that during `hir_ty_lowering` we do not represent everything as a `ConstKind::Unevaluated` corresponding to the anon const. For generic parameters i.e. `[(); N]` we simply represent them as `ConstKind::Param` as we do not want `ConstKind::Unevaluated` with generic substs on stable under min const generics. The anon const still gets type checked resulting in errors about type mismatches.

Eventually we intend to not create anon consts for all const arguments (for example for `ConstKind::Param`) and instead check that the argument type is correct via `ConstArgHasType` obligations (these effectively also act as a check that the anon consts have the correctly set return type).

What this all means is that the the only time we should ever have mismatched types when relating two `Const`s is if we have messed up our logic for ensuring that const arguments are of the correct type. Having this not be an assert is:
- Confusing as it may incorrectly lead people to believe this is an important check that is actually required
- Opens the possibility for bugs or behaviour reliant on this (unnecessary) check existing

---

This PR makes two tests go from pass->ICE (`generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.rs` and `tests/crashes/121858.rs`). This is caused by the fact that we evaluate anon consts even if their where clauses do not hold and is a pre-existing issue and only affects `generic_const_exprs`. I am comfortable exposing the brokenness of `generic_const_exprs` more with this PR

This PR makes a test go from ICE->pass (`const-generics/issues/issue-105821.rs`). I have no idea why this PR affects that but I believe that ICE is an unrelated issue to do with the fact that under `generic_const_exprs`/`adt_const_params` we do not handle lifetimes in const parameter types correctly. This PR is likely just masking this bug.

Note: this PR doesn't re-introduce the assertion that the two consts' tys are equal. I'm not really sure how I feel about this but tbh it has caused more ICEs than its found lately so 🤷‍♀️

r? `@oli-obk` `@compiler-errors`
bors added a commit to rust-lang-ci/rust that referenced this pull request May 30, 2024
…er-errors

Do not equate `Const`'s ty in `super_combine_const`

Fixes rust-lang#114456

In rust-lang#125451 we started relating the `Const`'s tys outside of a probe so it was no longer simply an assertion to catch bugs.

This was done so that when we _do_ provide a wrongly typed const argument to an item if we wind up relating it with some other instantiation we'll have a `TypeError` we can bubble up and taint the resulting mir allowing const eval to skip evaluation.

In this PR I instead change `ConstArgHasType` to correctly handle checking the types of const inference variables. Previously if we had something like `impl<const N: u32> Trait for [(); N]`, when using the impl we would instantiate it with infer vars and then check that `?x: u32` is of type `u32` and succeed. Then later we would infer `?x` to some `Const` of type `usize`.

We now stall on `?x` in `ConstArgHasType` until it has a concrete value that we can determine the type of. This allows us to fail using the erroneous implementation of `Trait` which allows us to taint the mir.

Long term we intend to remove the `ty` field on `Const` so we would have no way of accessing the `ty` of a const inference variable anyway and would have to do this. I did not fully update `ConstArgHasType` to avoid using the `ty` field as it's not entirely possible right now- we would need to lookup `ConstArgHasType` candidates in the env.

---

As for _why_ I think we should do this, relating the types of const's is not necessary for soundness of the type system. Originally this check started off as a plain `==` in `super_relate_consts` and gradually has been growing in complexity as we support more complicated types. It was never actually required to ensure that const arguments are correctly typed for their parameters however.

The way we currently check that a const argument has the correct type is a little convoluted and confusing (and will hopefully be less weird as time goes on). Every const argument has an anon const with its return type set to type of the const parameter it is an argument to. When type checking the anon const regular type checking rules require that the expression is the same type as the return type. This effectively ensure that no matter what every const argument _always_ has the correct type.

An extra bit of complexity is that during `hir_ty_lowering` we do not represent everything as a `ConstKind::Unevaluated` corresponding to the anon const. For generic parameters i.e. `[(); N]` we simply represent them as `ConstKind::Param` as we do not want `ConstKind::Unevaluated` with generic substs on stable under min const generics. The anon const still gets type checked resulting in errors about type mismatches.

Eventually we intend to not create anon consts for all const arguments (for example for `ConstKind::Param`) and instead check that the argument type is correct via `ConstArgHasType` obligations (these effectively also act as a check that the anon consts have the correctly set return type).

What this all means is that the the only time we should ever have mismatched types when relating two `Const`s is if we have messed up our logic for ensuring that const arguments are of the correct type. Having this not be an assert is:
- Confusing as it may incorrectly lead people to believe this is an important check that is actually required
- Opens the possibility for bugs or behaviour reliant on this (unnecessary) check existing

---

This PR makes two tests go from pass->ICE (`generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.rs` and `tests/crashes/121858.rs`). This is caused by the fact that we evaluate anon consts even if their where clauses do not hold and is a pre-existing issue and only affects `generic_const_exprs`. I am comfortable exposing the brokenness of `generic_const_exprs` more with this PR

This PR makes a test go from ICE->pass (`const-generics/issues/issue-105821.rs`). I have no idea why this PR affects that but I believe that ICE is an unrelated issue to do with the fact that under `generic_const_exprs`/`adt_const_params` we do not handle lifetimes in const parameter types correctly. This PR is likely just masking this bug.

Note: this PR doesn't re-introduce the assertion that the two consts' tys are equal. I'm not really sure how I feel about this but tbh it has caused more ICEs than its found lately so 🤷‍♀️

r? `@oli-obk` `@compiler-errors`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
7 participants