Skip to content

Expr.betaReduce does not correctly handle inlining function literals type-ascribed to subclasses of Function #8290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
fhackett opened this issue Feb 11, 2020 · 2 comments

Comments

@fhackett
Copy link
Contributor

minimized code

abstract class Test extends (Int => Int) {
  def impl(i: Int): Int
  def apply(i: Int): Int = -1
}
// ...
object Macros {
  inline def dummy : Test =
    (i: Int) => i + 1

  inline def test : Int =
    ${ testImpl }
  def testImpl(using: QuoteContext): Expr[Int]
    Expr.betaReduce('{ dummy })('{ 5 })
}
// ...
object Test {
  def main(argv: Array[String]): Unit =
    println(s"${ Macros.test }")
}

Runtime output

6

expectation

-1
@fhackett
Copy link
Contributor Author

The rabbit hole goes even deeper - I just learned that type ascriptions in Scala are not algebraically transitive:

abstract class Test1 extends (Int => Int) {
  def apply(s: String): String
}
abstract class Test2 extends Test1 {
  def apply(s: String): String = "gotcha"
}
// ...
( (i: Int) => i + 1 ) : Test2 : Test1

@fhackett
Copy link
Contributor Author

fhackett commented Feb 11, 2020

... actually, yes they are [re: ascription transitivity]. Closure.tpt contains the necessary info to handle SAM cases.

I learned that the inliner has its own betaReduce, here: https://github.com/lampepfl/dotty/blob/a29178ce4ac848e773423f57f45186373f410970/compiler/src/dotty/tools/dotc/typer/Inliner.scala#L804-L824

This other betaReduce rejects SAM closures, and given the amount of complexity my attempt to properly handle SAM closures introduces I think it's probably a good idea to imitate the inliner for now. In any case, that will prevent the crashes and strange behaviours this issue is talking about.

fhackett added a commit to fhackett/dotty that referenced this issue Feb 11, 2020
…ion typed closure expression

This commit addresses 2 issues with existing betaReduce behaviour:
- when given a non-function typed closure the previous iteration could easily fail to resolve the correct apply method,
  or even successfully inline the wrong code (see added test cases)
- if betaReduce did not successfully inline, it would return a transformed tree. This was fine until the above change made
  it possible to give up while inside a closureDef, which could insert a type ascription inside the closureDef's block,
  leading to betaReduce returning invalid trees (the closureDef block can only contain a DefDef and Closure, no
  type ascriptions). Fixing this issue would add meaningless complexity, so instead this commit changes betaReduce to
  cleanly give up by returning the function tree unchanged, only generating the code necessary to call it.

Note: this change affects a few tests that were checking for betaReduce's slight changes to the function tree.

Testing the correctness of this change is done by adding cases to existing tests for betaReduce's treatment of type
ascriptions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants