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

Match type does not check bounds #13741

Open
bishabosha opened this issue Oct 13, 2021 · 3 comments
Open

Match type does not check bounds #13741

bishabosha opened this issue Oct 13, 2021 · 3 comments

Comments

@bishabosha
Copy link
Member

bishabosha commented Oct 13, 2021

Compiler version

Scala 3.1.1-RC1-bin-20211008-0a89c6f-NIGHTLY-git-0a89c6f

Minimized code

type Init[X <: NonEmptyTuple] <: Tuple = X match {
  case _ *: EmptyTuple => EmptyTuple
  case x *: xs => x *: Init[xs] // statically `xs` does not match, in practice it will not fail
}

Output

compiles ok

Expectation

A static failure for the recursive step as xs is not <: NonEmptyTuple, or is all checking left until a concrete type is applied?

@soronpo
Copy link
Contributor

soronpo commented Oct 14, 2021

I think it is the required behavior. Type matches check bounds somewhat lazily, when the type is more concrete.
It's equivalent to a method that only can invoke runtime error when it's actually running.

@dwijnand
Copy link
Member

dwijnand commented Apr 19, 2023

Fix

         case m @ MatchTypeTree(bounds, selector, cases) =>
           // Analog to the case above for match types
           def transformIgnoringBoundsCheck(x: CaseDef): CaseDef =
-            withMode(Mode.Pattern)(super.transform(x)).asInstanceOf[CaseDef]
+            val CaseDef(pat, guard, body) = x
+            cpy.CaseDef(tree)(inMode(Mode.Pattern)(transform(pat)), transform(guard), transform(body))
+
           cpy.MatchTypeTree(tree)(
             super.transform(bounds),
             super.transform(selector),

using the example

import scala.NonEmptyTuple

type Init[X <: NonEmptyTuple] <: Tuple = X match
  case EmptyTuple => EmptyTuple
  case x *: xs => x *: Init[xs]

def a: Init[Tuple3[Int, String, Boolean]] = ???

@sjrd
Copy link
Member

sjrd commented Apr 20, 2023

I think it is the required behavior. Type matches check bounds somewhat lazily, when the type is more concrete. It's equivalent to a method that only can invoke runtime error when it's actually running.

Taking the analogy of term levels, it would not be about run-time errors but about type errors, in the sense that a term t: T is used where U is expected but T </: U. For example

def init(x: ::[Int]): List[Int] = x match
  case _ :: Nil => Nil
  case x :: xs => x :: init(xs) // statically type error because xs: List[Int] </: ::[Int]

So IMO this should be a compile error.

@dwijnand Do you want to pursue your fix as a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants