Details

      Description

      The name-based pattern matcher doesn't like a Product1 extractor.

      The extracted value is taken as `v` instead of `v._1`.

      Here is the test added to `test/files/run/name-based-patmat.scala`:

      package p0 { 
        class Single(val x: Any) extends AnyRef with Product1[String] {
          private def s = "" + x
          override def canEqual(x: Any) = this eq x.asInstanceOf[AnyRef]
          def isEmpty = false
          def get = this
          def _1 = s + " only"
      
          override def toString = s"Single(${_1})"
        }
      
        object Single {
          def unapply(x: Any): Single = new Single(x)
        }
      }
      

      This throws CCE:

          "catdog" match {
            case p0.Single(x) => println(s"`$x` has ${x.length} chars")
            case x            => println("fail: " + x)
          }
      

      FWIW, I was working from this spec (i.e. commit comment):
      "If it does not contain _1, then it is a single value
      extractor analogous like Option[T]."

        Issue Links

          Activity

          Hide
          Paul Phillips added a comment -

          This does the right thing in a hopefully imminent wip.

          Show
          Paul Phillips added a comment - This does the right thing in a hopefully imminent wip.
          Hide
          A. P. Marki added a comment -

          "Wip it good." Is that an old one?

          I have a spec question. Boolean match is achieved by unapply returning boolean. What about `get` returning boolean? It's the same use case. Right now, you must supply a pattern arg. isEmpty means you don't match.

          The additional use case is that in a macro, it's more symmetrical or regular to generate the return of get in one place. I already worked around SI-7897 in the obvious way, `get: String`, so this was the next target.

            class Nada(s: String) extends AnyRef {
              def isEmpty = s != "null"
              def get: Boolean = !isEmpty
          
              override def toString = "Nada"
            }
          
            object Nada {
              def unapply(x: Any): Nada = new Nada(String.valueOf(x))
            }
          

          Trying to eliminate the bad:

              null match {
                case p0.Nada(/*bad*/) => println(s"matched Nada")
                case _         => println("no matchada")
              }
          
          Show
          A. P. Marki added a comment - "Wip it good." Is that an old one? I have a spec question. Boolean match is achieved by unapply returning boolean. What about `get` returning boolean? It's the same use case. Right now, you must supply a pattern arg. isEmpty means you don't match. The additional use case is that in a macro, it's more symmetrical or regular to generate the return of get in one place. I already worked around SI-7897 in the obvious way, `get: String`, so this was the next target. class Nada(s: String) extends AnyRef { def isEmpty = s != "null" def get: Boolean = !isEmpty override def toString = "Nada" } object Nada { def unapply(x: Any): Nada = new Nada(String.valueOf(x)) } Trying to eliminate the bad: null match { case p0.Nada(/*bad*/) => println(s"matched Nada") case _ => println("no matchada") }
          Hide
          Jason Zaugg added a comment -

          Possibly the same issue as SI-7850

          Show
          Jason Zaugg added a comment - Possibly the same issue as SI-7850
          Hide
          Paul Phillips added a comment -

          If it's a boolean extractor, get should actually return Unit. That doesn't work, but it should. Having get return Boolean seems undesirable to me because there's no way to be sure which of isEmpty and get will be honored if they are in disagreement.

          Show
          Paul Phillips added a comment - If it's a boolean extractor, get should actually return Unit. That doesn't work, but it should. Having get return Boolean seems undesirable to me because there's no way to be sure which of isEmpty and get will be honored if they are in disagreement.
          Hide
          Paul Phillips added a comment -

          From some experience with it I can say the way it should be specified that isEmpty is always checked first and if it's false it will never match. I forget what makes me say that or what alternative I'm positioning it against, but I know there was something.

          Also, it's important that get returning boolean is not the same use case. If get returns boolean the unapply encodes three possible outcomes. If the unapply returns boolean it encodes two possible outcomes.

          If I were designing my own pattern matcher there would be a first class Product and all extractors would return some efficiently encoded variation of Option[Product[Arity]], but as it is there's not going to be a way to abstract uniformly over unapply return types.

          Show
          Paul Phillips added a comment - From some experience with it I can say the way it should be specified that isEmpty is always checked first and if it's false it will never match. I forget what makes me say that or what alternative I'm positioning it against, but I know there was something. Also, it's important that get returning boolean is not the same use case. If get returns boolean the unapply encodes three possible outcomes. If the unapply returns boolean it encodes two possible outcomes. If I were designing my own pattern matcher there would be a first class Product and all extractors would return some efficiently encoded variation of Option[Product [Arity] ], but as it is there's not going to be a way to abstract uniformly over unapply return types.
          Show
          Paul Phillips added a comment - https://github.com/scala/scala/pull/3275

            People

            • Assignee:
              Paul Phillips
              Reporter:
              A. P. Marki
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development