I was just experimenting with the behavior of givens and inline in Scala 3.2.2, and ran into the following example:
trait Max[X]:
inline def max(a: X, b: X): X
inline given maxForDoubles: Max[Double] with
inline def max(a: Double, b: Double) = if a < b then b else a
inline given maxForPairs[A, B](using mA: Max[A], mB: Max[B]): Max[(A, B)] with
inline def max(x: (A, B), y: (A, B)) =
(mA.max(x._1, y._1), mB.max(x._2, y._2))
@main def entryPoint(): Unit = {
println(summon[Max[(Double, Double)]].max((10.0, 3.0), (20.0, -7.0)))
}
Instead of just printing the pair (20, 3), it fails the compilation with the following error:
12 | println(summon[Max[(Double, Double)]].max((10.0, 3.0), (20.0, -7.0)))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Deferred inline method max in trait Max cannot be invoked
|----------------------------------------------------------------------------
|Inline stack trace
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|This location contains code that was inlined from buggy-example.scala:9
9 | (mA.max(x._1, y._1), mB.max(x._2, y._2))
| ^^^^^^
----------------------------------------------------------------------------
It seems that it should know everything statically. Any clues why it's failing?
If you tried to use alias givens rather than given instances (
with-syntax)this wouldn't work because of
But with
with-syntax nestedinlineare allowed becauseis actually
Indeed, with
-Xprint:pickleQuotesoption (or-Xprint:typer) thewith-syntax producesLet's temporarily simplify the
with-syntax removingusingandmaxForDoublesThen the difference between
and
is understandable because there is a rule
https://docs.scala-lang.org/scala3/reference/metaprogramming/inline.html#rules-for-overriding
And
maxis exactly an abstract inline method in the traitMax.summon[Max[(Double, Double)]]returns the precise type of implicit:maxForPairs[Double, Double] <: Max[(Double, Double)](asshapeless.thein Scala 2), not justMax[(Double, Double)](asimplicitlyin Scala 2).But if we restore
usingandmaxForDoublesthen for some reason this confuses inlines: both options forval inst(: maxForPairs[Double, Double]and: Max[(Double, Double)]) produceDeferred inline method max in trait Max cannot be invoked.This seems to be a bug or underspecified feature. Try to open a ticket at https://github.com/lampepfl/dotty/issues
By the way, sometimes
with-syntax behaves weirdly in comparison with alias givens (even without inlines): https://github.com/lampepfl/dotty/issues/8882