3

我开始为 Scala 中的 X500PrincipalBuilder 类编写单元测试。这是我的测试代码:

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))
        }
      }
    }
  }
}

但是,当使用 Scala 2.9.2 或 2.10.0 编译此代码时,我遇到了编译器崩溃。这是 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)

2.10.0 的输出似乎是一些难以理解的伪代码来生成 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 这意味着什么,我该如何解决?

4

1 回答 1

8

此崩溃似乎是由SI-6317引起的,其中使用匿名部分函数(with case (...) =>)有时会杀死编译器。

票证中有一个修复程序,但它似乎还没有进入 2.10.1(参见adriaanm/scala@08dffa3scala/scala@2.10.1),但它确实提供了一种解决方法:

给出foreach一个做 amatch本身而不是给它 a的函数PartialFunction

attributes foreach { _ match { case (key, value) => b addAttribute (key, value)}}
于 2013-05-16T17:48:25.073 回答