Description
I'd be happy to contribute a PR to fix if necessary.
The inline
doc says
when called with a constant exponent n, the following method for power will be implemented by straight inline code without any loop or recursion.
and then goes on to show this example:
inline def power(x: Double, n: Int): Double =
if n == 0 then 1.0
else if n == 1 then x
else
val y = power(x, n / 2)
if n % 2 == 0 then y * y else y * y * x
power(expr, 10)
// translates to
//
// val x = expr
// val y1 = x * x // ^2
// val y2 = y1 * y1 // ^4
// val y3 = y2 * x // ^5
// y3 * y3 // ^10
So if I understand correctly,
n == 0
andn == 1
occur at compile-time and only match constants.def p(n: Int) = power(expr,n); p(10)
wouldn't translate to the example translation above becausen
would be a dynamic reference rather than a constant.- scalac allows comparisons of arguments to constants like
1
and0
because they're constants in the inline function body
All well and good but what if one wants to simply know whether n
is a constant or not (regardless of the value)?
In my case I was trying to determine whether a String
argument is constant or not.
This doesn't work:
inline given blah(inline body: String): Name =
inline match n
case _: Singleton => Name.now(body)
case _ => Name.lazily(body)
The methods in scala.compiletime
don't seem to help because they're more about types.
My own workaround was to fallback to the quoting API like this:
inline given blah(inline body: String): Name =
${ _blah('body) }
private def _blah(expr: Expr[String])(using Quotes): Expr[Name] = {
import quotes.reflect.*
expr.asTerm match {
case Inlined(_, _, Literal(StringConstant(s))) => '{ Name.now($expr) }
case _ => '{ Name.lazily($expr) }
}
}
It'd be nice to be able to make this work without falling back to quotes. This ability doesn't seem to exist yet, nor does it seem hard to write. I'd be happy to write a PR to add this. Maybe a bunch of methods like inline def stringConstantOpt(inline s: String): Option[String]
for each constant type?