Skip to content

Commit 71ddfb5

Browse files
committed
Fix issue with static this references erroring in quoted code
Previously, inherited methods, even if accessed via static objects, were not able to be used in quotations, unless explicitly pointed to with a non-`this` prefix. This was due to the fact that during the cross-stage safety check, first the method itself was checked for if it was static (which for the inherited method, it was not), and if not, the prefix was checked further, erroring on any `this` tree found along the way. This was fixed by allowing `this` trees if they point to static objects. This way not only is the initial issue fixed, but also we are able to freely reference static methods with `this`, like '{this.objectMethod} (whereas previously, only '{Object.objectMethod} or '{objectMethod} were allowed, despite them all pointing to the same static method).
1 parent 4518ce5 commit 71ddfb5

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,19 +203,27 @@ class CrossStageSafety extends TreeMapWithStages {
203203

204204
/** Check level consistency of terms references */
205205
private def checkLevelConsistency(tree: Ident | This)(using Context): Unit =
206+
def isStatic(pre: Type)(using Context): Boolean = pre match
207+
case pre: NamedType =>
208+
val sym = pre.currentSymbol
209+
sym.is(Package) || sym.isStaticOwner && isStatic(pre.prefix)
210+
case pre: ThisType => isStatic(pre.tref)
211+
case _ => true
206212
new TypeTraverser {
207213
def traverse(tp: Type): Unit =
208214
tp match
209215
case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level != levelOf(tp.symbol) =>
210216
levelError(tp.symbol, tp, tree.srcPos)
217+
case tp: ThisType if isStatic(tp) =>
218+
// static object (OK)
211219
case tp: ThisType if level != -1 && level != levelOf(tp.cls) =>
212220
levelError(tp.cls, tp, tree.srcPos)
213221
case tp: AnnotatedType =>
214222
traverse(tp.parent)
215223
case _ if tp.typeSymbol.is(Package) =>
216224
// OK
217225
case _ =>
218-
traverseChildren(tp)
226+
traverseChildren(tp)
219227
}.traverse(tree.tpe)
220228

221229
private def levelError(sym: Symbol, tp: Type, pos: SrcPos)(using Context): tp.type = {

tests/neg/i22592.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.quoted.*
2+
3+
trait Foo:
4+
def inherited = ()
5+
6+
class Bar extends Foo:
7+
def local = ()
8+
def localArg(arg: Any) = ()
9+
10+
def macro1(using Quotes): Expr[Unit] = '{ local } // error
11+
def macro3(using Quotes): Expr[Unit] = '{ inherited } // error
12+
def macro4(using Quotes): Expr[Unit] = '{ this.local } // error
13+
def macro5(using Quotes): Expr[Unit] = '{ this.inherited } // error
14+
def macro6(using Quotes): Expr[Unit] = '{ localArg(this) } // error // error

tests/pos/i22592.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.quoted.*
2+
3+
trait Foo:
4+
def inherited = ()
5+
6+
object Bar extends Foo:
7+
def local = ()
8+
def localArg(arg: Any) = ()
9+
10+
def macro1(using Quotes): Expr[Unit] = '{ local }
11+
def macro2(using Quotes): Expr[Unit] = '{ Bar.inherited }
12+
def macro3(using Quotes): Expr[Unit] = '{ inherited }
13+
def macro4(using Quotes): Expr[Unit] = '{ this.local }
14+
def macro5(using Quotes): Expr[Unit] = '{ this.inherited }
15+
def macro6(using Quotes): Expr[Unit] = '{ localArg(this) }

0 commit comments

Comments
 (0)