From c64e676404ad5ac1f314fbf2144c3c162d51c5a9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Jan 2020 14:25:47 +0100 Subject: [PATCH 1/3] Fix #8058: Fix `isStableMember` test isStableMember classified NoSymbol as stable. This meant that an Application without a symbol was classified as pure in TreeInfo. This in turn meant that the application could be dropped and replaced with `Unit` at the end of a block. The (non-)pure application in the test was an array update. --- .../src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- tests/run/i8058.scala | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 tests/run/i8058.scala diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 8729abe877a8..73380bd7bbfd 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -727,7 +727,7 @@ object SymDenotations { */ final def isStableMember(implicit ctx: Context): Boolean = { def isUnstableValue = isOneOf(UnstableValueFlags) || info.isInstanceOf[ExprType] - isType || is(StableRealizable) || !isUnstableValue + isType || is(StableRealizable) || exists && !isUnstableValue } /** Is this a denotation of a class that does not have - either direct or inherited - diff --git a/tests/run/i8058.scala b/tests/run/i8058.scala new file mode 100644 index 000000000000..b9ad34ba7282 --- /dev/null +++ b/tests/run/i8058.scala @@ -0,0 +1,10 @@ +extension on (x: Array[Char]): + inline def swap(i: Int, j: Int) : Unit = + val v = x(i) + x(i) = x(j) + x(j) = v + +@main def Test = + val a = Array('A','B') + a.swap(0, 1) + assert(a.toList == List('B', 'A')) \ No newline at end of file From 15452c7ad3a68d88da56960f45e44e962e17cefa Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Jan 2020 16:42:37 +0100 Subject: [PATCH 2/3] References with constant type are pure Before the fix to #8058, a reference `x` with constant type `0` was deemed to have a stable member symbol since its symbol did not exist. That's what gave the reference the `PurePath` status. Now that `isStableMember` is fixed, this needs to be asserted explicitly. --- compiler/src/dotty/tools/dotc/ast/TreeInfo.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index f6aba763da4e..d4a1126c5df7 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -442,7 +442,9 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => /** The purity level of this reference. * @return - * PurePath if reference is (nonlazy and stable) or to a parameterized function + * PurePath if reference is (nonlazy and stable) + * or to a parameterized function + * or its type is a constant type * IdempotentPath if reference is lazy and stable * Impure otherwise * @DarkDimius: need to make sure that lazy accessor methods have Lazy and Stable @@ -452,6 +454,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => val sym = tree.symbol if (!tree.hasType) Impure else if (!tree.tpe.widen.isParameterless || sym.isEffectivelyErased) PurePath + else if tree.tpe.isInstanceOf[ConstantType] then PurePath else if (!sym.isStableMember) Impure else if (sym.is(Module)) if (sym.moduleClass.isNoInitsClass) PurePath else IdempotentPath From bb009bf3bf486ab4451653628a9fdb18c4f58b1a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Jan 2020 17:43:38 +0100 Subject: [PATCH 3/3] Another compensation for c64e6764 TermRefs that do not have a symbol should not be widened under widenIfUnstable. --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index e51ad56e8a88..4d789c05ba85 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1082,7 +1082,7 @@ object Types { /** Widen type if it is unstable (i.e. an ExprType, or TermRef to unstable symbol */ final def widenIfUnstable(implicit ctx: Context): Type = stripTypeVar match { case tp: ExprType => tp.resultType.widenIfUnstable - case tp: TermRef if !tp.symbol.isStableMember => tp.underlying.widenIfUnstable + case tp: TermRef if tp.symbol.exists && !tp.symbol.isStableMember => tp.underlying.widenIfUnstable case _ => this }