Skip to content

Commit 9e5f77f

Browse files
committed
Inlined non-eta-expanded trees message
Closes #11483
1 parent 12f34c2 commit 9e5f77f

File tree

3 files changed

+95
-0
lines changed

3 files changed

+95
-0
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,11 +592,15 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
592592

593593
object Apply extends ApplyModule:
594594
def apply(fun: Term, args: List[Term]): Apply =
595+
yCheckArgs(args)
595596
withDefaultPos(tpd.Apply(fun, args))
596597
def copy(original: Tree)(fun: Term, args: List[Term]): Apply =
598+
yCheckArgs(args)
597599
tpd.cpy.Apply(original)(fun, args)
598600
def unapply(x: Apply): (Term, List[Term]) =
599601
(x.fun, x.args)
602+
private def yCheckArgs(args: List[Term]): Unit =
603+
if yCheck then args.foreach(yCheckValidExpr)
600604
end Apply
601605

602606
given ApplyMethods: ApplyMethods with
@@ -2873,6 +2877,12 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
28732877
Extractors.showConstant(using QuotesImpl.this)(const)
28742878

28752879
end Printer
2880+
2881+
private def yCheckValidExpr(term: Term): Unit =
2882+
if yCheck then
2883+
assert(!term.tpe.widenDealias.isInstanceOf[dotc.core.Types.MethodicType],
2884+
"Reference to method must be eta-expanded before it is used as an expression: " + term.show)
2885+
28762886
end reflect
28772887

28782888
def unpickleExpr[T](pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.Quotes) => scala.quoted.Expr[?]): scala.quoted.Expr[T] =

tests/neg-macros/i11483/Macro_1.scala

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package x
2+
3+
import scala.annotation._
4+
import scala.quoted._
5+
import scala.compiletime._
6+
7+
8+
trait CpsMonad[F[_]]:
9+
10+
def pure[T](x:T):F[T]
11+
12+
def impure[T](x:F[T]):T
13+
14+
def map[A,B](x:F[A])(f: A=>B):F[B]
15+
16+
17+
@compileTimeOnly("await should be inside async block")
18+
def await[F[_],T](f:F[T])(using am:CpsMonad[F]):T = ???
19+
20+
inline given conversion[F[_],T](using CpsMonad[F]): Conversion[F[T],T] =
21+
x => await(x)
22+
23+
24+
object X {
25+
26+
inline def process[F[_], T](inline t:T)(using m: CpsMonad[F]):F[T] =
27+
${ processImpl[F,T]('t, 'm) }
28+
29+
30+
def processImpl[F[_]:Type, T:Type](t:Expr[T], m:Expr[CpsMonad[F]])(using Quotes):Expr[F[T]] =
31+
import quotes.reflect._
32+
val r = processTree[F,T](t.asTerm, m.asTerm)
33+
r.asExprOf[F[T]]
34+
35+
36+
def processTree[F[_]:Type, T:Type](using Quotes)(t: quotes.reflect.Term, m: quotes.reflect.Term):quotes.reflect.Term =
37+
import quotes.reflect._
38+
val r: Term = t match
39+
case Inlined(_,List(),body) => processTree[F,T](body, m)
40+
case Inlined(d,bindings,body) =>
41+
Inlined(d,bindings,processTree[F,T](body, m))
42+
case Block(stats,expr) => Block(stats,processTree(expr, m))
43+
case Apply(Apply(TypeApply(Ident("await"),targs),List(body)),List(m)) => body
44+
case Apply(f,List(arg)) =>
45+
val nArg = processTree[F,String](arg, m)
46+
Apply(Apply(TypeApply(Select.unique(m,"map"),
47+
List(Inferred(arg.tpe.widen),Inferred(t.tpe.widen))
48+
),
49+
List(nArg)),
50+
List(f)
51+
)
52+
case Apply(f,List()) =>
53+
Apply(TypeApply(Select.unique(m,"pure"),List(Inferred(t.tpe.widen))),List(t))
54+
case Typed(x,tp) => Typed(processTree(x,m), Inferred(TypeRepr.of[F].appliedTo(tp.tpe)) )
55+
case _ => throw new RuntimeException(s"tree not recoginized: $t")
56+
r
57+
58+
59+
}

tests/neg-macros/i11483/Test_2.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package x
2+
3+
import scala.language.implicitConversions
4+
import scala.concurrent.Future
5+
6+
given FutureAsyncMonad: CpsMonad[Future] with
7+
def pure[T](t:T): Future[T] = ???
8+
def impure[T](t:Future[T]): T = ???
9+
def map[A,B](x:Future[A])(f: A=>B): Future[B] = ???
10+
11+
12+
object Api:
13+
14+
def doSomething():Future[String] =
15+
Future.successful("doSomething")
16+
17+
def println(x:String):Unit =
18+
Console.println(x)
19+
20+
21+
object Main:
22+
23+
def main(args: Array[String]): Unit =
24+
X.process[Future,Unit]{ // error
25+
Api.println(Api.doSomething())
26+
}

0 commit comments

Comments
 (0)