How to Call Inline Methods in Scala 3 Macros?

In Scala 3.6.4, we are implementing a serialization library that involves the use of a type-class called DiscriminationCriteria. This type-class plays a crucial role in determining the appropriate discriminator value for each variant of a sum-type. In this article, we will explore how to properly call inline methods, such as discriminator, from within a macro, addressing a common compilation issue that developers face. Understanding DiscriminatorCriteria The DiscriminationCriteria trait is defined as follows: trait DiscriminationCriteria[-S] { transparent inline def discriminator[P '{ $discriminatorCriteriaExpr.discriminator[VariantType & SumType] } case None => // Fall back to the alphanumerical index Expr[Int](alphanumericIndex) } Here, we use Expr.summon to retrieve an instance of DiscriminationCriteria for a specific sum-type and then we call discriminator on it. The error occurs because invoking an inline method in this context is not allowed. Correcting the Macro Call To successfully call an inline method from a macro in Scala 3, it’s important to ensure that you're not calling it directly on a quoted expression. Instead, you should invoke it at a phase where inline resolution can happen correctly. Here’s how to address this: Step 1: Modify the Macro Instead of calling discriminator directly, we can refer to it within a context where it can be determined correctly. You can achieve this by creating a function that allows invoking discriminator inline within a quote. Step 2: Define a Helper Function Define a helper function that wraps the invocation in a way that resolves at the proper phase: inline def summonDiscriminator[Rep '{ summonDiscriminator[VariantType & SumType] } case None => Expr[Int](alphanumericIndex) } In this manner, we can ensure that the inline method is called correctly and will compile without issues. Conclusion In conclusion, calling inline methods within macros in Scala requires careful handling to ensure proper resolution during compilation. By restructuring our approach to calling the discriminator method through a dedicated helper function, we can avoid the "Deferred inline method cannot be invoked" error. This approach allows for greater flexibility and maintains the benefits of inline methods effectively. Frequently Asked Questions What is an inline method in Scala? An inline method is a method that, during compilation, gets replaced with its actual code, avoiding the overhead of a typical method call. This is particularly useful for performance optimization. What does the transparent modifier do in Scala? The transparent modifier ensures that the inline method behaves as if it were a constant value, making it easier for the compiler to optimize and inline it, leading to better performance. How can I resolve macro compilation issues in Scala? Resolving macro compilation issues often involves restructuring your code to ensure that inline methods are invoked properly, potentially by using helper functions or different invocation contexts.

May 10, 2025 - 07:13
 0
How to Call Inline Methods in Scala 3 Macros?

In Scala 3.6.4, we are implementing a serialization library that involves the use of a type-class called DiscriminationCriteria. This type-class plays a crucial role in determining the appropriate discriminator value for each variant of a sum-type. In this article, we will explore how to properly call inline methods, such as discriminator, from within a macro, addressing a common compilation issue that developers face.

Understanding DiscriminatorCriteria

The DiscriminationCriteria trait is defined as follows:

trait DiscriminationCriteria[-S] {
    transparent inline def discriminator[P <: S]: Int
}

This method needs to be marked as inline to utilize the scala.compiletime.erasedValue functionality effectively. Furthermore, marking it as transparent ensures that the return values are constant, thus allowing the use of singleton types.

The Compilation Issue

The challenge arises when summoning instances of the DiscriminationCriteria type-class within a macro and attempting to invoke the discriminator method. When developers try to compile the code, they often encounter the following error: "Deferred inline method discriminator in trait DiscriminationCriteria cannot be invoked." This error suggests that the method cannot be called in the context it is being used.

Analyzing the Macro Invocation

To investigate this problem, let’s take a closer look at the code snippet that attempts to summon the discriminator:

val discriminatorExpr: Expr[Int] = Expr.summon[DiscriminationCriteria[SumType]] match {
    case Some(discriminatorCriteriaExpr) =>
        '{ $discriminatorCriteriaExpr.discriminator[VariantType & SumType] }
    case None =>
        // Fall back to the alphanumerical index
        Expr[Int](alphanumericIndex)
}

Here, we use Expr.summon to retrieve an instance of DiscriminationCriteria for a specific sum-type and then we call discriminator on it. The error occurs because invoking an inline method in this context is not allowed.

Correcting the Macro Call

To successfully call an inline method from a macro in Scala 3, it’s important to ensure that you're not calling it directly on a quoted expression. Instead, you should invoke it at a phase where inline resolution can happen correctly. Here’s how to address this:

Step 1: Modify the Macro

Instead of calling discriminator directly, we can refer to it within a context where it can be determined correctly. You can achieve this by creating a function that allows invoking discriminator inline within a quote.

Step 2: Define a Helper Function

Define a helper function that wraps the invocation in a way that resolves at the proper phase:

inline def summonDiscriminator[Rep <: S]: Int =
    summon[DiscriminationCriteria[S]].discriminator[Rep]

Step 3: Update the Macro

Now, we can modify the macro expression to call this helper function instead:

val discriminatorExpr: Expr[Int] = Expr.summon[DiscriminationCriteria[SumType]] match {
    case Some(_) =>
        '{ summonDiscriminator[VariantType & SumType] }
    case None =>
        Expr[Int](alphanumericIndex)
}

In this manner, we can ensure that the inline method is called correctly and will compile without issues.

Conclusion

In conclusion, calling inline methods within macros in Scala requires careful handling to ensure proper resolution during compilation. By restructuring our approach to calling the discriminator method through a dedicated helper function, we can avoid the "Deferred inline method cannot be invoked" error. This approach allows for greater flexibility and maintains the benefits of inline methods effectively.

Frequently Asked Questions

What is an inline method in Scala?

An inline method is a method that, during compilation, gets replaced with its actual code, avoiding the overhead of a typical method call. This is particularly useful for performance optimization.

What does the transparent modifier do in Scala?

The transparent modifier ensures that the inline method behaves as if it were a constant value, making it easier for the compiler to optimize and inline it, leading to better performance.

How can I resolve macro compilation issues in Scala?

Resolving macro compilation issues often involves restructuring your code to ensure that inline methods are invoked properly, potentially by using helper functions or different invocation contexts.