Skip to content

Commit 70ec709

Browse files
Set the correct type when copying reflect Inlined trees (#19409)
Fixes #19191
2 parents b2ba6dc + 2930d2e commit 70ec709

File tree

4 files changed

+80
-1
lines changed

4 files changed

+80
-1
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,11 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
10301030
def apply(call: Option[Tree], bindings: List[Definition], expansion: Term): Inlined =
10311031
withDefaultPos(tpd.Inlined(call.getOrElse(tpd.EmptyTree), bindings.map { case b: tpd.MemberDef => b }, xCheckMacroValidExpr(expansion)))
10321032
def copy(original: Tree)(call: Option[Tree], bindings: List[Definition], expansion: Term): Inlined =
1033-
tpd.Inlined(call.getOrElse(tpd.EmptyTree), bindings.asInstanceOf[List[tpd.MemberDef]], xCheckMacroValidExpr(expansion)).withSpan(original.span).withType(original.tpe)
1033+
original match
1034+
case original: Inlined =>
1035+
tpd.cpy.Inlined(original)(call.getOrElse(tpd.EmptyTree), bindings.asInstanceOf[List[tpd.MemberDef]], xCheckMacroValidExpr(expansion))
1036+
case original =>
1037+
throw new IllegalArgumentException(i"Expected argument `original` to be an `Inlined` but was: ${original.show}")
10341038
def unapply(x: Inlined): (Option[Tree /* Term | TypeTree */], List[Definition], Term) =
10351039
(optional(x.call), x.bindings, x.body)
10361040
end Inlined

tests/pos-macros/i19191/Lib_1.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
trait Binding[+A]:
2+
def value: A = ???
3+
object Binding:
4+
inline def apply[A](inline a: A): Binding[A] = ???
5+
final case class Constant[+A](override val value: A) extends Binding[A]
6+
7+
extension [A](inline binding: Binding[A])
8+
transparent inline def bind: A = null.asInstanceOf[A]
9+
10+
trait Vars[A] extends BindingSeq[A]
11+
trait BindingSeq[+A]:
12+
def foreachBinding[U](f: A => Binding[U]): Binding[Unit] = ???
13+
14+
extension [A](inline bindingSeq: BindingSeq[A])
15+
transparent inline def foreach[U](inline f: A => U): Unit = ${ Macros.foreach('bindingSeq, 'f) }

tests/pos-macros/i19191/Macro_1.scala

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import scala.compiletime._
2+
import scala.deriving._
3+
import scala.quoted._
4+
import scala.annotation.meta.field
5+
6+
object Macros{
7+
private def bindingFunctionBody[A: quoted.Type, B: quoted.Type](f: quoted.Expr[A => B])(using Quotes) =
8+
import quoted.quotes.reflect.*
9+
f.asTerm match
10+
case inlined @ Inlined(
11+
call,
12+
bindings,
13+
block @ Block(
14+
List(
15+
defDef @ DefDef(
16+
name,
17+
paramss @ List(TermParamClause(List(param @ ValDef(paramName, paramTpt, _)))),
18+
tpt,
19+
Some(rhs)
20+
)
21+
),
22+
closureIdent
23+
)
24+
) =>
25+
Inlined
26+
.copy(inlined)(
27+
call,
28+
bindings,
29+
'{ (a: A) =>
30+
${
31+
Block(
32+
List(
33+
ValDef
34+
.copy(param)(paramName, paramTpt, Some('a.asTerm))
35+
.changeOwner(Symbol.spliceOwner)
36+
),
37+
'{
38+
Binding(${ rhs.changeOwner(Symbol.spliceOwner).asExprOf[B] })
39+
}.asTerm.changeOwner(Symbol.spliceOwner)
40+
)
41+
.asExprOf[Binding[B]]
42+
}: Binding[B]
43+
}.asTerm
44+
)
45+
.asExprOf[A => Binding[B]]
46+
case _ =>
47+
'{ (a: A) => Binding.Constant($f(a)): Binding[B] }
48+
end match
49+
end bindingFunctionBody
50+
51+
def foreach[A: quoted.Type, U: quoted.Type](self: quoted.Expr[BindingSeq[A]], f: quoted.Expr[A => U])(using
52+
qctx: Quotes
53+
): quoted.Expr[Unit] = '{ $self.foreachBinding(${ bindingFunctionBody(f) }).bind }
54+
}

tests/pos-macros/i19191/Test_2.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
def Test = {
2+
val vars: Vars[Int] = ???
3+
4+
val works = vars.foreach { v => () }
5+
val fails = for (v <- vars) ()
6+
}

0 commit comments

Comments
 (0)