summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2012-08-08 09:57:31 -0700
committerAdriaan Moors <adriaan.moors@epfl.ch>2012-08-08 09:57:31 -0700
commit5fc4057c7706ec1efa13a5f892a6d40de61ab970 (patch)
tree64d33ad3dcf85693424ce1abff2931d19607abd6 /src
parentadbdb18d93374b7c68f77649cc7ec4c3b9e33f4b (diff)
parent8ebe8e3e885f23d2a4c21a87e4dfcc07a7b3583a (diff)
downloadscala-5fc4057c7706ec1efa13a5f892a6d40de61ab970.tar.gz
scala-5fc4057c7706ec1efa13a5f892a6d40de61ab970.tar.bz2
scala-5fc4057c7706ec1efa13a5f892a6d40de61ab970.zip
Merge pull request #1060 from adriaanm/ticket-5739b
SI-5739 (bis) vals for subpatterns when -g:patmatvars
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala41
1 files changed, 37 insertions, 4 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index bcc172e9f0..1b502025c2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -663,8 +663,15 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// binder has type paramType
def treeMaker(binder: Symbol, pos: Position): TreeMaker = {
+ val paramAccessors = binder.constrParamAccessors
+ // binders corresponding to mutable fields should be stored (SI-5158, SI-6070)
+ val mutableBinders =
+ if (paramAccessors exists (_.isMutable))
+ subPatBinders.zipWithIndex.collect{ case (binder, idx) if paramAccessors(idx).isMutable => binder }
+ else Nil
+
// checks binder ne null before chaining to the next extractor
- ProductExtractorTreeMaker(binder, lengthGuard(binder))(subPatBinders, subPatRefs(binder))
+ ProductExtractorTreeMaker(binder, lengthGuard(binder))(subPatBinders, subPatRefs(binder), mutableBinders)
}
// reference the (i-1)th case accessor if it exists, otherwise the (i-1)th tuple component
@@ -926,10 +933,27 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
atPos(pos)(casegen.flatMapCond(cond, res, nextBinder, substitution(next)))
}
- trait PreserveSubPatBinders extends NoNewBinders {
+ // unless we're optimizing, emit local variable bindings for all subpatterns of extractor/case class patterns
+ protected val debugInfoEmitVars = !settings.optimise.value
+
+ trait PreserveSubPatBinders extends TreeMaker {
val subPatBinders: List[Symbol]
val subPatRefs: List[Tree]
+ // unless `debugInfoEmitVars`, this set should contain the bare minimum for correctness
+ // mutable case class fields need to be stored regardless (SI-5158, SI-6070) -- see override in ProductExtractorTreeMaker
+ def storedBinders: Set[Symbol] = if (debugInfoEmitVars) subPatBinders.toSet else Set.empty
+
+ def emitVars = storedBinders.nonEmpty
+
+ private lazy val (stored, substed) = (subPatBinders, subPatRefs).zipped.partition{ case (sym, _) => storedBinders(sym) }
+
+ protected lazy val localSubstitution: Substitution = if (!emitVars) Substitution(subPatBinders, subPatRefs)
+ else {
+ val (subPatBindersSubstituted, subPatRefsSubstituted) = substed.unzip
+ Substitution(subPatBindersSubstituted.toList, subPatRefsSubstituted.toList)
+ }
+
/** The substitution that specifies the trees that compute the values of the subpattern binders.
*
* We pretend to replace the subpattern binders by subpattern refs
@@ -939,7 +963,11 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
Substitution(subPatBinders, subPatRefs) >> super.subPatternsAsSubstitution
import CODE._
- def bindSubPats(in: Tree): Tree = Block(map2(subPatBinders, subPatRefs)(VAL(_) === _), in)
+ def bindSubPats(in: Tree): Tree = if (!emitVars) in
+ else {
+ val (subPatBindersStored, subPatRefsStored) = stored.unzip
+ Block(map2(subPatBindersStored.toList, subPatRefsStored.toList)(VAL(_) === _), in)
+ }
}
/**
@@ -1000,11 +1028,16 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
*/
case class ProductExtractorTreeMaker(prevBinder: Symbol, extraCond: Option[Tree])(
val subPatBinders: List[Symbol],
- val subPatRefs: List[Tree]) extends FunTreeMaker with PreserveSubPatBinders {
+ val subPatRefs: List[Tree],
+ val mutableBinders: List[Symbol]) extends FunTreeMaker with PreserveSubPatBinders {
import CODE._
val nextBinder = prevBinder // just passing through
+ // mutable binders must be stored to avoid unsoundness or seeing mutation of fields after matching (SI-5158, SI-6070)
+ // (the implementation could be optimized by duplicating code from `super.storedBinders`, but this seems more elegant)
+ override def storedBinders: Set[Symbol] = super.storedBinders ++ mutableBinders.toSet
+
def chainBefore(next: Tree)(casegen: Casegen): Tree = {
val nullCheck = REF(prevBinder) OBJ_NE NULL
val cond = extraCond map (nullCheck AND _) getOrElse nullCheck