Skip to content

Commit 12af044

Browse files
Backport "Patch underlyingArgument to avoid mapping into modules" to LTS (#20777)
Backports #18923 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents 7481bfa + 279a510 commit 12af044

File tree

3 files changed

+97
-1
lines changed

3 files changed

+97
-1
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1253,7 +1253,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
12531253
*/
12541254
private class MapToUnderlying extends TreeMap {
12551255
override def transform(tree: Tree)(using Context): Tree = tree match {
1256-
case tree: Ident if isBinding(tree.symbol) && skipLocal(tree.symbol) =>
1256+
case tree: Ident if isBinding(tree.symbol) && skipLocal(tree.symbol) && !tree.symbol.is(Module) =>
12571257
tree.symbol.defTree match {
12581258
case defTree: ValOrDefDef =>
12591259
val rhs = defTree.rhs
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import scala.quoted._
2+
import scala.compiletime.testing.{typeChecks, typeCheckErrors}
3+
4+
trait Assertion
5+
trait Bool {
6+
def value: Boolean
7+
}
8+
class SimpleMacroBool(expression: Boolean) extends Bool {
9+
override def value: Boolean = expression
10+
}
11+
class BinaryMacroBool(left: Any, operator: String, right: Any, expression: Boolean) extends Bool {
12+
override def value: Boolean = expression
13+
}
14+
object Bool {
15+
def simpleMacroBool(expression: Boolean): Bool = new SimpleMacroBool(expression)
16+
def binaryMacroBool(left: Any, operator: String, right: Any, expression: Boolean): Bool =
17+
new BinaryMacroBool(left, operator, right, expression)
18+
def binaryMacroBool(left: Any, operator: String, right: Any, bool: Bool): Bool =
19+
new BinaryMacroBool(left, operator, right, bool.value)
20+
}
21+
22+
object Assertions {
23+
inline def assert(inline condition: Boolean): Assertion =
24+
${ AssertionsMacro.assert('{ condition }) }
25+
}
26+
27+
object AssertionsMacro {
28+
def assert(condition: Expr[Boolean])(using Quotes): Expr[Assertion] =
29+
transform(condition)
30+
31+
def transform(
32+
condition: Expr[Boolean]
33+
)(using Quotes): Expr[Assertion] = {
34+
val bool = BooleanMacro.parse(condition)
35+
'{
36+
new Assertion {
37+
val condition = $bool
38+
}
39+
}
40+
}
41+
}
42+
43+
object BooleanMacro {
44+
private val supportedBinaryOperations =
45+
Set("!=", "==")
46+
47+
def parse(condition: Expr[Boolean])(using Quotes): Expr[Bool] = {
48+
import quotes.reflect._
49+
import quotes.reflect.ValDef.let
50+
import util._
51+
52+
def exprStr: String = condition.show
53+
def defaultCase = '{ Bool.simpleMacroBool($condition) }
54+
55+
def isByNameMethodType(tp: TypeRepr): Boolean = tp.widen match {
56+
case MethodType(_, ByNameType(_) :: Nil, _) => true
57+
case _ => false
58+
}
59+
60+
condition.asTerm.underlyingArgument match { // WARNING: unsound use of `underlyingArgument`
61+
case Apply(sel @ Select(lhs, op), rhs :: Nil) =>
62+
def binaryDefault =
63+
if (isByNameMethodType(sel.tpe)) defaultCase
64+
else if (supportedBinaryOperations.contains(op)) {
65+
let(Symbol.spliceOwner, lhs) { left =>
66+
let(Symbol.spliceOwner, rhs) { right =>
67+
val app = left.select(sel.symbol).appliedTo(right)
68+
let(Symbol.spliceOwner, app) { result =>
69+
val l = left.asExpr
70+
val r = right.asExpr
71+
val b = result.asExprOf[Boolean]
72+
val code = '{ Bool.binaryMacroBool($l, ${ Expr(op) }, $r, $b) }
73+
code.asTerm
74+
}
75+
}
76+
}.asExprOf[Bool]
77+
} else defaultCase
78+
79+
op match {
80+
case "==" => binaryDefault
81+
case _ => binaryDefault
82+
}
83+
84+
case Literal(_) =>
85+
'{ Bool.simpleMacroBool($condition) }
86+
87+
case _ =>
88+
defaultCase
89+
}
90+
}
91+
}

tests/pos-macros/i18911/Test_2.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@main def Test = {
2+
case class Document()
3+
val expected: Document = ???
4+
Assertions.assert( expected == Document()) // error
5+
}

0 commit comments

Comments
 (0)