Uploaded image for project: 'Scala Programming Language'
  1. Scala Programming Language
  2. SI-5399

Regression involving existential types and pattern matching

    Details

      Description

      The following code compiles without errors in 2.9.1, but fails in 2.10.0-SNAPSHOT (2.10.0.rdev-4232-2012-01-23-g9a20086). This looks related to Martin's fix on Jan. 21:
      https://github.com/scala/scala/commit/2e092d4822d044312317c502badd8ad5c2674b58

       
      class Foo {
        trait Init[T]
        class ScopedKey[T] extends Init[T]
       
        trait Setting[T] {
          val key: ScopedKey[T]
        }
       
        case class ScopedKey1[T](val foo: Init[T]) extends ScopedKey[T]
       
        val scalaHome: Setting[Option[String]] = null
        val scalaVersion: Setting[String] = null
       
        def testPatternMatch(s: Setting[_]) {
          s.key match {
            case ScopedKey1(scalaHome.key | scalaVersion.key) => ()
          }
        }
      }
      

      Errors when compiled with trunk:

       
      existential.scala:34: error: type mismatch;
       found   : Foo.this.ScopedKey[Option[String]]
       required: Foo.this.Init[Any]
      Note: Option[String] <: Any, but trait Init is invariant in type T.
      You may wish to define T as +T instead. (SLS 4.5)
            case ScopedKey1(scalaHome.key | scalaVersion.key) => ()
                                      ^
      existential.scala:34: error: type mismatch;
       found   : Foo.this.ScopedKey[String]
       required: Foo.this.Init[Any]
      Note: String <: Any, but trait Init is invariant in type T.
      You may wish to define T as +T instead. (SLS 4.5)
            case ScopedKey1(scalaHome.key | scalaVersion.key) => ()
                                                         ^
      two errors found
      

        Attachments

          Issue Links

            Activity

            Hide
            odersky Martin Odersky added a comment -

            In fact, my suspicion is that it's the virtual pattern matcher. Not sure whether the pattern matcher is right to refuse or not. Assigning to Adriaan.

            Show
            odersky Martin Odersky added a comment - In fact, my suspicion is that it's the virtual pattern matcher. Not sure whether the pattern matcher is right to refuse or not. Assigning to Adriaan.
            Hide
            dragos Iulian Dragos added a comment -

            I'm not sure either.

            For the record, I opened related ticket SI-5400. It might be a duplicate as it involves the same actors, but the error is different.

            Show
            dragos Iulian Dragos added a comment - I'm not sure either. For the record, I opened related ticket SI-5400 . It might be a duplicate as it involves the same actors, but the error is different.
            Hide
            grek Grzegorz Kossakowski added a comment -

            AFAIK, virtual pattern matcher kicks in only -Yvirtpatmat is supplied. It's off by default.

            Show
            grek Grzegorz Kossakowski added a comment - AFAIK, virtual pattern matcher kicks in only -Yvirtpatmat is supplied. It's off by default.
            Hide
            extempore Paul Phillips added a comment -

            This also regressed with r25935 aka https://github.com/scala/scala/commit/22d125f1e3

            Show
            extempore Paul Phillips added a comment - This also regressed with r25935 aka https://github.com/scala/scala/commit/22d125f1e3
            Hide
            extempore Paul Phillips added a comment -

            Closed #5400 as a duplicate since it regressed in the same commit. Here's the source for an additional test case.

            class Test {
              type AnyCyclic = Execute[Task]#CyclicException[_]
             
              trait Task[T]
             
              trait Execute[A[_] <: AnyRef] {
                class CyclicException[T](val caller: A[T], val target: A[T])
              }
             
              def convertCyclic(c: AnyCyclic): String =
                (c.caller, c.target) match {
                  case (caller: Task[_], target: Task[_]) => "bazinga!"
                }
            }
            

            Show
            extempore Paul Phillips added a comment - Closed #5400 as a duplicate since it regressed in the same commit. Here's the source for an additional test case. class Test { type AnyCyclic = Execute[Task]#CyclicException[_]   trait Task[T]   trait Execute[A[_] <: AnyRef] { class CyclicException[T](val caller: A[T], val target: A[T]) }   def convertCyclic(c: AnyCyclic): String = (c.caller, c.target) match { case (caller: Task[_], target: Task[_]) => "bazinga!" } }
            Hide
            extempore Paul Phillips added a comment -

            Another test case for when this is fixed.

              trait TFn1B {
                type In
                type Out
                type Apply[T <: In] <: Out
              }
             
              trait TFn1[I, O] extends TFn1B {
                type In = I
                type Out = O
              }
             
              trait >>[F1 <: TFn1[_, _], F2 <: TFn1[_, _]] extends TFn1[F1#In, F2#Out] {
                type Apply[T] = F2#Apply[F1#Apply[T]]
              }
            

            Show
            extempore Paul Phillips added a comment - Another test case for when this is fixed. trait TFn1B { type In type Out type Apply[T <: In] <: Out }   trait TFn1[I, O] extends TFn1B { type In = I type Out = O }   trait >>[F1 <: TFn1[_, _], F2 <: TFn1[_, _]] extends TFn1[F1#In, F2#Out] { type Apply[T] = F2#Apply[F1#Apply[T]] }
            Hide
            moors Adriaan Moors added a comment -

            minimal version of the AnyCyclic test case:

            class Test {
              class A[T]
              class B[T](val a: A[T])
             
              case class CaseClass[T](x: T)
             
              def break(existB: B[_]) =
                CaseClass(existB.a) match { case CaseClass(_) => }
            }
            

            Show
            moors Adriaan Moors added a comment - minimal version of the AnyCyclic test case: class Test { class A[T] class B[T](val a: A[T])   case class CaseClass[T](x: T)   def break(existB: B[_]) = CaseClass(existB.a) match { case CaseClass(_) => } }
            Show
            retronym Jason Zaugg added a comment - https://github.com/scala/scala/commit/fc24db4c

              People

              • Assignee:
                odersky Martin Odersky
                Reporter:
                dragos Iulian Dragos
              • Votes:
                0 Vote for this issue
                Watchers:
                9 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: