プロジェクト内から参照したいオープン ソース プロジェクト用の SBT ビルドを生成しようとしましたが、コンパイラのバグと思われるものに遭遇しました。
次のコードは、eclipse/scala-ide で期待どおりにコンパイルおよび実行されますが、scala 2.10.6 コンパイラはそれを消化できません。
package foo
import scala.language.dynamics
object Caller extends App {
val client = new Client() // initialise an R interpreter
client.x = 1.0
}
class Client extends Dynamic {
var map = Map.empty[String, Any]
def selectDynamic(name: String) = map get name getOrElse sys.error("field not found")
def updateDynamic(name: String)(value: Any) { map += name -> value }
}
これが私のbuild.sbtです:
scalaVersion := "2.10.6"
libraryDependencies++= Seq(
"org.scalanlp" %% "breeze" % "0.12"
)
scalaVersion := 2.10.6 を指定すると、次のコンパイル エラーが発生します。
[error] /home/philwalk/dynsbt/src/main/scala/foo/Caller.scala:8: type mismatch;
[error] found : foo.Caller.client.type (with underlying type foo.Client)
[error] required: ?{def x: ?}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error] both method any2Ensuring in object Predef of type [A](x: A)Ensuring[A]
[error] and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
[error] are possible conversion functions from foo.Caller.client.type to ?{def x: ?}
[error] client.x = Seq("a","b","c")
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 3 s, completed May 3, 2016 11:03:08 AM
scalaVersion := 2.11.8 では、問題はありませんが、クロスコンパイルする必要があるため、回避策ではありません。
もう 1 つの手がかりは、次のコード行を変更することで問題を隠すことができるということです。
client.x = 1.0
これに:
client.xx = 1.0
scalac 2.10.6 で直接コンパイルした場合にも問題が発生します。
回避策として、プロジェクトをリファクタリングして 1 文字より長いフィールド名を使用することができますが、これは私のプロジェクトではないため、回避策として受け入れることができるものには多少の制約があります。また、これは Breeze.linalg プロジェクトであり、単一文字の行列名とベクトル名を許可しないことは深刻な制限となります。
問題を大規模なプロジェクトからこのコード フラグメントに要約するのに数時間かかりました。このオープン ソース ライブラリの scala 2.10 バージョンに制限を課したくありません。このバグは scala 2.11 で修正されたようですので、修正を 2.10 にバックポートしないことが決定されたと思います。
回避策の存在を反映するようにタイトルを変更しました (より長いフィールド名)。