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

Pattern Matcher substitution doesn't handle references in singleton types #7459

Closed
scabug opened this issue May 6, 2013 · 16 comments
Closed
Assignees
Labels
Milestone

Comments

@scabug
Copy link

scabug commented May 6, 2013

With the following tail-recursive version of ListMap.remove:

@tailrec private def remove0(k: A, cur: ListMap[A, B1], acc: List[ListMap[A, B1]]): ListMap[A, B1] =
  if (cur.isEmpty)
    acc.last
  else if (k == cur.key)
    (cur.tail /: acc) {
      case (t, h) => new t.Node(h.key, h.value)
    }
  else
    remove0(k, cur.tail, cur::acc)

the exception is raised:

[quick.library] symbol value t does not exist in scala.collection.immutable.ListMap$Node.remove0
[quick.library]         at scala.reflect.internal.SymbolTable.abort(SymbolTable.scala:52)
[quick.library]         at scala.tools.nsc.Global.abort(Global.scala:251)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadIdent$1(GenICode.scala:887)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:893)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$genLoadArguments$1.apply(GenICode.scala:1124)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$genLoadArguments$1.apply(GenICode.scala:1122)
[quick.library]         at scala.collection.LinearSeqOptimized$class.foldLeft(LinearSeqOptimized.scala:109)
[quick.library]         at scala.collection.immutable.List.foldLeft(List.scala:84)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadArguments(GenICode.scala:1122)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadApply3$1(GenICode.scala:696)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:706)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:926)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:918)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$genLoadArguments$1.apply(GenICode.scala:1124)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$genLoadArguments$1.apply(GenICode.scala:1122)
[quick.library]         at scala.collection.LinearSeqOptimized$class.foldLeft(LinearSeqOptimized.scala:109)
[quick.library]         at scala.collection.immutable.List.foldLeft(List.scala:84)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadArguments(GenICode.scala:1122)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadApply6$1(GenICode.scala:777)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:811)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadQualifier(GenICode.scala:1083)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadApply1$1(GenICode.scala:612)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:637)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:918)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadIf(GenICode.scala:372)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:535)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadIf(GenICode.scala:373)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:535)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:926)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadLabelDef$1(GenICode.scala:504)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:506)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:918)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.gen(GenICode.scala:122)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$gen$1.apply(GenICode.scala:70)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$gen$1.apply(GenICode.scala:70)
[quick.library]         at scala.collection.immutable.List.foreach(List.scala:301)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.gen(GenICode.scala:70)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.gen(GenICode.scala:147)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.gen(GenICode.scala:97)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$gen$1.apply(GenICode.scala:70)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$gen$1.apply(GenICode.scala:70)
[quick.library]         at scala.collection.immutable.List.foreach(List.scala:301)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.gen(GenICode.scala:70)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.gen(GenICode.scala:88)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$gen$1.apply(GenICode.scala:70)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$gen$1.apply(GenICode.scala:70)
[quick.library]         at scala.collection.immutable.List.foreach(List.scala:301)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.gen(GenICode.scala:70)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.gen(GenICode.scala:88)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.gen(GenICode.scala:66)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.apply(GenICode.scala:62)
[quick.library]         at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:413)
[quick.library]         at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:380)
[quick.library]         at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:380)
[quick.library]         at scala.collection.Iterator$class.foreach(Iterator.scala:743)
[quick.library]         at scala.collection.AbstractIterator.foreach(Iterator.scala:1174)
[quick.library]         at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:380)
[quick.library]         at scala.tools.nsc.backend.icode.GenICode$ICodePhase.run(GenICode.scala:55)
[quick.library]         at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1518)
[quick.library]         at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1493)
[quick.library]         at scala.tools.nsc.Global$Run.compileSources(Global.scala:1489)
[quick.library]         at scala.tools.nsc.Global$Run.compile(Global.scala:1596)
[quick.library]         at scala.tools.nsc.Driver.doCompile(Driver.scala:33)
[quick.library]         at scala.tools.nsc.MainClass.doCompile(Main.scala:23)
[quick.library]         at scala.tools.nsc.Driver.process(Driver.scala:54)
[quick.library]         at scala.tools.nsc.Driver.main(Driver.scala:67)
[quick.library]         at scala.tools.nsc.Main.main(Main.scala)
[quick.library]
@scabug
Copy link
Author

scabug commented May 6, 2013

Imported From: https://issues.scala-lang.org/browse/SI-7459?orig=1
Reporter: @vigdorchik
Affected Versions: 2.11.0-M2

@scabug
Copy link
Author

scabug commented May 6, 2013

@retronym said:
Minimized:

class LM {
  class Node[B1]

  // crash
  val f: (LM => Any) = {
    case t => new t.Node[Any]()
  }

  // okay
  val g: (LM => Any) = {
    t => new t.Node[Any]()
  }
}

@scabug
Copy link
Author

scabug commented May 6, 2013

@paulp said:
Regression from 2.10.0. 494ba94518 is the first bad commit.

@scabug
Copy link
Author

scabug commented May 6, 2013

@paulp said:
Oh, but amusingly it's in 2.9. In 2.9, not in 2.10.0, back in 2.10.1.

@scabug
Copy link
Author

scabug commented May 6, 2013

@retronym said (edited on May 6, 2013 8:14:07 PM UTC):
Are you sure?

I see at least the the minimized snippet crashing from 2.10.0-M1 until the present day.

  /code/scala cat sandbox/t7459.scala
package test

class LM {
  class Node[B1]

  // crash
  val f: (LM => Any) = {
    case t => new t.Node[Any]()
  }

  // okay
  val g: (LM => Any) = {
    t => new t.Node[Any]()
  }
}
  /code/scala RUNNER=scalac scala-hash master sandbox/t7459.scala 2>&1 | grep "symbol value t"
error: symbol value t does not exist in test.LM.<init>
symbol value t does not exist in test.LM.<init>") @ scala.reflect.internal.SymbolTable.abort(SymbolTable.scala:51)
symbol value t does not exist in test.LM.<init>

  /code/scala RUNNER=scalac scala-hash v2.10.1 sandbox/t7459.scala 2>&1 | grep "symbol value t"
error: symbol value t does not exist in test.LM.<init>
symbol value t does not exist in test.LM.<init>

  /code/scala RUNNER=scalac scala-hash v2.10.0 sandbox/t7459.scala 2>&1 | grep "symbol value t"
error: symbol value t does not exist in test.LM.<init>
symbol value t does not exist in test.LM.<init>
symbol value t does not exist in test.LM.<init>

  /code/scala RUNNER=scalac scala-hash v2.10.0-M1 sandbox/t7459.scala 2>&1 | grep "symbol value t"
error: symbol value t does not exist in test.LM$$anonfun$1.apply
error: scala.reflect.internal.FatalError: symbol value t does not exist in test.LM$$anonfun$1.apply
error: fatal error: symbol value t does not exist in test.LM$$anonfun$1.apply

@scabug
Copy link
Author

scabug commented May 7, 2013

@retronym said (edited on May 7, 2013 6:28:40 AM UTC):
In any case, the code to blame is PatternMatching#Substitution. Ideally that would be a vanilla substituteSymbols. I'll take a look.

@scabug
Copy link
Author

scabug commented May 7, 2013

@retronym said:
Here's another test case the eludes my first attempt at a fix:

class LM {
  class Node[B1]

  // crash
  val g: (CC => Any) = {
    case CC(tttt) =>
      // tttt.##
      new tttt.Node[Any]()
  }
}

@scabug
Copy link
Author

scabug commented May 7, 2013

@vigdorchik said:
Your last example fails on master (and presumably 2.10.1) but works ok on 2.10.0 for me.

@scabug
Copy link
Author

scabug commented May 7, 2013

@paulp said:
Right, nobody's test cases seem particularly self-contained but yesterday I minimized my way to one which definitely works on 2.10.0 and for which the commit I cited was when it stopped working post-2.10 (but it doesn't work in 2.9 either.) Here is another which fits that description:

class LM {
  class Node[B1]
  case class CC(x: LM)

  // crash
  val g: (CC => Any) = {
    case CC(tttt) =>
      // tttt.##
      new tttt.Node[Any]()
  }
}
% scalac-hash 494ba94518^ z.scala 
% scalac-hash 494ba94518 z.scala 
error: symbol value tttt does not exist in LM.<init>
error: uncaught exception during compilation: scala.reflect.internal.FatalError
error: scala.reflect.internal.FatalError: 

@scabug
Copy link
Author

scabug commented May 7, 2013

@retronym said:
This isn't quite complete, but it moves in the right direction:

https://github.com/retronym/scala/compare/ticket/7459

It still leaves unsubstituted references in cases where the 'to' trees in the substitution are Selects, rather than simple Idents.

object Test extends App {
  class C { class D }

  case class FooSeq(x: Int, y: String, z: C*)

  FooSeq(1, "a", ???) match {
    case FooSeq(1, "a", x@_* ) =>
      null.asInstanceOf[x.type]
  }
}
      case <synthetic> val x1: Test.FooSeq = Test.this.FooSeq.apply(1, "a", scala.this.Predef.???);
      case8(){
        if (x1.ne(null))
          {
            <synthetic> val p2: Int = x1.x;
            <synthetic> val p3: String = x1.y;
            if (1.==(p2))
              if ("a".==(p3))
                matchEnd7(null.asInstanceOf[x.type])
              else
                case9()
            else
              case9()
          }
        else
          case9()
      };

I'm going to assign to Adriaan for an opinion.

@scabug
Copy link
Author

scabug commented May 13, 2013

@vigdorchik said:
Any news on this? Besides IMHO being a blocker, this blocks ListMap#- refactoring that removes unneeded allocations.

@scabug
Copy link
Author

scabug commented May 13, 2013

@retronym said:
You can work around the problem by adding an unused binding into the case body, e.g. val tt = t; new t.Node.

It's not a regression, so I don't think this blocks 2.10.2. But we should fix ASAP. Adriaan is travelling right now, which is why he hasn't had a chance to comment.

@scabug
Copy link
Author

scabug commented Jul 28, 2013

@retronym said:
Merging with #7701.

class Attr { type V ; class Val }
class StrAttr extends Attr { type V = String }
class BoolAttr extends Attr { type V = Boolean }

object Main {
  def f(x: Attr) = x match {
    case v: StrAttr  => new v.Val
    case v: BoolAttr => new v.Val
  }
}

@scabug
Copy link
Author

scabug commented Nov 30, 2013

@vigdorchik said:
Anything new on this issue? It looks like there is no progress in 2.11 either...

@scabug
Copy link
Author

scabug commented Feb 8, 2014

@retronym said:
scala/scala#3490

@scabug
Copy link
Author

scabug commented Nov 9, 2014

@retronym said:
I've found a way to get that branch working, so I'm taking another swing for 2.11.5: scala/scala#4122

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

No branches or pull requests

2 participants