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

Warning when constructor name is used as variable in match #1600

Open
RustanLeino opened this issue Nov 19, 2021 · 4 comments · May be fixed by #2298
Open

Warning when constructor name is used as variable in match #1600

RustanLeino opened this issue Nov 19, 2021 · 4 comments · May be fixed by #2298
Assignees
Labels
area: error-reporting Clarity of the error reporting kind: enhancement Enhancements, feature requests, etc. These are NOT bugs, but ways we can improve Dafny

Comments

@RustanLeino
Copy link
Collaborator

Consider the following program, which contains a simple mistake:

datatype Color = Red | Green | ShadesOfGray(nat)

predicate Monochromatic(c: Color) {
  match c
  case ShadesOfGray => true
  case anythingElse => false
}

For this program, Dafny issues a "redundant branch" warning for the second case. Why? Because the constructor ShadesOfGray takes a parameter, and since the pattern ShadesOfGray does not list a parameter, Dafny interprets the ShadesOfGray in the first pattern as a variable (which will match any c, just like the variable anythingElse in the second pattern would match anything that does not match in a prior case).

It would be nice if Dafny issued a warning in this case. I can imagine

Warning: "ShadesOfGray" on line 5 is used as a variable, but it is also the name of a constructor that can be written here. If you intended to write a pattern that uses this constructor, add the parameters, like `ShadesOfGray(_)`.

Such a warning could be emitted once all resolution/type inference/type checking has been done. The check would then traverse through all case patterns. If inside a pattern it finds a variable X of type T, where T is a datatype that contains a constructor (with 1 or more parameters) named X, then the warning above is generated. Alternatively, this check could be implemented earlier, at the point where the Resolver today distinguishes between a nullary constructor (like Red) and a variable.

@RustanLeino RustanLeino added the kind: enhancement Enhancements, feature requests, etc. These are NOT bugs, but ways we can improve Dafny label Nov 19, 2021
@seebees
Copy link

seebees commented Nov 20, 2021

I agree. My issue with "redundant branch" wording is that it makes me think that I can clean something up because these branches "do the same thing". But as you point out, in this case Dafny means "I will never go into that branch".
If I have 2 copies of the same function that do the same thing, one of them is redundant.
However, I would never expect that callsites for the redundant function would never execute.
Not exactly the same example, I know. But it was how I was interpreting that warning.

@cpitclaudel
Copy link
Member

Oh, it looks like my recent issue #1789 is a duplicate of this one.

@robin-aws
Copy link
Member

robin-aws commented Apr 8, 2022

I thought of another way we could attack this. The code sample should also produce a style warning something along the lines of:

Warning: variable names should begin with a lowercase letter: "ShadesOfGray" 

That's a lot shorter than trying to explain the specific situation.

@keyboardDrummer
Copy link
Member

keyboardDrummer commented Apr 8, 2022

A related but slightly different issue: #1991

Which gives the following example:

datatype D = C1 | C2 | C3

var x: D = ...
match x {
    case C1 /* matches type C1 */ => ...
    case C2 /* matches type C2 */ => ...
    case C4 /* binds variable C4 */ => ...
}
vs
match x {
    case C1() /* matches constructor C1() */ => ...
    case C2() /* matches constructor C2() */ => ...
    case C4() /* ERROR, no constructor C4 */ => ...
}

The bigger issue seems to be that the syntax for capturing a variable and matching a datatype constructor is too similar. The imagined warning:

Warning: "ShadesOfGray" on line 5 is used as a variable, but it is also the name of a constructor that can be written here. If you intended to write a pattern that uses this constructor, add the parameters, like `ShadesOfGray(_)`.

Works for the case where the captured variable has the exact name of the constructor, but not for the case where a name that's not a constructor is captured as a variable, even though the programmer intended to match on a constructor.

An alternative solution would be a flag "strictMatchCases" that gives a warning for any case where a datatype constructor is not followed by parenthesis.

I thought of another way we could attack this. The code sample should also produce a style warning something along the lines of:

I like that but maybe that would make most sense if the language also came with a standard code style that's enforced through compiler warnings and for which there's an automated formatter.

@keyboardDrummer keyboardDrummer added the area: error-reporting Clarity of the error reporting label May 20, 2022
tobiaj10 added a commit to tobiaj10/dafny that referenced this issue Jun 24, 2022
…iable in match dafny-lang#1600. The code will produce a warning whenever a variable in a case expression starts with a capital letter.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: error-reporting Clarity of the error reporting kind: enhancement Enhancements, feature requests, etc. These are NOT bugs, but ways we can improve Dafny
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants