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

Pattern matching against enum case without parameters compiles without warnings #21618

Open
lolgab opened this issue Sep 19, 2024 · 8 comments
Open
Labels
area:linting Linting warnings enabled with -W or -Xlint area:pattern-matching itype:bug

Comments

@lolgab
Copy link
Contributor

lolgab commented Sep 19, 2024

Compiler version

3.5.0 (3.4.0+)
3.3.3 works correctly

Minimized code

enum Foo:
  case Bar(i: Int)
case class Container(foo: Foo) 

@main def main = Container(Foo.Bar(1)) match {
  case Container(Foo.Bar) => println("yes")
  case _ => println("no")
}

Output

Using Scala 3.5.0

no

Using Scala 3.3.3

[error] ./main.scala:8:18
[error] Found:    Foo.Bar.type
[error] Required: Foo
[error] pattern type is incompatible with expected type
[error]   case Container(Foo.Bar) => println("yes")
[error]                  ^^^^^^^
Error compiling project (Scala 3.3.3, JVM (11))
Compilation failed

Expectation

It should fail to compile since Container takes a Foo and I expect Foo.Bar to be of type Foo.Bar.type but not of type Foo.
Scala 3.3.3 does the right thing, but 3.5.0 doesn't.

@lolgab lolgab added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Sep 19, 2024
@bracevac
Copy link
Contributor

I think these kinds of checks are now covered by -Wimplausible-patterns since 3.4. See #18093.

@Gedochao
Copy link
Contributor

Gedochao commented Sep 20, 2024

BTW, the error is still raised in 3.3.4-RC4.

I think these kinds of checks are now covered by -Wimplausible-patterns since 3.4. See #18093.

@bracevac it's true -Wimplausible-patterns correctly emits a warning for 3.4+

[warn] ./repro.scala:7:18
[warn] Implausible pattern:
[warn] Foo.Bar  could match selector of type  Foo
[warn] only if there is an `equals` method identifying elements of the two types.
[warn]   case Container(Foo.Bar) => println("yes")
[warn]                  ^^^^^^^

So at first glance it looks like a regression, but indeed it seems these checks have been moved behind a linting flag and the errors downgraded to warnings. I wonder if it wouldn't make sense to be able to identify them as errors (I'd personally expect them to be errors).
However, perhaps it'd be enough to document this better...

cc @odersky @dwijnand

@Gedochao Gedochao added area:pattern-matching area:linting Linting warnings enabled with -W or -Xlint and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Sep 20, 2024
@odersky
Copy link
Contributor

odersky commented Sep 20, 2024

If I add an equals method like this

enum Foo:
  def equals(x: Bar, y: Bar) = true
  case Bar(i: Int)
case class Container(foo: Foo)

@main def main = Container(Foo.Bar(1)) match
  case Container(Foo.Bar) => println("yes")
  case _ => println("no")

I still get a warning. So I think should not be an error, because now the program would print "yes". The problem is the compiler does not know what the equals method, if one is given, does. So it has to argue on the basis of plausibility, and such guesses should in general not be errors.

@Gedochao
Copy link
Contributor

@odersky ah, I see, thanks for explaining.
Then, even if confusing, I guess the current behaviour is expected.

@lolgab
Copy link
Contributor Author

lolgab commented Sep 20, 2024

One thing I don't understand is the role of the Bar term. What is it? The equivalent of a companion object for a case class? Why can be used interchangeably with the instances of Bar?
For sure I'm missing a lot of how enums are represented.

@OlegYch
Copy link
Contributor

OlegYch commented Sep 20, 2024

If I add an equals method like this

enum Foo:
  def equals(x: Bar, y: Bar) = true
  case Bar(i: Int)
case class Container(foo: Foo)

@main def main = Container(Foo.Bar(1)) match
  case Container(Foo.Bar) => println("yes")
  case _ => println("no")

I still get a warning. So I think should not be an error, because now the program would print "yes". The problem is the compiler does not know what the equals method, if one is given, does. So it has to argue on the basis of plausibility, and such guesses should in general not be errors.

There is no way Foo.Bar and Foo.Bar(1) can be equal, so the attempted comparison should fail with compilation error.

@odersky
Copy link
Contributor

odersky commented Sep 21, 2024

Yes but the example can easily be changed so that's no longer true.

@OlegYch
Copy link
Contributor

OlegYch commented Sep 21, 2024

@odersky that would be a separate issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:linting Linting warnings enabled with -W or -Xlint area:pattern-matching itype:bug
Projects
None yet
Development

No branches or pull requests

5 participants