diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 30eb2b16ba5e..2c0be4f27f2b 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -449,7 +449,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => def isIdempotentRef(tree: Tree)(implicit ctx: Context): Boolean = refPurity(tree) >= Idempotent - /** If `tree` is a constant expression, its value as a Literal, + /** (1) If `tree` is a constant expression, its value as a Literal, * or `tree` itself otherwise. * * 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] => * Ident * Select * TypeApply + * + * (2) A primitive 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 that does not have a symbol. */ def constToLiteral(tree: Tree)(implicit ctx: Context): Tree = { val tree1 = ConstFold(tree) tree1.tpe.widenTermRefExpr match { - case ConstantType(value) if isIdempotentExpr(tree1) => Literal(value) + case ConstantType(value) => + if (isIdempotentExpr(tree1)) Literal(value) + else tree1 match { + case Select(qual, _) if tree1.tpe.isInstanceOf[ConstantType] => + // it's a primitive unary operator; Simplify `pre.op` to `{ pre; v }` where `v` is the value of `pre.op` + Block(qual :: Nil, Literal(value)) + case _ => + tree1 + } case _ => tree1 } } diff --git a/tests/run/i5386.check b/tests/run/i5386.check new file mode 100644 index 000000000000..343e36be2164 --- /dev/null +++ b/tests/run/i5386.check @@ -0,0 +1,8 @@ +! +! +! +! +1 +2 +! +1 diff --git a/tests/run/i5386.scala b/tests/run/i5386.scala new file mode 100644 index 000000000000..eff28a2601f9 --- /dev/null +++ b/tests/run/i5386.scala @@ -0,0 +1,34 @@ +object Test extends App { + + ~{ + println("!") + 1 + } + + +{ + println("!") + 1 + } + + -{ + println("!") + 1 + } + + !{ + println("!") + true + } + + { println("1"); 1 } + { println("2"); 2} + + !(try true finally{()}) + + + class C { + def foo: 1 = { println("1"); 1 } + } + + { println("!"); new C }.foo + +} \ No newline at end of file