Skip to content

Commit e1de43d

Browse files
Merge pull request #11537 from dotty-staging/fix-#11483
Inlined non-eta-expanded trees message
2 parents ce30a1c + 5ea0084 commit e1de43d

File tree

3 files changed

+124
-22
lines changed

3 files changed

+124
-22
lines changed

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

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
264264
object DefDef extends DefDefModule:
265265
def apply(symbol: Symbol, rhsFn: List[List[Tree]] => Option[Term]): DefDef =
266266
withDefaultPos(tpd.DefDef(symbol.asTerm, prefss =>
267-
yCheckedOwners(rhsFn(prefss), symbol).getOrElse(tpd.EmptyTree)
267+
yCheckedOwners(yCheckValidExpr(rhsFn(prefss)), symbol).getOrElse(tpd.EmptyTree)
268268
))
269269
def copy(original: Tree)(name: String, paramss: List[ParamClause], tpt: TypeTree, rhs: Option[Term]): DefDef =
270270
tpd.cpy.DefDef(original)(name.toTermName, paramss, tpt, yCheckedOwners(rhs, original.symbol).getOrElse(tpd.EmptyTree))
@@ -293,9 +293,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
293293

294294
object ValDef extends ValDefModule:
295295
def apply(symbol: Symbol, rhs: Option[Term]): ValDef =
296-
tpd.ValDef(symbol.asTerm, yCheckedOwners(rhs, symbol).getOrElse(tpd.EmptyTree))
296+
tpd.ValDef(symbol.asTerm, yCheckedOwners(yCheckValidExpr(rhs), symbol).getOrElse(tpd.EmptyTree))
297297
def copy(original: Tree)(name: String, tpt: TypeTree, rhs: Option[Term]): ValDef =
298-
tpd.cpy.ValDef(original)(name.toTermName, tpt, yCheckedOwners(rhs, original.symbol).getOrElse(tpd.EmptyTree))
298+
tpd.cpy.ValDef(original)(name.toTermName, tpt, yCheckedOwners(yCheckValidExpr(rhs), original.symbol).getOrElse(tpd.EmptyTree))
299299
def unapply(vdef: ValDef): (String, TypeTree, Option[Term]) =
300300
(vdef.name.toString, vdef.tpt, optional(vdef.rhs))
301301

@@ -568,9 +568,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
568568

569569
object NamedArg extends NamedArgModule:
570570
def apply(name: String, arg: Term): NamedArg =
571-
withDefaultPos(tpd.NamedArg(name.toTermName, arg))
571+
withDefaultPos(tpd.NamedArg(name.toTermName, yCheckValidExpr(arg)))
572572
def copy(original: Tree)(name: String, arg: Term): NamedArg =
573-
tpd.cpy.NamedArg(original)(name.toTermName, arg)
573+
tpd.cpy.NamedArg(original)(name.toTermName, yCheckValidExpr(arg))
574574
def unapply(x: NamedArg): (String, Term) =
575575
(x.name.toString, x.value)
576576
end NamedArg
@@ -592,8 +592,10 @@ 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+
yCheckValidExprs(args)
595596
withDefaultPos(tpd.Apply(fun, args))
596597
def copy(original: Tree)(fun: Term, args: List[Term]): Apply =
598+
yCheckValidExprs(args)
597599
tpd.cpy.Apply(original)(fun, args)
598600
def unapply(x: Apply): (Term, List[Term]) =
599601
(x.fun, x.args)
@@ -665,9 +667,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
665667

666668
object Typed extends TypedModule:
667669
def apply(expr: Term, tpt: TypeTree): Typed =
668-
withDefaultPos(tpd.Typed(expr, tpt))
670+
withDefaultPos(tpd.Typed(yCheckValidExpr(expr), tpt))
669671
def copy(original: Tree)(expr: Term, tpt: TypeTree): Typed =
670-
tpd.cpy.Typed(original)(expr, tpt)
672+
tpd.cpy.Typed(original)(yCheckValidExpr(expr), tpt)
671673
def unapply(x: Typed): (Term, TypeTree) =
672674
(x.expr, x.tpt)
673675
end Typed
@@ -689,9 +691,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
689691

