Dotty: Overridden inline in class instances does not propogate correctly

Created on 30 Jan 2020  路  3Comments  路  Source: lampepfl/dotty

minimized code

Say that we create a class with an inline member and a macro that prints it during compile-time.

package example
import scala.quoted._
import scala.quoted.matching._
import scala.compiletime._

// Create a class
class DualTestClass {
  inline def v = "foo"
  inline def compiletimeValue: Unit = ${ DualTestClass.compiletimeValueImpl('v) }
}
// Add a macro that prints an inline paramter
object DualTestClass {
  def compiletimeValueImpl(input: Expr[String])(given qctx: QuoteContext): Expr[Unit] = {
    val v = input match { case Value(v) => v }
    println("*********** Compile-Time Value is: " + v + " *******************")
    '{ () }
  }
}
// Then create a instance of that class (using a factory-pattern just because...)
object DualTestClassMaker {
  def make: DualTestClass =
    new DualTestClass {
      override inline def v = "bar"
    }
}

Then let's run this:

package example

@main def dualTestClassTester() = {
  DualTestClassMaker.make.compiletimeValue
}

When the code is compiling, it will print the value:

*********** Compile-Time Value is: foo *******************

As opposed to this which is the expectation.

*********** Compile-Time Value is: bar *******************
bug

Most helpful comment

As far as I can tell, the inline mechanism functions correctly in the examples you gave. You seem to need to take into account that what matters for inline are the _static_ arguments to calls (even more specifically: the _types_ of the static arguments), not the runtime ones.

For instance, in your first example, the static type of the object you call compiletimeValue on is the actual DualTestClass, not the anonymous class that you create inside the body of make. If you made make an inline method, I believe it would work according to your expectations.

If this clears up your doubts, I'll close the issue.

All 3 comments

Also note that when I properly extend DualTestClass like this:

class DualTestClassExt extends DualTestClass {
  override inline def v = "bar"
}

and then run it:

@main def dualTestClassTester() = {
  new DualTestClassExt().compiletimeValue
}

Then the correct value is printed:

*********** Compile-Time Value is: bar *******************

It is also interesting to note that if you try to create the subclass DualTestClassExt inside of a macro (I call it DualTestInst) the same error happens.
Here's the macro:

object DualTestClassMaker {
  import scala.quoted._
  inline def makeMacro: DualTestClass = ${ dualTestImpl }
  def dualTestImpl(given qctx: QuoteContext): Expr[DualTestClass] = {
    '{
      class DualTestInst extends DualTestClass {
        override inline def v = "bar"
      }
      new DualTestInst
    }
  }
}

Then I run it:

@main def dualTestClassTester() = {
  DualTestClassMaker.makeMacro.compiletimeValue
}

It prints out:

*********** Compile-Time Value is: foo *******************

Which is also incorrect.

As far as I can tell, the inline mechanism functions correctly in the examples you gave. You seem to need to take into account that what matters for inline are the _static_ arguments to calls (even more specifically: the _types_ of the static arguments), not the runtime ones.

For instance, in your first example, the static type of the object you call compiletimeValue on is the actual DualTestClass, not the anonymous class that you create inside the body of make. If you made make an inline method, I believe it would work according to your expectations.

If this clears up your doubts, I'll close the issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

liufengyun picture liufengyun  路  3Comments

adamgfraser picture adamgfraser  路  3Comments

ohze picture ohze  路  3Comments

dwijnand picture dwijnand  路  3Comments

LaymanMergen picture LaymanMergen  路  3Comments