I'm porting a macro from Scala 2 to Scala 3. As part of it's work, the Scala 2 macro creates an instance of a generic type using the default constructor. This is simple to do with a quasiquote in Scala 2, but I'm struggling with Scala 3 macros. This is my best approach so far:
import scala.quoted.*
inline def make[A <: AnyRef]: A = ${ makeThat[A] }
private def makeThat[A <: AnyRef : Type](using Quotes): Expr[A] =
import quotes.reflect.*
'{ new A().asInstanceOf[A] }
Without the .asInstanceOf[A]
, the compiler emits an error message:
[error] -- [E007] Type Mismatch Error: ...
[error] 17 | '{ new A() }
[error] | ^^^^^^^
[error] |Found: Object
[error] |Required: A
[error] |
[error] |where: A is a type in method makeThat with bounds <: AnyRef
[error] one error found
Is there a better solution without a downcast at runtime?
EDIT: As of Scala 3.0.1, this doesn't even compile anymore.
You can create the right tree with the lower level reflect API.
import scala.quoted.*
inline def make[A <: AnyRef]: A = ${ makeThat[A] }
def makeThat[A <: AnyRef : Type](using Quotes): Expr[A] =
import quotes.reflect.*
TypeRepr.of[A].classSymbol.map( sym =>
Apply(Select(New(TypeTree.of[A]), sym.primaryConstructor), Nil).asExprOf[A]
)
.getOrElse(???) // not a class, so can't instantiate
Though you should include a check to see if your constructor doesn't have parameters.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With