diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index dc3bfd62a5ce..a80c5dbf4d51 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1016,11 +1016,20 @@ class Global(var currentSettings: Settings, reporter0: Reporter) && rootMirror.isMirrorInitialized ) override def isPastTyper = isPast(currentRun.typerPhase) + def isBeforeErasure = isBefore(currentRun.erasurePhase) def isPast(phase: Phase) = ( (curRun ne null) && isGlobalInitialized // defense against init order issues && (globalPhase.id > phase.id) ) + def isBefore(phase: Phase) = ( + (curRun ne null) + && isGlobalInitialized // defense against init order issues + && (phase match { + case NoPhase => true // if phase is NoPhase then that phase ain't comin', so we're "before it" + case _ => globalPhase.id < phase.id + }) + ) // TODO - trim these to the absolute minimum. @inline final def exitingErasure[T](op: => T): T = exitingPhase(currentRun.erasurePhase)(op) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index b5538dfb2441..7644604902dd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1240,9 +1240,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper inferExprAlternative(tree, pt) adaptAfterOverloadResolution(tree, mode, pt, original) case NullaryMethodType(restpe) => // (2) - val resTpDeconst = - if (isPastTyper || (tree.symbol.isAccessor && tree.symbol.hasFlag(STABLE) && treeInfo.isExprSafeToInline(tree))) restpe - else restpe.deconst + val resTpDeconst = // only keep the result type as a constant (foldable) type when before erasure & it's safe to inline/fold + if (isBeforeErasure && tree.symbol.isAccessor && tree.symbol.hasFlag(STABLE) && treeInfo.isExprSafeToInline(tree)) restpe + else restpe.deconst // otherwise deconst-ify, so we don't constant fold it adapt(tree setType resTpDeconst, mode, pt, original) case TypeRef(_, ByNameParamClass, arg :: Nil) if mode.inExprMode => // (2) adapt(tree setType arg, mode, pt, original) diff --git a/test/files/run/patmat-no-inline-isEmpty.check b/test/files/run/patmat-no-inline-isEmpty.check new file mode 100644 index 000000000000..60ed79c25c04 --- /dev/null +++ b/test/files/run/patmat-no-inline-isEmpty.check @@ -0,0 +1,36 @@ +[[syntax trees at end of patmat]] // newSource1.scala +package { + object A extends scala.AnyRef { + def (): A.type = { + A.super.(); + () + }; + def unapplySeq(a: Int): Wrap = new Wrap(a) + }; + class T extends scala.AnyRef { + def (): T = { + T.super.(); + () + }; + def t: Any = { + case val x1: Int(2) = 2; + case5(){ + val o7: Wrap = A.unapplySeq(x1); + if (o7.isEmpty.unary_!) + { + val xs: Seq[Int] = o7.get.toSeq; + matchEnd4(xs) + } + else + case6() + }; + case6(){ + matchEnd4("other") + }; + matchEnd4(x: Any){ + x + } + } + } +} + diff --git a/test/files/run/patmat-no-inline-isEmpty.scala b/test/files/run/patmat-no-inline-isEmpty.scala new file mode 100644 index 000000000000..3af510134c70 --- /dev/null +++ b/test/files/run/patmat-no-inline-isEmpty.scala @@ -0,0 +1,31 @@ +import scala.tools.partest._ + +object Test extends DirectTest { + def depCode = + """class Wrap(private val a: Int) extends AnyVal { + | def isEmpty: false = { println("confirm seq isEmpty method doesn't get elided"); false } + | def get = this + | def lengthCompare(len: Int) = Integer.compare(1, len) + | def apply(i: Int) = if (i == 0) a else Nil(i) + | def drop(n: Int): scala.Seq[Int] = if (n == 0) toSeq else Nil + | def toSeq: scala.Seq[Int] = List(a) + |} + """.stripMargin + + override def code = + """object A { + | def unapplySeq(a: Int) = new Wrap(a) + |} + |class T { + | def t: Any = 2 match { + | case A(xs @ _*) => xs + | case _ => "other" + | } + |} + """.stripMargin + + def show(): Unit = Console.withErr(System.out) { + compileString(newCompiler("-usejavacp"))(depCode) + compileString(newCompiler("-usejavacp", "-cp", testOutput.path, "-Vprint:patmat"))(code) + } +} diff --git a/test/files/run/patmat-no-inline-unapply.check b/test/files/run/patmat-no-inline-unapply.check new file mode 100644 index 000000000000..6b0b6eb2425b --- /dev/null +++ b/test/files/run/patmat-no-inline-unapply.check @@ -0,0 +1,25 @@ +[[syntax trees at end of patmat]] // newSource1.scala +package { + class T extends scala.AnyRef { + def (): T = { + T.super.(); + () + }; + def t: Any = { + case val x1: Int(2) = 2; + case5(){ + if (A.unapply(x1)) + matchEnd4("ok") + else + case6() + }; + case6(){ + matchEnd4("other") + }; + matchEnd4(x: Any){ + x + } + } + } +} + diff --git a/test/files/run/patmat-no-inline-unapply.scala b/test/files/run/patmat-no-inline-unapply.scala new file mode 100644 index 000000000000..bd6a5541cdd6 --- /dev/null +++ b/test/files/run/patmat-no-inline-unapply.scala @@ -0,0 +1,23 @@ +import scala.tools.partest._ + +object Test extends DirectTest { + def depCode = + """object A { + | def unapply(a: Int): true = true + |} + """.stripMargin + + override def code = + """class T { + | def t: Any = 2 match { + | case A() => "ok" + | case _ => "other" + | } + |} + """.stripMargin + + def show(): Unit = Console.withErr(System.out) { + compileString(newCompiler("-usejavacp"))(depCode) + compileString(newCompiler("-usejavacp", "-cp", testOutput.path, "-Vprint:patmat"))(code) + } +} diff --git a/test/files/run/patmat-seq.check b/test/files/run/patmat-seq.check index 8de58f733fb1..ffd4b8c20ac7 100644 --- a/test/files/run/patmat-seq.check +++ b/test/files/run/patmat-seq.check @@ -66,7 +66,7 @@ package { case val x1: Int(2) = 2; case16(){ val o18: collection.SeqFactory.UnapplySeqWrapper[Int] = A.unapplySeq(x1); - if (false.unary_!) + if (o18.isEmpty.unary_!) { val xs: Seq[Int] = o18.get.toSeq; matchEnd15(xs) @@ -76,7 +76,7 @@ package { }; case17(){ val o20: collection.SeqFactory.UnapplySeqWrapper[Int] = A.unapplySeq(x1); - if (false.unary_!.&&(o20.get.!=(null).&&(o20.get.lengthCompare(2).==(0)))) + if (o20.isEmpty.unary_!.&&(o20.get.!=(null).&&(o20.get.lengthCompare(2).==(0)))) { val x: Int = o20.get.apply(0); val y: Int = o20.get.apply(1); @@ -87,7 +87,7 @@ package { }; case19(){ val o22: collection.SeqFactory.UnapplySeqWrapper[Int] = A.unapplySeq(x1); - if (false.unary_!.&&(o22.get.!=(null).&&(o22.get.lengthCompare(1).>=(0)))) + if (o22.isEmpty.unary_!.&&(o22.get.!=(null).&&(o22.get.lengthCompare(1).>=(0)))) { val x: Int = o22.get.apply(0); val xs: Seq[Int] = o22.get.drop(1); @@ -267,7 +267,7 @@ package { case val x1: Int(2) = 2; case16(){ val o18: scala.collection.SeqOps = A.unapplySeq(x1); - if (false.unary_!()) + if (scala.collection.SeqFactory.UnapplySeqWrapper.isEmpty$extension(o18).unary_!()) { val xs: Seq = scala.collection.SeqFactory.UnapplySeqWrapper.toSeq$extension(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o18)); matchEnd15(xs) @@ -277,7 +277,7 @@ package { }; case17(){ val o20: scala.collection.SeqOps = A.unapplySeq(x1); - if (false.unary_!().&&(new collection.SeqFactory.UnapplySeqWrapper(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o20)).!=(null).&&(scala.collection.SeqFactory.UnapplySeqWrapper.lengthCompare$extension(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o20), 2).==(0)))) + if (scala.collection.SeqFactory.UnapplySeqWrapper.isEmpty$extension(o20).unary_!().&&(new collection.SeqFactory.UnapplySeqWrapper(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o20)).!=(null).&&(scala.collection.SeqFactory.UnapplySeqWrapper.lengthCompare$extension(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o20), 2).==(0)))) { val x: Int = unbox(scala.collection.SeqFactory.UnapplySeqWrapper.apply$extension(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o20), 0)); val y: Int = unbox(scala.collection.SeqFactory.UnapplySeqWrapper.apply$extension(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o20), 1)); @@ -288,7 +288,7 @@ package { }; case19(){ val o22: scala.collection.SeqOps = A.unapplySeq(x1); - if (false.unary_!().&&(new collection.SeqFactory.UnapplySeqWrapper(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o22)).!=(null).&&(scala.collection.SeqFactory.UnapplySeqWrapper.lengthCompare$extension(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o22), 1).>=(0)))) + if (scala.collection.SeqFactory.UnapplySeqWrapper.isEmpty$extension(o22).unary_!().&&(new collection.SeqFactory.UnapplySeqWrapper(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o22)).!=(null).&&(scala.collection.SeqFactory.UnapplySeqWrapper.lengthCompare$extension(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o22), 1).>=(0)))) { val x: Int = unbox(scala.collection.SeqFactory.UnapplySeqWrapper.apply$extension(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o22), 0)); val xs: Seq = scala.collection.SeqFactory.UnapplySeqWrapper.drop$extension(scala.collection.SeqFactory.UnapplySeqWrapper.get$extension(o22), 1);