scala3
scala3 copied to clipboard
Compiler ignores instance of typeclass and tries to derive it instead
Regression found in Open CB #4758 for wangzaixiang/wjson Part of the 3.2.1-RC1 regressions tracker https://github.com/lampepfl/dotty/issues/15949
There seem to be 2 reasons why code now fails to compile:
- In Scala 3.2.0 compiler used defined instance of
given [T:JsValueMapper]: JsValueMapper[Map[String, T]]
in 3.2.1 it tries to derive type class instead usinggiven [T: JsValueMapper, CC[x] <: IterableOps[x, CC, CC[x]]]: Conversion[CC[T], JsArray]
. See AST below - While deriving
Map[String, Int]
TypeTree.of[T].symbol
whereT=Tuple2[String, Int]
returns NoSymbol
Compiler version
3.2.1-RC1
Minimized code
// test.scala
import scala.collection.IterableOps
enum JsValue:
case JsNumber(value: Double|Long)
case JsString(value: String)
case JsArray(elements: Seq[JsValue])
case JsObject(fields: Map[String, JsValue])
object JsValue:
given [T: JsValueMapper]: Conversion[T, JsValue] = ???
given [T: JsValueMapper, CC[x] <: IterableOps[x, CC, CC[x]]]: Conversion[CC[T], JsArray] = ???
trait JsValueMapper[T]:
def toJson(t: T): JsValue
object JsValueMapper:
inline given[T](using deriving.Mirror.ProductOf[T]): JsValueMapper[T] = ${JsValueMapperMacro.generateImpl[T]}
given JsValueMapper[Int] = ???
given JsValueMapper[String] = ???
given [T:JsValueMapper]: JsValueMapper[Map[String, T]] = ???
extension [T: JsValueMapper](obj: T)
inline def toJson: JsValue = summon[JsValueMapper[T]].toJson(obj)
@main def Test =
val works = Map("a"->1,"b"->2,"c"->3).toJson
val fails = Map("a"->1,"b"->2,"c"->3): JsValue // error
// macro.scala
import scala.quoted.*
import scala.deriving.*
object JsValueMapperMacro:
def generateImpl[T: Type](using Quotes): Expr[JsValueMapper[T]] =
import quotes.reflect.*
import JsValueMapper.*
val sym = TypeTree.of[T].symbol // no symbol for Tuple2[String,Int]
val module = Ref(sym.companionModule)
???
Output
[error] java.lang.AssertionError: assertion failed
[error] at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:11)
[error] at scala.quoted.runtime.impl.QuotesImpl$reflect$Ref$.apply(QuotesImpl.scala:435)
[error] at scala.quoted.runtime.impl.QuotesImpl$reflect$Ref$.apply(QuotesImpl.scala:434)
[error] at JsValueMapperMacro$.generateImpl(macro.scala:9)
[error]
[error] val fails = Map("a"->1,"b"->2,"c"->3): JsValue // error
[error] ^
AST in Scala 3.2.0
val fails: wjson.JsValue =
wjson.JsValue.given_Conversion_T_JsValue[Map[String, Int]](
wjson.JsValueMapper.given_JsValueMapper_Map[Int](
wjson.JsValueMapper.given_JsValueMapper_Int
)
).apply(
Map.apply[String, Int](
[ArrowAssoc[String]("a").->[Int](1),
ArrowAssoc[String]("b").->[Int](2)
,ArrowAssoc[String]("c").->[Int](3) : (String, Int)]*
)
):wjson.JsValue
AST in Scala 3.2.1-RC1
val fails: wjson.JsValue =
wjson.JsValue.given_Conversion_CC_JsArray[(String, Int),
scala.collection.immutable.Iterable
](
wjson.JsValueMapper.given_JsValueMapper_T[(String, Int)](
new scala.runtime.TupleMirror(2).$asInstanceOf[
scala.deriving.Mirror.Product{
MirroredMonoType = (String, Int);
MirroredType = (String, Int)
; MirroredLabel = ("Tuple2" : String);
MirroredElemTypes = (String, Int)
; MirroredElemLabels = (("_1" : String), ("_2" : String))
}
]
)
).apply(
Map.apply[String, Int](
[ArrowAssoc[String]("a").->[Int](1),
ArrowAssoc[String]("b").->[Int](2)
,ArrowAssoc[String]("c").->[Int](3) : (String, Int)]*
)
):wjson.JsValue
Expectation
Should compile