Skip to content

Commit c7a88fa

Browse files
committed
WIP: Construct trees for HOAS patterns respecting eta expansion
1 parent 209d763 commit c7a88fa

File tree

3 files changed

+51
-29
lines changed

3 files changed

+51
-29
lines changed

compiler/src/scala/quoted/runtime/impl/QuoteMatcher.scala

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import dotty.tools.dotc.core.Symbols.*
1111
import dotty.tools.dotc.util.optional
1212
import dotty.tools.dotc.core.Types
1313
import dotty.tools.dotc.core.Definitions
14+
import dotty.tools.dotc.ast.untpd
1415

1516
/** Matches a quoted tree against a quoted pattern tree.
1617
* A quoted pattern tree may have type and term holes in addition to normal terms.
@@ -508,14 +509,30 @@ object QuoteMatcher {
508509
case Block(List(DefDef(nme.ANON_FUN, _, _, Apply(Ident(name), _))), _) => name.asTermName
509510
case arg => arg.symbol.name.asTermName
510511
}
511-
val paramTypes = args.map(x => mapTypeHoles(x.tpe.widenTermRefExpr))
512+
val paramTypes = args.map(x => adaptTypes(mapTypeHoles(x.tpe.widenTermRefExpr)))
512513
val methTpe = MethodType(names)(_ => paramTypes, _ => mapTypeHoles(patternTpe))
513514
val meth = newAnonFun(ctx.owner, methTpe)
514515
def bodyFn(lambdaArgss: List[List[Tree]]): Tree = {
515516
val argsMap = args.view.map(_.symbol).zip(lambdaArgss.head).toMap
516517
val body = new TreeMap {
517518
override def transform(tree: Tree)(using Context): Tree =
518519
tree match
520+
/*
521+
* When matching a method call `f(0)` against a HOAS pattern `p(g)` where
522+
* f has a method type `(x: Int): Int` and `f` maps to `g`, `p` should be `g.apply(0)`
523+
* because the type of `g` is `Int => Int` due to eta expansion.
524+
*
525+
* Remaining TODOs from issue-17105
526+
* * [ ] cover the case of nested method call
527+
* * [ ] contextual params?
528+
* * [ ] erasure types?
529+
*/
530+
case Apply(methId: Ident, args) =>
531+
val fnId = env.get(tree.symbol).flatMap(argsMap.get).getOrElse(tree)
532+
ctx.typer.typed(
533+
untpd.Apply(
534+
untpd.Select(untpd.TypedSplice(fnId), nme.apply),
535+
args.map(untpd.TypedSplice(_))))
519536
case tree: Ident => env.get(tree.symbol).flatMap(argsMap.get).getOrElse(tree)
520537
case tree => super.transform(tree)
521538
}.transform(tree)

tests/run-macros/i17105/Macro_1.scala

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
11
import scala.quoted.*
22

3-
inline def test1: String = ${ testExpr1 }
4-
def testExpr1(using Quotes): Expr[String] =
5-
'{ def f(x: Int) = 1; val n = 2; f(n) } match
6-
case '{ def g(y: Int) = 1; val n = 2; $a(g, n): Int } => Expr(a.show)
3+
inline def testExpr(inline body: Any) = ${ testExprImpl('body) }
4+
def testExprImpl(body: Expr[Any])(using Quotes): Expr[String] =
5+
body match
6+
case '{ def g(y: Int) = "hello" * y; $a(g): String } =>
7+
'{ $a((z:Int) => "this is " + z.toString()) }
78
case _ => Expr("not matched")
89

9-
inline def test2: String = ${ testExpr2 }
10-
def testExpr2(using Quotes): Expr[String] =
11-
'{ def f(x: Int, y:Int) = 1; f(1, 2) } match
12-
case '{ def g(y: Int, z:Int) = 1; $a(g): Int } => Expr(a.show)
13-
case _ => Expr("not matched")
10+
// TODO issue-17105: Clean this up if not neccessary
11+
// inline def test1: String = ${ testExpr1 }
12+
// def testExpr1(using Quotes): Expr[String] =
13+
// '{ def f(x: Int) = 1; val n = 2; f(n) } match
14+
// case '{ def g(y: Int) = 1; val n = 2; $a(g, n): Int } => Expr(a.show)
15+
// case _ => Expr("not matched")
1416

15-
inline def test3: String = ${ testExpr3 }
16-
def testExpr3(using Quotes): Expr[String] =
17-
'{
18-
def f1(using Ordered[Int]) =
19-
def f2(using Ordered[Int]) =
20-
1 < 2
21-
f2 || 2 < 3: Boolean
22-
} match
23-
case '{
24-
def g1(using ord: Ordered[Int]) =
25-
def g2(using Ordered[Int]) =
26-
1 < 2
27-
$a(g2, ord): Boolean
28-
} => Expr(a.show)
29-
case _ => Expr("not matched")
17+
// inline def test2: String = ${ testExpr2 }
18+
// def testExpr2(using Quotes): Expr[String] =
19+
// '{ def f(x: Int, y:Int) = 1; f(1, 2) } match
20+
// case '{ def g(y: Int, z:Int) = 1; $a(g): Int } => Expr(a.show)
21+
// case _ => Expr("not matched")
3022

23+
// inline def test3: String = ${ testExpr3 }
24+
// def testExpr3(using Quotes): Expr[String] =
25+
// '{
26+
// def f1(using Ordered[Int]) =
27+
// def f2(using Ordered[Int]) =
28+
// 1 < 2
29+
// f2 || 2 < 3: Boolean
30+
// } match
31+
// case '{
32+
// def g1(using ord: Ordered[Int]) =
33+
// def g2(using Ordered[Int]) =
34+
// 1 < 2
35+
// $a(g2, ord): Boolean
36+
// } => Expr(a.show)
37+
// case _ => Expr("not matched")

tests/run-macros/i17105/Test_2.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
@main def Test: Unit =
2-
println(test1)
3-
println(test2)
4-
println(test3)
1+
@main def app: Unit =
2+
testExpr { def f(x: Int) = "hello" * x; f(0) + "bye" }

0 commit comments

Comments
 (0)