Skip to content

Opaque type combined with match type has unexpected behavior #17944

Closed
@mrdziuban

Description

@mrdziuban

Compiler version

3.3.0, also tested with the latest nightly 3.3.2-RC1-bin-20230606-5d2812a-NIGHTLY

Minimized code

I'm splitting this into two snippets because for some reason the code to actually reproduce the error doesn't compile when it's compiled at the same time as the setup code

Setup code

Save this to a file and load a REPL with it

package test

import types._

object types {
  opaque type ->>[K, V] = V
  extension [K <: Singleton](k: K) def ->>[V](v: V): K ->> V = v.asInstanceOf[K ->> V]
}

type FindField[T <: Tuple, K] = FindField0[T, K, 0]

type FindField0[T <: Tuple, K, I <: Int] <: (Any, Int) = T match {
  case (K ->> f) *: _ => (f, I)
  case _ *: t => FindField0[t, K, compiletime.ops.int.S[I]]
}

trait Selector[T, Key] {
  type Out
  def apply(t: T): Out
}

object Selector {
  type Aux[T, K, O] = Selector[T, K] { type Out = O }

  inline def apply[T, K](using s: Selector[T, K]): Aux[T, K, s.Out] = s

  inline given selectorInst[T <: Tuple, K](
    using idx: ValueOf[Tuple.Elem[FindField[T, K], 1]],
  ): Selector.Aux[T, K, Tuple.Head[FindField[T, K]]] =
    new Selector[T, K] {
      type Out = Tuple.Head[FindField[T, K]]
      def apply(t: T): Out = t.productElement(idx.value).asInstanceOf[Out]
    }
}

Error code

Run this code in the REPL

import test._
import test.types._

val t = ("s" ->> "foo") *: ("i" ->> 3) *: EmptyTuple
val s = Selector[("s" ->> String) *: ("i" ->> Int) *: EmptyTuple, "i"]
s(t)

Output

scala> s(t)
java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
  at rs$line$4$$anon$1.apply(rs$line$4:1)
  at rs$line$4$$anon$1.apply(rs$line$4:1)
  ... 66 elided

Expectation

The code should run without error and return an Int. Interestingly, if you make a small change to the definition of opaque type ->>, then the error goes away:

diff --git a/Selector.scala b/Selector.scala
index 69bd8a3..314e219 100644
--- a/Selector.scala
+++ b/Selector.scala
@@ -3,7 +3,8 @@ package test
 import types._
 
 object types {
-  opaque type ->>[K, V] = V
+  type Tag[A]
+  opaque type ->>[K, V] = V & Tag[K]
   extension [K <: Singleton](k: K) def ->>[V](v: V): K ->> V = v.asInstanceOf[K ->> V]
 }

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions