3

I was starting to write a unit test for an X500PrincipalBuilder class in Scala. Here's my test code:

import org.junit.runner.RunWith
import org.scalatest.WordSpec
import org.scalatest.junit.JUnitRunner
import org.scalatest.matchers.ShouldMatchers._
import org.scalatest.prop.PropertyChecks._
import javax.security.auth.x500.X500Principal

@RunWith(classOf[JUnitRunner])
class X500PrincipalBuilderTest extends WordSpec {

  "An X500 Principal Builder" when {
    "given a list of attributes" should {
      "properly build an X500 Principal" in {
        val table = Table(
          ("expected", "attributes"),
          ("CN=Duke", List("CN" -> "Duke"))
        )
        forAll (table) { (expected, attributes) =>
          val b = new X500PrincipalBuilder
          attributes foreach { case (key, value) => b addAttribute (key, value) }
          b.build should equal (new X500Principal(expected))
        }
      }
    }
  }
}

However, when compiling this code with Scala 2.9.2 or 2.10.0, I get a compiler crash. Here's the initial stacktrace from 2.9.2:

[ERROR] error: java.lang.Error: no-symbol does not have owner
[INFO]  at scala.tools.nsc.symtab.SymbolTable.abort(SymbolTable.scala:34)
[INFO]  at scala.tools.nsc.symtab.Symbols$NoSymbol$.owner(Symbols.scala:2155)
[INFO]  at scala.tools.nsc.symtab.Symbols$Symbol.logicallyEnclosingMember(Symbols.scala:1251)
[INFO]  at scala.tools.nsc.transform.LambdaLift$LambdaLifter.searchIn$1(LambdaLift.scala:234)
[INFO]  at scala.tools.nsc.transform.LambdaLift$LambdaLifter.proxy(LambdaLift.scala:243)
[INFO]  at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$proxyRef(LambdaLift.scala:259)
[INFO]  at scala.tools.nsc.transform.LambdaLift$LambdaLifter.postTransform(LambdaLift.scala:389)
[INFO]  at scala.tools.nsc.transform.LambdaLift$LambdaLifter.transform(LambdaLift.scala:412)
... (removed some hundred stack frames)

The output from 2.10.0 seems to be some incomprehensible pseudo code to generate an AST:

[INFO]
[INFO]      while compiling: /Users/christian/code/truelicense~v2/truelicense-core/src/test/scala/net/java/truelicense/core/util/X500PrincipalBuilderTest.scala
[INFO]         during phase: global=lambdalift, atPhase=constructors
[INFO]      library version: version 2.10.0
[INFO]     compiler version: version 2.10.0
[INFO]   reconstructed args: -deprecation -feature -classpath /Users/christian/code/truelicense~v2/truelicense-core/target/classes:/Users/christian/.m2/repository/net/java/truelicense/truelicense-obfuscate/2.3-SNAPSHOT/truelicense-obfuscate-2.3-SNAPSHOT.jar:/Users/christian/.m2/repository/commons-codec/commons-codec/1.8/commons-codec-1.8.jar:/Users/christian/.m2/repository/org/slf4j/slf4j-simple/1.7.5/slf4j-simple-1.7.5.jar:/Users/christian/.m2/repository/org/slf4j/slf4j-api/1.7.5/slf4j-api-1.7.5.jar:/Users/christian/.m2/repository/com/google/code/findbugs/annotations/2.0.1/annotations-2.0.1.jar:/Users/christian/.m2/repository/junit/junit/4.11/junit-4.11.jar:/Users/christian/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/Users/christian/.m2/repository/org/mockito/mockito-core/1.9.5/mockito-core-1.9.5.jar:/Users/christian/.m2/repository/org/objenesis/objenesis/1.3/objenesis-1.3.jar:/Users/christian/.m2/repository/org/scalatest/scalatest_2.10.0/1.8/scalatest_2.10.0-1.8.jar:/Users/christian/.m2/repository/org/scala-lang/scala-library/2.10.0/scala-library-2.10.0.jar:/Users/christian/.m2/repository/org/scala-lang/scala-actors/2.10.0/scala-actors-2.10.0.jar:/Users/christian/.m2/repository/org/scala-lang/scala-reflect/2.10.0/scala-reflect-2.10.0.jar:/Users/christian/.m2/repository/org/scalacheck/scalacheck_2.10.0/1.10.0/scalacheck_2.10.0-1.10.0.jar:/Users/christian/.m2/repository/org/scala-tools/testing/test-interface/0.5/test-interface-0.5.jar:/Users/christian/code/truelicense~v2/truelicense-core/target/test-classes -d /Users/christian/code/truelicense~v2/truelicense-core/target/test-classes
[INFO]
[INFO]   last tree to typer: term $outer
[INFO]               symbol: value $outer (flags: <synthetic> <paramaccessor> <triedcooking> private[this])
[INFO]    symbol definition: private[this] val $outer: net.java.truelicense.core.util.X500PrincipalBuilderTest
[INFO]                  tpe: <notype>
[INFO]        symbol owners: value $outer -> anonymous class $anonfun$1 -> value <local X500PrincipalBuilderTest> -> class X500PrincipalBuilderTest -> package util
[INFO]       context owners: value key -> value $anonfun -> value $anonfun -> method apply -> anonymous class $anonfun$apply$mcV$sp$2 -> method apply$mcV$sp -> anonymous class $anonfun$apply$mcV$sp$1 -> method apply$mcV$sp -> anonymous class $anonfun$1 -> value <local X500PrincipalBuilderTest> -> class X500PrincipalBuilderTest -> package util
[INFO]
[INFO] == Enclosing template or block ==
[INFO]
[INFO] DefDef( // final def apply(x$1: Tuple2): Unit
[INFO]   <method> final <triedcooking>
[INFO]   "apply"
[INFO]   []
[INFO]   // 1 parameter list
[INFO]   ValDef( // x0$2: Tuple2
[INFO]     <param> <synthetic> <triedcooking>
[INFO]     "x0$2"
[INFO]     <tpt> // tree.tpe=Tuple2
[INFO]     <empty>
[INFO]   )
[INFO]   <tpt> // tree.tpe=Unit
[INFO]   Block( // tree.tpe=Unit
[INFO]     // 3 statements
[INFO]     ValDef( // case val x1: Tuple2
[INFO]       case <synthetic> <triedcooking>
[INFO]       "x1"
[INFO]       <tpt> // tree.tpe=Tuple2
[INFO]       "x0$2" // x0$2: Tuple2, tree.tpe=Tuple2
[INFO]     )
[INFO]     LabelDef( // case def case4(): Unit, tree.tpe=Unit
[INFO]       ()
[INFO]       If( // tree.tpe=Unit
[INFO]         Apply( // final def ne(x$1: Object): Boolean in class Object, tree.tpe=Boolean
[INFO]           "x1"."ne" // final def ne(x$1: Object): Boolean in class Object, tree.tpe=(x$1: Object)Boolean
[INFO]           null
[INFO]         )
[INFO]         Block( // tree.tpe=Unit
[INFO]           // 2 statements
[INFO]           ValDef( // val key: String
[INFO]             <triedcooking>
[INFO]             "key"
[INFO]             <tpt> // tree.tpe=String
[INFO]             Apply( // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=String
[INFO]               TypeApply( // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=()String
[INFO]                 x1._1()."$asInstanceOf" // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=[T0 >: ? <: ?]()T0
[INFO]                 <tpt> // tree.tpe=String
[INFO]               )
[INFO]               Nil
[INFO]             )
[INFO]           )
[INFO]           ValDef( // val value: String
[INFO]             <triedcooking>
[INFO]             "value"
[INFO]             <tpt> // tree.tpe=String
[INFO]             Apply( // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=String
[INFO]               TypeApply( // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=()String
[INFO]                 x1._2()."$asInstanceOf" // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=[T0 >: ? <: ?]()T0
[INFO]                 <tpt> // tree.tpe=String
[INFO]               )
[INFO]               Nil
[INFO]             )
[INFO]           )
[INFO]           Apply( // case def matchEnd3(x: runtime.BoxedUnit): Unit, tree.tpe=Unit
[INFO]             "matchEnd3" // case def matchEnd3(x: runtime.BoxedUnit): Unit, tree.tpe=(x: runtime.BoxedUnit)Unit
[INFO]             Block( // tree.tpe=runtime.BoxedUnit
[INFO]               Apply( // def addAttribute(x$1: String,x$2: String): Unit in class X500PrincipalBuilder, tree.tpe=Unit
[INFO]                 "b"."addAttribute" // def addAttribute(x$1: String,x$2: String): Unit in class X500PrincipalBuilder, tree.tpe=(x$1: String, x$2: String)Unit
[INFO]                 // 2 arguments
[INFO]                 "key" // val key: String, tree.tpe=String
[INFO]                 "value" // val value: String, tree.tpe=String
[INFO]               )
[INFO]               "scala"."runtime"."BoxedUnit"."UNIT" // final val UNIT: runtime.BoxedUnit in object BoxedUnit, tree.tpe=runtime.BoxedUnit
[INFO]             )
[INFO]           )
[INFO]         )
[INFO]         Apply( // case def case5(): Unit, tree.tpe=Unit
[INFO]           "case5" // case def case5(): Unit, tree.tpe=()Unit
[INFO]           Nil
[INFO]         )
[INFO]       )
[INFO]     )
[INFO]     LabelDef( // case def case5(): Unit, tree.tpe=Unit
[INFO]       ()
[INFO]       Apply( // case def matchEnd3(x: runtime.BoxedUnit): Unit, tree.tpe=Unit
[INFO]         "matchEnd3" // case def matchEnd3(x: runtime.BoxedUnit): Unit, tree.tpe=(x: runtime.BoxedUnit)Unit
[INFO]         Throw( // tree.tpe=Nothing
[ERROR]           Apply( // def <init>(obj: Object): MatchError in class MatchError, tree.tpe=MatchError
[ERROR]             new MatchError."<init>" // def <init>(obj: Object): MatchError in class MatchError, tree.tpe=(obj: Object)MatchError
[INFO]             "x1" // case val x1: Tuple2, tree.tpe=Tuple2
[INFO]           )
[INFO]         )
[INFO]       )
[INFO]     )
[INFO]     LabelDef( // case def matchEnd3(x: runtime.BoxedUnit): Unit, tree.tpe=Unit
[INFO]       "x" // x: runtime.BoxedUnit, tree.tpe=runtime.BoxedUnit
[INFO]       ()
[INFO]     )
[INFO]   )
[INFO] )
[INFO]
[INFO] == Expanded type of tree ==
[INFO]
[INFO] <notype>
[INFO]
[INFO] unhandled exception while transforming X500PrincipalBuilderTest.scala
[ERROR] error:
[INFO]      while compiling: /Users/christian/code/truelicense~v2/truelicense-core/src/test/scala/net/java/truelicense/core/util/X500PrincipalBuilderTest.scala
[INFO]         during phase: lambdalift
[INFO]      library version: version 2.10.0
[INFO]     compiler version: version 2.10.0
[INFO]   reconstructed args: -deprecation -feature -classpath /Users/christian/code/truelicense~v2/truelicense-core/target/classes:/Users/christian/.m2/repository/net/java/truelicense/truelicense-obfuscate/2.3-SNAPSHOT/truelicense-obfuscate-2.3-SNAPSHOT.jar:/Users/christian/.m2/repository/commons-codec/commons-codec/1.8/commons-codec-1.8.jar:/Users/christian/.m2/repository/org/slf4j/slf4j-simple/1.7.5/slf4j-simple-1.7.5.jar:/Users/christian/.m2/repository/org/slf4j/slf4j-api/1.7.5/slf4j-api-1.7.5.jar:/Users/christian/.m2/repository/com/google/code/findbugs/annotations/2.0.1/annotations-2.0.1.jar:/Users/christian/.m2/repository/junit/junit/4.11/junit-4.11.jar:/Users/christian/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/Users/christian/.m2/repository/org/mockito/mockito-core/1.9.5/mockito-core-1.9.5.jar:/Users/christian/.m2/repository/org/objenesis/objenesis/1.3/objenesis-1.3.jar:/Users/christian/.m2/repository/org/scalatest/scalatest_2.10.0/1.8/scalatest_2.10.0-1.8.jar:/Users/christian/.m2/repository/org/scala-lang/scala-library/2.10.0/scala-library-2.10.0.jar:/Users/christian/.m2/repository/org/scala-lang/scala-actors/2.10.0/scala-actors-2.10.0.jar:/Users/christian/.m2/repository/org/scala-lang/scala-reflect/2.10.0/scala-reflect-2.10.0.jar:/Users/christian/.m2/repository/org/scalacheck/scalacheck_2.10.0/1.10.0/scalacheck_2.10.0-1.10.0.jar:/Users/christian/.m2/repository/org/scala-tools/testing/test-interface/0.5/test-interface-0.5.jar:/Users/christian/code/truelicense~v2/truelicense-core/target/test-classes -d /Users/christian/code/truelicense~v2/truelicense-core/target/test-classes
[INFO]
[INFO]   last tree to typer: term $outer
[INFO]               symbol: value $outer (flags: <synthetic> <paramaccessor> <triedcooking> private[this])
[INFO]    symbol definition: private[this] val $outer: net.java.truelicense.core.util.X500PrincipalBuilderTest
[INFO]                  tpe: <notype>
[INFO]        symbol owners: value $outer -> anonymous class $anonfun$1 -> value <local X500PrincipalBuilderTest> -> class X500PrincipalBuilderTest -> package util
[INFO]       context owners: value key -> value $anonfun -> value $anonfun -> method apply -> anonymous class $anonfun$apply$mcV$sp$2 -> method apply$mcV$sp -> anonymous class $anonfun$apply$mcV$sp$1 -> method apply$mcV$sp -> anonymous class $anonfun$1 -> value <local X500PrincipalBuilderTest> -> class X500PrincipalBuilderTest -> package util
[INFO]
[INFO] == Enclosing template or block ==
[INFO]
[INFO] DefDef( // final def apply(x$1: Tuple2): Unit
[INFO]   <method> final <triedcooking>
[INFO]   "apply"
[INFO]   []
[INFO]   // 1 parameter list
[INFO]   ValDef( // x0$2: Tuple2
[INFO]     <param> <synthetic> <triedcooking>
[INFO]     "x0$2"
[INFO]     <tpt> // tree.tpe=Tuple2
[INFO]     <empty>
[INFO]   )
[INFO]   <tpt> // tree.tpe=Unit
[INFO]   Block( // tree.tpe=Unit
[INFO]     // 3 statements
[INFO]     ValDef( // case val x1: Tuple2
[INFO]       case <synthetic> <triedcooking>
[INFO]       "x1"
[INFO]       <tpt> // tree.tpe=Tuple2
[INFO]       "x0$2" // x0$2: Tuple2, tree.tpe=Tuple2
[INFO]     )
[INFO]     LabelDef( // case def case4(): Unit, tree.tpe=Unit
[INFO]       ()
[INFO]       If( // tree.tpe=Unit
[INFO]         Apply( // final def ne(x$1: Object): Boolean in class Object, tree.tpe=Boolean
[INFO]           "x1"."ne" // final def ne(x$1: Object): Boolean in class Object, tree.tpe=(x$1: Object)Boolean
[INFO]           null
[INFO]         )
[INFO]         Block( // tree.tpe=Unit
[INFO]           // 2 statements
[INFO]           ValDef( // val key: String
[INFO]             <triedcooking>
[INFO]             "key"
[INFO]             <tpt> // tree.tpe=String
[INFO]             Apply( // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=String
[INFO]               TypeApply( // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=()String
[INFO]                 x1._1()."$asInstanceOf" // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=[T0 >: ? <: ?]()T0
[INFO]                 <tpt> // tree.tpe=String
[INFO]               )
[INFO]               Nil
[INFO]             )
[INFO]           )
[INFO]           ValDef( // val value: String
[INFO]             <triedcooking>
[INFO]             "value"
[INFO]             <tpt> // tree.tpe=String
[INFO]             Apply( // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=String
[INFO]               TypeApply( // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=()String
[INFO]                 x1._2()."$asInstanceOf" // final def $asInstanceOf[T0 >: ? <: ?](): T0 in class Object, tree.tpe=[T0 >: ? <: ?]()T0
[INFO]                 <tpt> // tree.tpe=String
[INFO]               )
[INFO]               Nil
[INFO]             )
[INFO]           )
[INFO]           Apply( // case def matchEnd3(x: runtime.BoxedUnit): Unit, tree.tpe=Unit
[INFO]             "matchEnd3" // case def matchEnd3(x: runtime.BoxedUnit): Unit, tree.tpe=(x: runtime.BoxedUnit)Unit
[INFO]             Block( // tree.tpe=runtime.BoxedUnit
[INFO]               Apply( // def addAttribute(x$1: String,x$2: String): Unit in class X500PrincipalBuilder, tree.tpe=Unit
[INFO]                 "b"."addAttribute" // def addAttribute(x$1: String,x$2: String): Unit in class X500PrincipalBuilder, tree.tpe=(x$1: String, x$2: String)Unit
[INFO]                 // 2 arguments
[INFO]                 "key" // val key: String, tree.tpe=String
[INFO]                 "value" // val value: String, tree.tpe=String
[INFO]               )
[INFO]               "scala"."runtime"."BoxedUnit"."UNIT" // final val UNIT: runtime.BoxedUnit in object BoxedUnit, tree.tpe=runtime.BoxedUnit
[INFO]             )
[INFO]           )
[INFO]         )
[INFO]         Apply( // case def case5(): Unit, tree.tpe=Unit
[INFO]           "case5" // case def case5(): Unit, tree.tpe=()Unit
[INFO]           Nil
[INFO]         )
[INFO]       )
[INFO]     )
[INFO]     LabelDef( // case def case5(): Unit, tree.tpe=Unit
[INFO]       ()
[INFO]       Apply( // case def matchEnd3(x: runtime.BoxedUnit): Unit, tree.tpe=Unit
[INFO]         "matchEnd3" // case def matchEnd3(x: runtime.BoxedUnit): Unit, tree.tpe=(x: runtime.BoxedUnit)Unit
[INFO]         Throw( // tree.tpe=Nothing
[ERROR]           Apply( // def <init>(obj: Object): MatchError in class MatchError, tree.tpe=MatchError
[ERROR]             new MatchError."<init>" // def <init>(obj: Object): MatchError in class MatchError, tree.tpe=(obj: Object)MatchError
[INFO]             "x1" // case val x1: Tuple2, tree.tpe=Tuple2
[INFO]           )
[INFO]         )
[INFO]       )
[INFO]     )
[INFO]     LabelDef( // case def matchEnd3(x: runtime.BoxedUnit): Unit, tree.tpe=Unit
[INFO]       "x" // x: runtime.BoxedUnit, tree.tpe=runtime.BoxedUnit
[INFO]       ()
[INFO]     )
[INFO]   )
[INFO] )
[INFO]
[INFO] == Expanded type of tree ==
[INFO]
[INFO] <notype>
[INFO]
[INFO] uncaught exception during compilation: java.lang.IllegalArgumentException
[ERROR] error: java.lang.IllegalArgumentException: Could not find proxy for case val x1: Tuple2 in List(value x1, method apply, anonymous class $anonfun$apply$1, method apply, anonymous class $anonfun$apply$mcV$sp$3, method apply$mcV$sp, anonymous class $anonfun$apply$mcV$sp$2, method apply$mcV$sp, anonymous class $anonfun$apply$mcV$sp$1, method apply$mcV$sp, anonymous class $anonfun$1, value <local X500PrincipalBuilderTest>, class X500PrincipalBuilderTest, package util, package core, package truelicense, package java, package net, package <root>) (currentOwner= value key )
[INFO]  at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:303)
[INFO]  at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:308)
[INFO]  at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:308)
[INFO]  at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:308)
... (removed some hundred stack frames)

WTF does this mean and how can I work around it?

3
  • 2.10.1 fixed a crash of this sort. Have you tried it? Commented May 16, 2013 at 17:18
  • I haven't been able to convince my build to use 2.10.1 yet because the dependency coordinates for scalatest and scalacheck don't follow the usual pattern when using 2.10.1 - grrr. Commented May 16, 2013 at 17:45
  • Nope, same for 2.10.1. Commented May 16, 2013 at 17:51

1 Answer 1

8

This crash seems to be caused by SI-6317, where using an anonymous partial function (with case (...) =>) sometime slays the compiler.

There is a fix given in the ticket, but it seems like it hasn't made its way into 2.10.1 (see adriaanm/scala@08dffa3 versus scala/[email protected]), but it does give a workaround:

Giving foreach a function that does a match itself instead of giving it a PartialFunction:

attributes foreach { _ match { case (key, value) => b addAttribute (key, value)}}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.