Scala 2の場合のscalikejdbc.autoConstructのバグの説明

以下の解説

github.com

おそらく、新しいScala 2.13、かつ "-Xsource:3" か "-Xsource:3-cross" を指定しないと発生しない?ので、だいぶややこしいですね。Scala 2.12やScala 3ではおそらく発生しないです。

Scala 2には、なぜかpackage object内部のimplicitが、importしなくても勝手に有効になる謎挙動がありました。

https://github.com/scala/scala/pull/10621

それはScala 3で改善され、また、最新のScala 2.13で移行用の "-Xsource:3" や "-Xsource:3-cross" を指定すると、それを使っていたら怒られるか、強制的にScala 3と同じ挙動になったりします。

このあまり知られていない微妙な挙動にscalikejdbcのautoConstructが依存していました。

以下のメソッドです

https://github.com/scalikejdbc/scalikejdbc/blob/cb374af49d079576a429d70165cdccd8d7556c61/scalikejdbc-core/src/main/scala/scalikejdbc/interpolation/Implicits.scala

これの定義自体はpackage objectではないですが、結局package objectに(色々経由した挙句に)mixinされています。 *1

というわけで

「最新のScala 2.13で移行用の "-Xsource:3" や "-Xsource:3-cross" 指定した場合だけ、autoConstructのmacro内部でtype errorになる」

ということが発生します。

普通は、macroの内部で生成するTreeは、呼び出し側のimportの影響を受けるべきではありません。呼び出し側の追加のimportを必要とするべきではありません。 (あえてそれをやるすごい黒魔術テクニックはあり得なくはないが、99.99%オススメしない) Scala 3と異なり、Scala 2ではそういうmacroが意図せず書けてしまうというのは別問題としてありますが・・・。

というわけで、そのimplicit defに頼らずに、明示的に .value を呼ぶだけの修正を出しました。

これが入ったものがリリースされれば

「 "-Xsource:3-cross" 指定したらエラーになったんですが???」

というパターンは無くなるはずです。

それまでの対処法としては

import scalikejdbc._

ワイルドカードimportするか

import scalikejdbc.scalikejdbcSQLSyntaxToStringImplicitDef

とするくらいですかね。いっそのことautoConstruct使うのやめてもいいですが、そこまでするほどではない・・・はず。

*1:それ自体が歴史的経緯でややこしいというか、そもそもpackage objectに継承させるの非推奨になるかも???という別の問題もある