From 8fd2917ce6f283df6ca6ceb578cee7aed8e36968 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 26 Nov 2014 14:18:31 +1000 Subject: SI-9003 Eagerly capture more potentially mutable binders This is a re-run of SI-5158 in two different contexts. As reported, the result of `unapply[Seq]` under name based pattern matching might not guarantee stability of results of calls to `_1`, `apply(i)`, etc, so we call these eagerly, and call them once only. I also found a case in regular pattern matching that we hadn't accounted for: extracting elements of sequences (either from a case class or from an `unapplySeq`) may also be unstable. This commit changes `ExtractorTreeMaker` to force storage of such binders, even under `-optimize`. This parallels the change to `ProductExtractorTreeMaker` in 8ebe8e3e8. I have added a special case for traditional `unapply` methods returning `Option`. This avoids a change for: ``` % cat test/files/run/t9003b.scala object Single { def unapply(a: Any) = Some("") } object Test { def main(args: Array[String]): Unit = { "" match { case Single(x) => (x, x) } } } % qscalac -optimize -Xprint:patmat test/files/run/t9003b.scala 2>&1 | grep --context=5 get case val x1: Any = ""; case5(){ val o7: Some[String] = Single.unapply(x1); if (o7.isEmpty.unary_!) matchEnd4({ scala.Tuple2.apply[String, String](o7.get, o7.get); () }) else case6() }; % scalac-hash v2.11.4 -optimize -Xprint:patmat test/files/run/t9003b.scala 2>&1 | grep --context=5 get case val x1: Any = ""; case5(){ val o7: Some[String] = Single.unapply(x1); if (o7.isEmpty.unary_!) matchEnd4({ scala.Tuple2.apply[String, String](o7.get, o7.get); () }) else case6() }; ``` --- test/files/run/t9003.flags | 1 + test/files/run/t9003.scala | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 test/files/run/t9003.flags create mode 100644 test/files/run/t9003.scala (limited to 'test/files') diff --git a/test/files/run/t9003.flags b/test/files/run/t9003.flags new file mode 100644 index 0000000000..49d036a887 --- /dev/null +++ b/test/files/run/t9003.flags @@ -0,0 +1 @@ +-optimize diff --git a/test/files/run/t9003.scala b/test/files/run/t9003.scala new file mode 100644 index 0000000000..4f24712201 --- /dev/null +++ b/test/files/run/t9003.scala @@ -0,0 +1,71 @@ +object Single { + var i = 0 + def isEmpty = false + def get = i + def unapply(a: Single.type) = this +} + +object Product { + var i = 0 + def _1: Int = i + def _2: String = ??? + def productArity = 2 + def unapply(a: Product.type) = this + def isEmpty = false + def get: this.type = this +} + +object Sequence { + var i = 0 + def apply(n: Int): Int = i + def length = 2 + def unapplySeq(a: Sequence.type) = this + def isEmpty = false + def get = this +} + +object Test { + def main(args: Array[String]): Unit = { + def assertZero(i: Int) = assert(i == 0) + + Single match { + case Single(i) => + Single.i = 1 + assertZero(i) // fails under -optimize + } + + Product match { + case Product(i, _) => + Product.i = 1 + assertZero(i) // fails under -optimize + } + + Sequence match { + case Sequence(i, _ @ _*) => + Sequence.i = 1 + assertZero(i) // okay + } + + Sequence.i = 0 + Sequence match { + case Sequence(_, i) => + Sequence.i = 1 + assertZero(i) // okay + } + + val buffer = collection.mutable.Buffer(0, 0) + buffer match { + case Seq(_, i) => + buffer(1) = 1 + assertZero(i) // failed + } + + case class CaseSequence(as: Int*) + val buffer1 = collection.mutable.Buffer(0, 0) + CaseSequence(buffer1: _*) match { + case CaseSequence(_, i) => + buffer1(1) = 1 + assertZero(i) // failed + } + } +} -- cgit v1.2.3