From 8479be56e6275b2fe0670d213fa013d09bff688f Mon Sep 17 00:00:00 2001 From: Aggelos Biboudis Date: Sun, 4 Nov 2018 15:19:36 -0500 Subject: [PATCH 1/6] Generate a synthetic val def and then apply the unary operator --- .../dotc/transform/InterceptedMethods.scala | 12 ++++++++++ tests/pos/i5386.scala | 23 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 tests/pos/i5386.scala diff --git a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala index 2eacd1b010e1..bee3531d0f77 100644 --- a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala @@ -9,6 +9,7 @@ import dotty.tools.dotc.core.Names.TermName import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.core.Types._ +import dotty.tools.dotc.core.NameKinds._ import dotty.tools.dotc.transform.MegaPhase.MiniPhase object InterceptedMethods { @@ -45,6 +46,17 @@ class InterceptedMethods extends MiniPhase { ctx.log(s"$phaseName rewrote $tree to $rewritten") rewritten } + else if (tree.name.startsWith(nme.UNARY_PREFIX.toString)) { + tree.qualifier match { + case refTree: RefTree => tree + case _ => { + val tempDef = SyntheticValDef(UniqueName.fresh().toTermName, tree.qualifier) + val rewritten = Block(tempDef :: Nil, ref(tempDef.symbol).select(tree.name)) + ctx.log(s"$phaseName rewrote $tree to $rewritten") + rewritten + } + } + } else tree } diff --git a/tests/pos/i5386.scala b/tests/pos/i5386.scala new file mode 100644 index 000000000000..56c509d1309d --- /dev/null +++ b/tests/pos/i5386.scala @@ -0,0 +1,23 @@ +object Test { + ~{ + println("!") + 1 + } + + +{ + println("!") + 1 + } + + -{ + println("!") + 1 + } + + !{ + println("!") + true + } + + !(try true finally{()}) +} \ No newline at end of file From 28a42a561f598a1e98df336d9ec9e559fc938bbc Mon Sep 17 00:00:00 2001 From: Aggelos Biboudis Date: Sun, 4 Nov 2018 16:14:35 -0500 Subject: [PATCH 2/6] Transform only if symbol is absent --- .../src/dotty/tools/dotc/transform/InterceptedMethods.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala index bee3531d0f77..b954de3dc714 100644 --- a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala @@ -46,13 +46,16 @@ class InterceptedMethods extends MiniPhase { ctx.log(s"$phaseName rewrote $tree to $rewritten") rewritten } - else if (tree.name.startsWith(nme.UNARY_PREFIX.toString)) { + else if (tree.name.startsWith(nme.UNARY_PREFIX.toString) && tree.qualifier.symbol.isAbsent) { tree.qualifier match { case refTree: RefTree => tree case _ => { val tempDef = SyntheticValDef(UniqueName.fresh().toTermName, tree.qualifier) val rewritten = Block(tempDef :: Nil, ref(tempDef.symbol).select(tree.name)) ctx.log(s"$phaseName rewrote $tree to $rewritten") + println("### " + tree.tpe + " " + tree.tpe.show) + println("### " + tree.qualifier.symbol) + rewritten } } From 6868d6cc6c042104591fb1d11c871f73149a195b Mon Sep 17 00:00:00 2001 From: Aggelos Biboudis Date: Mon, 5 Nov 2018 10:59:19 -0500 Subject: [PATCH 3/6] Remove printlns --- .../src/dotty/tools/dotc/transform/InterceptedMethods.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala index b954de3dc714..c8dfeb42ea04 100644 --- a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala @@ -53,8 +53,6 @@ class InterceptedMethods extends MiniPhase { val tempDef = SyntheticValDef(UniqueName.fresh().toTermName, tree.qualifier) val rewritten = Block(tempDef :: Nil, ref(tempDef.symbol).select(tree.name)) ctx.log(s"$phaseName rewrote $tree to $rewritten") - println("### " + tree.tpe + " " + tree.tpe.show) - println("### " + tree.qualifier.symbol) rewritten } From 3e9ce510c9c48b88f35439f215eadf96af647366 Mon Sep 17 00:00:00 2001 From: Aggelos Biboudis Date: Mon, 5 Nov 2018 14:14:59 -0500 Subject: [PATCH 4/6] Address comments --- .../src/dotty/tools/dotc/transform/InterceptedMethods.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala index c8dfeb42ea04..05455d267ad2 100644 --- a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala @@ -46,16 +46,14 @@ class InterceptedMethods extends MiniPhase { ctx.log(s"$phaseName rewrote $tree to $rewritten") rewritten } - else if (tree.name.startsWith(nme.UNARY_PREFIX.toString) && tree.qualifier.symbol.isAbsent) { + else if (!tree.qualifier.symbol.exists && tree.name.startsWith(nme.UNARY_PREFIX.toString)) { tree.qualifier match { - case refTree: RefTree => tree - case _ => { + case _ => val tempDef = SyntheticValDef(UniqueName.fresh().toTermName, tree.qualifier) val rewritten = Block(tempDef :: Nil, ref(tempDef.symbol).select(tree.name)) ctx.log(s"$phaseName rewrote $tree to $rewritten") rewritten - } } } else tree From c83a362b6c08395cd2fc6171a5e053ab92ac2b2f Mon Sep 17 00:00:00 2001 From: Aggelos Biboudis Date: Mon, 5 Nov 2018 14:21:16 -0500 Subject: [PATCH 5/6] Add comments --- .../src/dotty/tools/dotc/transform/InterceptedMethods.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala index 05455d267ad2..96f0ad5bf12c 100644 --- a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala @@ -23,6 +23,7 @@ object InterceptedMethods { * - `x.##` for ## in Any becomes calls to ScalaRunTime.hash, * using the most precise overload available * - `x.getClass` for getClass in primitives becomes `x.getClass` with getClass in class Object. + * - `!{...;true}` becomes val tmp = {...;true};!tmp (similar to other primitives/unary ops) */ class InterceptedMethods extends MiniPhase { import tpd._ @@ -46,6 +47,9 @@ class InterceptedMethods extends MiniPhase { ctx.log(s"$phaseName rewrote $tree to $rewritten") rewritten } + // if the qualifier is constant folded then its type doesn't have a symbol + // in case a unary operator is applied to a block (potentially containing impure expressions) + // we create a synthetic variable and then apply the operator else if (!tree.qualifier.symbol.exists && tree.name.startsWith(nme.UNARY_PREFIX.toString)) { tree.qualifier match { case _ => From 3dba70ff26a1446342123eee20714230b9fc080a Mon Sep 17 00:00:00 2001 From: Aggelos Biboudis Date: Mon, 5 Nov 2018 14:24:13 -0500 Subject: [PATCH 6/6] Remove reduntant match --- .../tools/dotc/transform/InterceptedMethods.scala | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala index 96f0ad5bf12c..2cb17d216f68 100644 --- a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala @@ -51,14 +51,11 @@ class InterceptedMethods extends MiniPhase { // in case a unary operator is applied to a block (potentially containing impure expressions) // we create a synthetic variable and then apply the operator else if (!tree.qualifier.symbol.exists && tree.name.startsWith(nme.UNARY_PREFIX.toString)) { - tree.qualifier match { - case _ => - val tempDef = SyntheticValDef(UniqueName.fresh().toTermName, tree.qualifier) - val rewritten = Block(tempDef :: Nil, ref(tempDef.symbol).select(tree.name)) - ctx.log(s"$phaseName rewrote $tree to $rewritten") + val tempDef = SyntheticValDef(UniqueName.fresh().toTermName, tree.qualifier) + val rewritten = Block(tempDef :: Nil, ref(tempDef.symbol).select(tree.name)) + ctx.log(s"$phaseName rewrote $tree to $rewritten") - rewritten - } + rewritten } else tree }