Skip to content

Commit b89d900

Browse files
committed
Fix #5386: Normalize unary operator expressions
A unary operator expression `pre.op` where `op` is one of `+`, `-`, `~`, `!` that has a constant type `ConstantType(v)` but that is not a constant expression (i.e. `pre` has side-effects) is translated to { pre; v } This avoids the situation where we have a Select node which does not have a symbol.
1 parent 3a3d5a3 commit b89d900

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

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

+18-2
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
449449
def isIdempotentRef(tree: Tree)(implicit ctx: Context): Boolean =
450450
refPurity(tree) >= Idempotent
451451

452-
/** If `tree` is a constant expression, its value as a Literal,
452+
/** (1) If `tree` is a constant expression, its value as a Literal,
453453
* or `tree` itself otherwise.
454454
*
455455
* Note: Demanding idempotency instead of purity in literalize is strictly speaking too loose.
@@ -485,11 +485,27 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
485485
* Ident
486486
* Select
487487
* TypeApply
488+
*
489+
* (2) A unary operator expression `pre.op` where `op` is one of `+`, `-`, `~`, `!`
490+
* that has a constant type `ConstantType(v)` but that is not a constant expression
491+
* (i.e. `pre` has side-effects) is translated to
492+
*
493+
* { pre; v }
494+
*
495+
* This avoids the situation where we have a Select node that does not have a symbol.
488496
*/
489497
def constToLiteral(tree: Tree)(implicit ctx: Context): Tree = {
490498
val tree1 = ConstFold(tree)
491499
tree1.tpe.widenTermRefExpr match {
492-
case ConstantType(value) if isIdempotentExpr(tree1) => Literal(value)
500+
case ConstantType(value) =>
501+
if (isIdempotentExpr(tree1)) Literal(value)
502+
else tree1 match {
503+
case Select(qual, _) if tree1.tpe.isInstanceOf[ConstantType] =>
504+
// it's a unary operator; Simplify `pre.op` to `{ pre; v }` where `v` is the value of `pre.op`
505+
Block(qual :: Nil, Literal(value))
506+
case _ =>
507+
tree1
508+
}
493509
case _ => tree1
494510
}
495511
}

tests/pos/i5386.scala

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
object Test {
2+
~{
3+
println("!")
4+
1
5+
}
6+
7+
+{
8+
println("!")
9+
1
10+
}
11+
12+
-{
13+
println("!")
14+
1
15+
}
16+
17+
!{
18+
println("!")
19+
true
20+
}
21+
22+
{ println("1"); 1 } + { println("2"); 2}
23+
24+
!(try true finally{()})
25+
}

0 commit comments

Comments
 (0)