Skip to content

Commit 62b37dd

Browse files
committed
refactor: prepare null check redundancy analysis
this commit doesn't change any behavior
1 parent 415becd commit 62b37dd

File tree

1 file changed

+38
-13
lines changed

1 file changed

+38
-13
lines changed

src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -409,14 +409,14 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
409409

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

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

435435

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

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

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

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

743753
// checks binder ne null before chaining to the next extractor
744-
ProductExtractorTreeMaker(binder, lengthGuard(binder))(subPatBinders, subPatRefs(binder), mutableBinders)
754+
ProductExtractorTreeMaker(binder, lengthGuard(binder))(subPatBinders, subPatRefs(binder), mutableBinders, binderKnownNonNull)
745755
}
746756

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

766-
def treeMaker(patBinderOrCasted: Symbol, pos: Position): TreeMaker = {
776+
/** Create the TreeMaker that embodies this extractor call
777+
*
778+
* `binder` has been casted to `paramType` if necessary
779+
* `binderKnownNonNull` is not used in this subclass
780+
*/
781+
def treeMaker(patBinderOrCasted: Symbol, binderKnownNonNull: Boolean, pos: Position): TreeMaker = {
767782
// the extractor call (applied to the binder bound by the flatMap corresponding to the previous (i.e., enclosing/outer) pattern)
768783
val extractorApply = atPos(pos)(spliceApply(patBinderOrCasted))
769784
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
@@ -1081,7 +1096,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
10811096
case class ProductExtractorTreeMaker(prevBinder: Symbol, extraCond: Option[Tree])(
10821097
val subPatBinders: List[Symbol],
10831098
val subPatRefs: List[Tree],
1084-
val mutableBinders: List[Symbol]) extends FunTreeMaker with PreserveSubPatBinders {
1099+
val mutableBinders: List[Symbol],
1100+
binderKnownNonNull: Boolean) extends FunTreeMaker with PreserveSubPatBinders {
10851101

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

10931109
def chainBefore(next: Tree)(casegen: Casegen): Tree = {
10941110
val nullCheck = REF(prevBinder) OBJ_NE NULL
1095-
val cond = extraCond map (nullCheck AND _) getOrElse nullCheck
1096-
casegen.ifThenElseZero(cond, bindSubPats(substitution(next)))
1111+
val cond =
1112+
if (binderKnownNonNull) extraCond
1113+
else (extraCond map (nullCheck AND _)
1114+
orElse Some(nullCheck))
1115+
1116+
cond match {
1117+
case Some(cond) =>
1118+
casegen.ifThenElseZero(cond, bindSubPats(substitution(next)))
1119+
case _ =>
1120+
bindSubPats(substitution(next))
1121+
}
10971122
}
10981123

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

0 commit comments

Comments
 (0)