690692
object Assign extends AssignModule:
691693
def apply(lhs: Term, rhs: Term): Assign =
692-
withDefaultPos(tpd.Assign(lhs, rhs))
694+
withDefaultPos(tpd.Assign(lhs, yCheckValidExpr(rhs)))
693695
def copy(original: Tree)(lhs: Term, rhs: Term): Assign =
694-
tpd.cpy.Assign(original)(lhs, rhs)
696+
tpd.cpy.Assign(original)(lhs, yCheckValidExpr(rhs))
695697
def unapply(x: Assign): (Term, Term) =
696698
(x.lhs, x.rhs)
697699
end Assign
@@ -754,7 +756,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
754756
object Lambda extends LambdaModule:
755757
def apply(owner: Symbol, tpe: MethodType, rhsFn: (Symbol, List[Tree]) => Tree): Block =
756758
val meth = dotc.core.Symbols.newSymbol(owner, nme.ANON_FUN, Synthetic | Method, tpe)
757-
tpd.Closure(meth, tss => yCheckedOwners(rhsFn(meth, tss.head.map(withDefaultPos)), meth))
759+
tpd.Closure(meth, tss => yCheckedOwners(yCheckValidExpr(rhsFn(meth, tss.head.map(withDefaultPos))), meth))
758760

