Skip to content

Pattern Matching : Wrong Unreachable case warning #17188

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

Open
ftucky opened this issue Mar 30, 2023 · 7 comments
Open

Pattern Matching : Wrong Unreachable case warning #17188

ftucky opened this issue Mar 30, 2023 · 7 comments

Comments

@ftucky
Copy link

ftucky commented Mar 30, 2023

Compiler version

3.2.2, 3.3.0-RC3 , 3.3.1

Minimized code

trait Foo
type Of[F<:Foo] = Bar { val of : F }

sealed trait Bar :
	val of : Foo

trait Baz extends Bar

val b : Bar = ???
val y : Option[Of[b.of.type]] = ???
val z = y match
	case None    => false	
	case Some(_) => true  // <-- Warning Unreachable case

https://scastie.scala-lang.org/vLKPswdSQgOT2z292wXTdg

Output

Warning unreachable case

Expectation

The case is reachable.

Notes:

  • In my by source code (before minimization) I see the case being reached.
  • If trait Bar is not sealed, the faulty warning disappears
  • If trait Baz extends Bar is not present, the faulty warning disappears.
@ftucky ftucky added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Mar 30, 2023
@dwijnand dwijnand added area:pattern-matching and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Mar 31, 2023
@dwijnand dwijnand self-assigned this Mar 31, 2023
@jpsacha
Copy link

jpsacha commented Apr 12, 2023

This also happens for AnyVals, for instance:

value match
  case v: Double => ...
  case v: Float => ...
  ...

@ftucky
Copy link
Author

ftucky commented Apr 13, 2023

Hello jp,
can you be more specific ?

Code below does not raise any warning. [ neither in 3.2.2 nor in 3.3.0-RC3 ]

def tell(value:AnyVal) =
  value match
    case d:Double => "Double"
    case f:Float  => "Float"

tell(1.0:Float)  // -> "Float"
tell(1.0:Double) // -> "Double"

https://scastie.scala-lang.org/qEkzMwAjTcilQZS0U5XEzw

@mbovel
Copy link
Member

mbovel commented May 4, 2023

@dwijnand do you think this could be appropriate for a spree?

@dwijnand
Copy link
Member

dwijnand commented May 4, 2023

Yes. It's not going to be super interesting, it's a difference in typing Some.unapply[?A] between Typer and SpaceEngine's covers method, which is instantiating the type var ?A differently.

@scala-center-bot
Copy link

This issue was picked for the Issue Spree No. 31 of 30 May 2023 which takes place in 2 days. @natsukagami, @eugenefle, @nmcb, @jan-pieter will be working on it. If you have any insight into the issue or guidance on how to fix it, please leave it here.

@dwijnand
Copy link
Member

To give some more detail, when typing the method typedUnApply will constrain and then maximise the abstract types and type variables in the pattern Some.unapply[?A], using constrainPatternType and maximizeType. The method signature (I mistakenly said covers above) in the SpaceEngine instead uses two <:< calls, instantiateSelected and isFullyDefined. The result of this (if my analysis is correct!) is a difference that leads to this false positive.

@natsukagami
Copy link
Contributor

Another attempt at minimization:

sealed trait Bar:
  val of : Any

trait A extends Bar

object B extends Bar:
  val of : Int = 1

type Baz = Bar { val of : Int }

val x : Baz = ???

val y = x match
  case B => B.of
  case _ => 0 // unreachable

It seems that when we are checking the possible remaining values of Baz (which is a refined Bar), we try to decompose Bar into its candidates A and B; of which we try to refine A so that it is a subtype of Baz:
https://github.com/lampepfl/dotty/blob/28915c4bd20182486b3e11136cf79af516da23b0/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala#L658-L660
However, refineUsingParent doesn't seem to deal with general refinements, only type parameter instantiation; and so refining A fails and A is not considered a valid candidate. Here it means B is the only possible candidate, so the second match is unreachable.

@dwijnand dwijnand removed the Spree Suitable for a future Spree label May 31, 2023
@dwijnand dwijnand removed their assignment Feb 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants