Skip to content

Errors for if and match in a const are not descriptive #66125

Closed
@ecstatic-morse

Description

@ecstatic-morse

Consider the following code (Playground):

const _: i32 = match 1 {
    2 => 3,
    4 => 5,
    _ => 0,
};

const _: i32 = if true {
    4
} else {
    5
};

This is not valid today, since if and match are forbidden in constants. That restriction can be lifted soon on nightly, so we would like to emit good errors that point the user to the offending code and suggest a feature gate if it would help.

However, the errors emitted by the nightly compiler are not great:

error[E0019]: constant contains unimplemented expression type
 --> src/lib.rs:1:22
  |
1 | const _: i32 = match 1 {
  |                      ^

error[E0019]: constant contains unimplemented expression type
 --> src/lib.rs:2:5
  |
2 |     2 => 3,
  |     ^

error[E0019]: constant contains unimplemented expression type
 --> src/lib.rs:7:19
  |
7 | const _: i32 = if true {
  |                   ^^^^

error[E0019]: constant contains unimplemented expression type
  --> src/lib.rs:7:16
   |
7  |   const _: i32 = if true {
   |  ________________^
8  | |     4
9  | | } else {
10 | |     5
11 | | };
   | |_^

error: aborting due to 4 previous errors

At present, each const has two errors associated with it. One is triggered by the FakeRead emitted for the borrow checker and points to the value being branched on (1 and true) respectively. The other is triggered by the SwitchInt terminator itself. While the span of this error is good for the if (it points to the whole if-else construct), it is very confusing for the match, where it points to the pattern in the first match arm despite the SwitchInt handling all arms simultaneously.

I've thought a bit about how to improve this, but I don't have a great solution. I'm hoping someone can help. I don't think we want to rely only on the presence of FakeRead to reject branchy code in a const; SwitchInt seems like the natural candidate (maybe with a fallback to FakeRead to detect single-arm match statements). However, I don't know how to improve the span for the SwitchInt for the match, or if doing so would cause other diagnostics to regress.

I think the ideal approach would be to check for this at the HIR or AST level. This would give us very precise spans, and we could continue checking for SwitchInt in the MIR to make sure the high-level check didn't miss anything. Is this feasible?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)A-diagnosticsArea: Messages for errors, warnings, and lintsD-papercutDiagnostics: An error or lint that needs small tweaks.D-verboseDiagnostics: Too much output caused by a single piece of incorrect code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions