Skip to content

Commit

Permalink
refactor: prepare null check redundancy analysis
Browse files Browse the repository at this point in the history
this commit doesn't change any behavior
  • Loading branch information
adriaanm committed Jan 31, 2013
1 parent 415becd commit 62b37dd
Showing 1 changed file with 38 additions and 13 deletions.
51 changes: 38 additions & 13 deletions src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
Expand Up @@ -409,14 +409,14 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL


// example check: List[Int] <:< ::[Int] // example check: List[Int] <:< ::[Int]
// TODO: extractor.paramType may contain unbound type params (run/t2800, run/t3530) // TODO: extractor.paramType may contain unbound type params (run/t2800, run/t3530)
val (typeTestTreeMaker, patBinderOrCasted) = val (typeTestTreeMaker, patBinderOrCasted, binderKnownNonNull) =
if (needsTypeTest(patBinder.info.widen, extractor.paramType)) { if (needsTypeTest(patBinder.info.widen, extractor.paramType)) {
// chain a type-testing extractor before the actual extractor call // chain a type-testing extractor before the actual extractor call
// it tests the type, checks the outer pointer and casts to the expected type // it tests the type, checks the outer pointer and casts to the expected type
// TODO: the outer check is mandated by the spec for case classes, but we do it for user-defined unapplies as well [SPEC] // TODO: the outer check is mandated by the spec for case classes, but we do it for user-defined unapplies as well [SPEC]
// (the prefix of the argument passed to the unapply must equal the prefix of the type of the binder) // (the prefix of the argument passed to the unapply must equal the prefix of the type of the binder)
val treeMaker = TypeTestTreeMaker(patBinder, patBinder, extractor.paramType, extractor.paramType)(pos, extractorArgTypeTest = true) val treeMaker = TypeTestTreeMaker(patBinder, patBinder, extractor.paramType, extractor.paramType)(pos, extractorArgTypeTest = true)
(List(treeMaker), treeMaker.nextBinder) (List(treeMaker), treeMaker.nextBinder, false)
} else { } else {
// no type test needed, but the tree maker relies on `patBinderOrCasted` having type `extractor.paramType` (and not just some type compatible with it) // no type test needed, but the tree maker relies on `patBinderOrCasted` having type `extractor.paramType` (and not just some type compatible with it)
// SI-6624 shows this is necessary because apparently patBinder may have an unfortunate type (.decls don't have the case field accessors) // SI-6624 shows this is necessary because apparently patBinder may have an unfortunate type (.decls don't have the case field accessors)
Expand All @@ -426,10 +426,10 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
if (settings.developer.value && !(patBinder.info =:= extractor.paramType)) if (settings.developer.value && !(patBinder.info =:= extractor.paramType))
devWarning(s"resetting info of $patBinder: ${patBinder.info} to ${extractor.paramType}") devWarning(s"resetting info of $patBinder: ${patBinder.info} to ${extractor.paramType}")
*/ */
(Nil, patBinder setInfo extractor.paramType) (Nil, patBinder setInfo extractor.paramType, false)
} }


withSubPats(typeTestTreeMaker :+ extractor.treeMaker(patBinderOrCasted, pos), extractor.subBindersAndPatterns: _*) withSubPats(typeTestTreeMaker :+ extractor.treeMaker(patBinderOrCasted, binderKnownNonNull, pos), extractor.subBindersAndPatterns: _*)
} }




Expand Down Expand Up @@ -622,8 +622,13 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// to which type should the previous binder be casted? // to which type should the previous binder be casted?
def paramType : Type def paramType : Type


// binder has been casted to paramType if necessary /** Create the TreeMaker that embodies this extractor call
def treeMaker(binder: Symbol, pos: Position): TreeMaker *
* `binder` has been casted to `paramType` if necessary
* `binderKnownNonNull` indicates whether the cast implies `binder` cannot be null
* when `binderKnownNonNull` is `true`, `ProductExtractorTreeMaker` does not do a (redundant) null check on binder
*/
def treeMaker(binder: Symbol, binderKnownNonNull: Boolean, pos: Position): TreeMaker


// `subPatBinders` are the variables bound by this pattern in the following patterns // `subPatBinders` are the variables bound by this pattern in the following patterns
// subPatBinders are replaced by references to the relevant part of the extractor's result (tuple component, seq element, the result as-is) // subPatBinders are replaced by references to the relevant part of the extractor's result (tuple component, seq element, the result as-is)
Expand Down Expand Up @@ -731,8 +736,13 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
def isSeq: Boolean = rawSubPatTypes.nonEmpty && isRepeatedParamType(rawSubPatTypes.last) def isSeq: Boolean = rawSubPatTypes.nonEmpty && isRepeatedParamType(rawSubPatTypes.last)
protected def rawSubPatTypes = constructorTp.paramTypes protected def rawSubPatTypes = constructorTp.paramTypes


// binder has type paramType /** Create the TreeMaker that embodies this extractor call
def treeMaker(binder: Symbol, pos: Position): TreeMaker = { *
* `binder` has been casted to `paramType` if necessary
* `binderKnownNonNull` indicates whether the cast implies `binder` cannot be null
* when `binderKnownNonNull` is `true`, `ProductExtractorTreeMaker` does not do a (redundant) null check on binder
*/
def treeMaker(binder: Symbol, binderKnownNonNull: Boolean, pos: Position): TreeMaker = {
val paramAccessors = binder.constrParamAccessors val paramAccessors = binder.constrParamAccessors
// binders corresponding to mutable fields should be stored (SI-5158, SI-6070) // binders corresponding to mutable fields should be stored (SI-5158, SI-6070)
val mutableBinders = val mutableBinders =
Expand All @@ -741,7 +751,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
else Nil else Nil


// checks binder ne null before chaining to the next extractor // checks binder ne null before chaining to the next extractor
ProductExtractorTreeMaker(binder, lengthGuard(binder))(subPatBinders, subPatRefs(binder), mutableBinders) ProductExtractorTreeMaker(binder, lengthGuard(binder))(subPatBinders, subPatRefs(binder), mutableBinders, binderKnownNonNull)
} }


// reference the (i-1)th case accessor if it exists, otherwise the (i-1)th tuple component // reference the (i-1)th case accessor if it exists, otherwise the (i-1)th tuple component
Expand All @@ -763,7 +773,12 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
def resultType = tpe.finalResultType def resultType = tpe.finalResultType
def isSeq = extractorCall.symbol.name == nme.unapplySeq def isSeq = extractorCall.symbol.name == nme.unapplySeq


def treeMaker(patBinderOrCasted: Symbol, pos: Position): TreeMaker = { /** Create the TreeMaker that embodies this extractor call
*
* `binder` has been casted to `paramType` if necessary
* `binderKnownNonNull` is not used in this subclass
*/
def treeMaker(patBinderOrCasted: Symbol, binderKnownNonNull: Boolean, pos: Position): TreeMaker = {
// the extractor call (applied to the binder bound by the flatMap corresponding to the previous (i.e., enclosing/outer) pattern) // the extractor call (applied to the binder bound by the flatMap corresponding to the previous (i.e., enclosing/outer) pattern)
val extractorApply = atPos(pos)(spliceApply(patBinderOrCasted)) val extractorApply = atPos(pos)(spliceApply(patBinderOrCasted))
val binder = freshSym(pos, pureType(resultInMonad)) // can't simplify this when subPatBinders.isEmpty, since UnitClass.tpe is definitely wrong when isSeq, and resultInMonad should always be correct since it comes directly from the extractor's result type val binder = freshSym(pos, pureType(resultInMonad)) // can't simplify this when subPatBinders.isEmpty, since UnitClass.tpe is definitely wrong when isSeq, and resultInMonad should always be correct since it comes directly from the extractor's result type
Expand Down Expand Up @@ -1081,7 +1096,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
case class ProductExtractorTreeMaker(prevBinder: Symbol, extraCond: Option[Tree])( case class ProductExtractorTreeMaker(prevBinder: Symbol, extraCond: Option[Tree])(
val subPatBinders: List[Symbol], val subPatBinders: List[Symbol],
val subPatRefs: List[Tree], val subPatRefs: List[Tree],
val mutableBinders: List[Symbol]) extends FunTreeMaker with PreserveSubPatBinders { val mutableBinders: List[Symbol],
binderKnownNonNull: Boolean) extends FunTreeMaker with PreserveSubPatBinders {


import CODE._ import CODE._
val nextBinder = prevBinder // just passing through val nextBinder = prevBinder // just passing through
Expand All @@ -1092,8 +1108,17 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL


def chainBefore(next: Tree)(casegen: Casegen): Tree = { def chainBefore(next: Tree)(casegen: Casegen): Tree = {
val nullCheck = REF(prevBinder) OBJ_NE NULL val nullCheck = REF(prevBinder) OBJ_NE NULL
val cond = extraCond map (nullCheck AND _) getOrElse nullCheck val cond =
casegen.ifThenElseZero(cond, bindSubPats(substitution(next))) if (binderKnownNonNull) extraCond
else (extraCond map (nullCheck AND _)
orElse Some(nullCheck))

cond match {
case Some(cond) =>
casegen.ifThenElseZero(cond, bindSubPats(substitution(next)))
case _ =>
bindSubPats(substitution(next))
}
} }


override def toString = "P"+(prevBinder.name, extraCond getOrElse "", localSubstitution) override def toString = "P"+(prevBinder.name, extraCond getOrElse "", localSubstitution)
Expand Down

0 comments on commit 62b37dd

Please sign in to comment.