759761
def unapply(tree: Block): Option[(List[ValDef], Term)] = tree match {
760762
case Block((ddef @ DefDef(_, TermParamClause(params) :: Nil, _, Some(body))) :: Nil, Closure(meth, _))
@@ -774,9 +776,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
774776

775777
object If extends IfModule:
776778
def apply(cond: Term, thenp: Term, elsep: Term): If =
777-
withDefaultPos(tpd.If(cond, thenp, elsep))
779+
withDefaultPos(tpd.If(yCheckValidExpr(cond), yCheckValidExpr(thenp), yCheckValidExpr(elsep)))
778780
def copy(original: Tree)(cond: Term, thenp: Term, elsep: Term): If =
779-
tpd.cpy.If(original)(cond, thenp, elsep)
781+
tpd.cpy.If(original)(yCheckValidExpr(cond), yCheckValidExpr(thenp), yCheckValidExpr(elsep))
780782
def unapply(tree: If): (Term, Term, Term) =
781783
(tree.cond, tree.thenp, tree.elsep)
782784
end If
@@ -800,10 +802,10 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
800802

801803
object Match extends MatchModule:
802804
def apply(selector: Term, cases: List[CaseDef]): Match =
803-
withDefaultPos(tpd.Match(selector, cases))
805+
withDefaultPos(tpd.Match(yCheckValidExpr(selector), cases))
804806

805807
def copy(original: Tree)(selector: Term, cases: List[CaseDef]): Match =
806-
tpd.cpy.Match(original)(selector, cases)
808+
tpd.cpy.Match(original)(yCheckValidExpr(selector), cases)
807809

808810
def unapply(x: Match): (Term, List[CaseDef]) =
809811
(x.scrutinee, x.cases)
@@ -850,9 +852,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
850852

851853
object Try extends TryModule:
852854
def apply(expr: Term, cases: List[CaseDef], finalizer: Option[Term]): Try =
853-
withDefaultPos(tpd.Try(expr, cases, finalizer.getOrElse(tpd.EmptyTree)))
855+
withDefaultPos(tpd.Try(yCheckValidExpr(expr), cases, finalizer.getOrElse(tpd.EmptyTree)))
854856
def copy(original: Tree)(expr: Term, cases: List[CaseDef], finalizer: Option[Term]): Try =
855-
tpd.cpy.Try(original)(expr, cases, finalizer.getOrElse(tpd.EmptyTree))
857+
tpd.cpy.Try(original)(yCheckValidExpr(expr), cases, finalizer.getOrElse(tpd.EmptyTree))
856858
def unapply(x: Try): (Term, List[CaseDef], Option[Term]) =
857859
(x.body, x.cases, optional(x.finalizer))
858860
end Try
@@ -875,9 +877,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
875877

876878
object Return extends ReturnModule:
877879
def apply(expr: Term, from: Symbol): Return =
878-
withDefaultPos(tpd.Return(expr, from))
880+
withDefaultPos(tpd.Return(yCheckValidExpr(expr), from))
879881
def copy(original: Tree)(expr: Term, from: Symbol): Return =
880-
tpd.cpy.Return(original)(expr, tpd.ref(from))
882+
tpd.cpy.Return(original)(yCheckValidExpr(expr), tpd.ref(from))
881883
def unapply(x: Return): (Term, Symbol) =
882884
(x.expr, x.from.symbol)
883885
end Return
@@ -899,8 +901,10 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
899901

900902
object Repeated extends RepeatedModule:
901903
def apply(elems: List[Term], elemtpt: TypeTree): Repeated =
904+
yCheckValidExprs(elems)
902905
withDefaultPos(tpd.SeqLiteral(elems, elemtpt))
903906
def copy(original: Tree)(elems: List[Term], elemtpt: TypeTree): Repeated =
907+
yCheckValidExprs(elems)
904908
tpd.cpy.SeqLiteral(original)(elems, elemtpt)
905909
def unapply(x: Repeated): (List[Term], TypeTree) =
906910
(x.elems, x.elemtpt)
@@ -923,9 +927,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
923927

924928
object Inlined extends InlinedModule:
925929
def apply(call: Option[Tree], bindings: List[Definition], expansion: Term): Inlined =
926-
withDefaultPos(tpd.Inlined(call.getOrElse(tpd.EmptyTree), bindings.map { case b: tpd.MemberDef => b }, expansion))
930+
withDefaultPos(tpd.Inlined(call.getOrElse(tpd.EmptyTree), bindings.map { case b: tpd.MemberDef => b }, yCheckValidExpr(expansion)))
927931
def copy(original: Tree)(call: Option[Tree], bindings: List[Definition], expansion: Term): Inlined =
928-
tpd.cpy.Inlined(original)(call.getOrElse(tpd.EmptyTree), bindings.asInstanceOf[List[tpd.MemberDef]], expansion)
932+
tpd.cpy.Inlined(original)(call.getOrElse(tpd.EmptyTree), bindings.asInstanceOf[List[tpd.MemberDef]], yCheckValidExpr(expansion))
929933
def unapply(x: Inlined): (Option[Tree /* Term | TypeTree */], List[Definition], Term) =
930934
(optional(x.call), x.bindings, x.body)
931935
end Inlined
@@ -978,9 +982,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
978982

979983
object While extends WhileModule:
980984
def apply(cond: Term, body: Term): While =
981-
withDefaultPos(tpd.WhileDo(cond, body))
985+
withDefaultPos(tpd.WhileDo(yCheckValidExpr(cond), yCheckValidExpr(body)))
982986
def copy(original: Tree)(cond: Term, body: Term): While =
983-
tpd.cpy.WhileDo(original)(cond, body)
987+
tpd.cpy.WhileDo(original)(yCheckValidExpr(cond), yCheckValidExpr(body))
984988
def unapply(x: While): (Term, Term) =
985989
(x.cond, x.body)
986990
end While
@@ -2830,6 +2834,18 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
28302834
case _ => traverseChildren(t)
28312835
}.traverse(tree)
28322836

2837+
private def yCheckValidExprs(terms: List[Term]): terms.type =
2838+
if yCheck then terms.foreach(yCheckValidExpr)
2839+
terms
2840+
private def yCheckValidExpr(termOpt: Option[Term]): termOpt.type =
2841+
if yCheck then termOpt.foreach(yCheckValidExpr)
2842+
termOpt
2843+
private def yCheckValidExpr(term: Term): term.type =
2844+
if yCheck then
2845+
assert(!term.tpe.widenDealias.isInstanceOf[dotc.core.Types.MethodicType],
2846+
"Reference to a method must be eta-expanded before it is used as an expression: " + term.show)
2847+
term
2848+
28332849
object Printer extends PrinterModule:
28342850

28352851
lazy val TreeCode: Printer[Tree] = new Printer[Tree]:
@@ -2873,6 +2889,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
28732889
Extractors.showConstant(using QuotesImpl.this)(const)
28742890

28752891
end Printer
2892+
28762893
end reflect
28772894

28782895
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)