Description
There was a quiproquo in the original issue #14226 and it got closed before clarifying it. I will try to reformulate and be as accurate as possible.
Compiler version
3.1.0
Introdution
In Scala 3, you can create traits with inline methods:
trait Test {
inline def msg: String
}
msg
is compiles and runs as expected if the implementation's exact type is known at compile-time:
inline given Test = new TestImpl
summon[Test].msg //Deferred inline
inline given TestImpl = new TestImpl
summon[TestImpl].msg //Compiles and runs
transparent inline given Test = new TestImpl
summon[TestImpl].msg //Compiles and runs
This behaviour is useful when creating typeclasses that have to (or can) be evaluated at compile-time. A minimized example from on of my projects:
trait Constraint[A, -B] {
inline def assert(value: A): Boolean
inline def getMessage(value: A): String
}
implicit inline def refineValue[A, B, C <: Constraint[A, B]](value: A)(using inline constraint: C): A / B = {
Constrained(compileTime.preAssert[A, B, C](value, constraint.getMessage(value), constraint.assert(value)))
}
This code will pass the compile time-evaluated String
constraint.getMessage(value)
and Boolean
constraint.assert(value)
Note: the C
redudant type parameter forces the compiler to get the exact type of the Constraint
implementation.
The Issue
Currently, for Constraints with type parameters, we have to create a brand new class for each implementation:
trait Less[V] extends AlgebraEntryPoint[MathAlgebra] with Transitive[V] with Asymmetric[V, Greater]
class LessConstraint[A <: Number, V <: A] extends Constraint[A, Less[V]] {
override inline def assert(value: A): Boolean = NumberOrdering.lt(value, constValue[V])
override inline def getMessage(value: A): String = "value should be less than the specified one"
}
transparent inline given[A <: Number, V <: A]: Constraint[A, Less[V]] = new LessConstraint
Which works but we actually can't use anonymous given
instances for this:
given [A <: Number, V <: A]: Constraint[A, Less[V]] with {
override inline def assert(value: A): Boolean = NumberOrdering.lt(value, constValue[V])
override inline def getMessage(value: A): String = "value should be less than the specified one"
}
The assert
and getMessage
methods are not fully inline even when called with an inline value
input.
Expectation
I would expect this last example to behave the same as the preceding one above: method calls fully inline.
I hope my issue is now clearer. My goal is not to spam my issue.