Skip to content

Commit d36cd2d

Browse files
Fix references to class members defined in quotes (#17107)
If an inner quote selects a symbol that is defined in an outer quote we need to transform it or reject it. The issue is that the inner quote cannot contain a reference to the type of the class defined in the outer quote. Any such reference is erased the parents of that class that are statically know outside those quotes. If the selected symbol is overriding a symbol in one of those statically known classes, we can use that overridden symbol instead. If not we have to reject the code. Fixes #17103
2 parents 09a73dc + 2d1ef63 commit d36cd2d

File tree

5 files changed

+71
-1
lines changed

5 files changed

+71
-1
lines changed

compiler/src/dotty/tools/dotc/transform/Splicing.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,14 @@ class Splicing extends MacroTransform:
207207

208208
override def transform(tree: tpd.Tree)(using Context): tpd.Tree =
209209
tree match
210+
case tree: Select if tree.isTerm && isCaptured(tree.symbol) =>
211+
tree.symbol.allOverriddenSymbols.find(sym => !isCaptured(sym.owner)) match
212+
case Some(sym) =>
213+
// virtualize call on overridden symbol that is not defined in a non static class
214+
transform(tree.qualifier.select(sym))
215+
case _ =>
216+
report.error(em"Can not use reference to staged local ${tree.symbol} defined in an outer quote.\n\nThis can work if ${tree.symbol.owner} would extend a top level interface that defines ${tree.symbol}.", tree)
217+
tree
210218
case tree: RefTree =>
211219
if tree.isTerm then
212220
if isCaptured(tree.symbol) then

tests/neg-macros/i17103.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import scala.quoted.*
2+
3+
def test(using Quotes): Expr[Unit] =
4+
'{
5+
trait C:
6+
def d: Int
7+
val c: C = ???
8+
${
9+
val expr = '{
10+
val cRef: c.type = ???
11+
cRef.d // error
12+
()
13+
}
14+
expr
15+
}
16+
}

tests/pos-macros/i17103a.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import scala.quoted.*
2+
3+
trait C0:
4+
def d: Int
5+
6+
def test(using Quotes): Expr[Unit] =
7+
'{
8+
trait C1 extends C0:
9+
def d: Int
10+
trait C extends C1:
11+
def d: Int
12+
val c: C = ???
13+
${
14+
val expr = '{
15+
val cRef: C = ???
16+
cRef.d // calls C0.d
17+
()
18+
}
19+
expr
20+
}
21+
}

tests/pos-macros/i17103b.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import scala.quoted.*
2+
3+
trait C0:
4+
def d: Int
5+
6+
def test(using Quotes): Expr[Unit] =
7+
'{
8+
trait C1 extends C0:
9+
def d: Int
10+
trait C extends C1:
11+
def d: Int
12+
val c: C = ???
13+
${
14+
val expr = '{
15+
val cRef: c.type = ???
16+
cRef.d // calls C0.d
17+
()
18+
}
19+
expr
20+
}
21+
}

tests/pos-macros/i7405b.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import scala.quoted.*
33
class Foo {
44
def f(using Quotes): Expr[Any] = {
55
'{
6-
trait X {
6+
trait X extends A {
77
type Y
88
def y: Y = ???
99
}
@@ -17,3 +17,7 @@ class Foo {
1717
}
1818
}
1919
}
20+
21+
trait A:
22+
type Y
23+
def y: Y = ???

0 commit comments

Comments
 (0)