Skip to content

Commit c20c16d

Browse files
jchybtgodzik
authored andcommitted
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). [Cherry-picked 71ddfb5]
1 parent bb8eb47 commit c20c16d

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
@@ -189,19 +189,27 @@ class CrossStageSafety extends TreeMapWithStages {
189189

190190
/** Check level consistency of terms references */
191191
private def checkLevelConsistency(tree: Ident | This)(using Context): Unit =
192+
def isStatic(pre: Type)(using Context): Boolean = pre match
193+
case pre: NamedType =>
194+
val sym = pre.currentSymbol
195+
sym.is(Package) || sym.isStaticOwner && isStatic(pre.prefix)
196+
case pre: ThisType => isStatic(pre.tref)
197+
case _ => true
192198
new TypeTraverser {
193199
def traverse(tp: Type): Unit =
194200
tp match
195201
case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level != levelOf(tp.symbol) =>
196202
levelError(tp.symbol, tp, tree.srcPos)
203+
case tp: ThisType if isStatic(tp) =>
204+
// static object (OK)
197205
case tp: ThisType if level != -1 && level != levelOf(tp.cls) =>
198206
levelError(tp.cls, tp, tree.srcPos)
199207
case tp: AnnotatedType =>
200208
traverse(tp.parent)
201209
case _ if tp.typeSymbol.is(Package) =>
202210
// OK
203211
case _ =>
204-
traverseChildren(tp)
212+
traverseChildren(tp)
205213
}.traverse(tree.tpe)
206214

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