@@ -409,14 +409,14 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
409
409
410
410
// example check: List[Int] <:< ::[Int]
411
411
// TODO: extractor.paramType may contain unbound type params (run/t2800, run/t3530)
412
- val (typeTestTreeMaker, patBinderOrCasted) =
412
+ val (typeTestTreeMaker, patBinderOrCasted, binderKnownNonNull ) =
413
413
if (needsTypeTest(patBinder.info.widen, extractor.paramType)) {
414
414
// chain a type-testing extractor before the actual extractor call
415
415
// it tests the type, checks the outer pointer and casts to the expected type
416
416
// TODO: the outer check is mandated by the spec for case classes, but we do it for user-defined unapplies as well [SPEC]
417
417
// (the prefix of the argument passed to the unapply must equal the prefix of the type of the binder)
418
418
val treeMaker = TypeTestTreeMaker (patBinder, patBinder, extractor.paramType, extractor.paramType)(pos, extractorArgTypeTest = true )
419
- (List (treeMaker), treeMaker.nextBinder)
419
+ (List (treeMaker), treeMaker.nextBinder, false )
420
420
} else {
421
421
// no type test needed, but the tree maker relies on `patBinderOrCasted` having type `extractor.paramType` (and not just some type compatible with it)
422
422
// 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
426
426
if (settings.developer.value && !(patBinder.info =:= extractor.paramType))
427
427
devWarning(s"resetting info of $patBinder: ${patBinder.info} to ${extractor.paramType}")
428
428
*/
429
- (Nil , patBinder setInfo extractor.paramType)
429
+ (Nil , patBinder setInfo extractor.paramType, false )
430
430
}
431
431
432
- withSubPats(typeTestTreeMaker :+ extractor.treeMaker(patBinderOrCasted, pos), extractor.subBindersAndPatterns: _* )
432
+ withSubPats(typeTestTreeMaker :+ extractor.treeMaker(patBinderOrCasted, binderKnownNonNull, pos), extractor.subBindersAndPatterns: _* )
433
433
}
434
434
435
435
@@ -622,8 +622,13 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
622
622
// to which type should the previous binder be casted?
623
623
def paramType : Type
624
624
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
627
632
628
633
// `subPatBinders` are the variables bound by this pattern in the following patterns
629
634
// 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
731
736
def isSeq : Boolean = rawSubPatTypes.nonEmpty && isRepeatedParamType(rawSubPatTypes.last)
732
737
protected def rawSubPatTypes = constructorTp.paramTypes
733
738
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 = {
736
746
val paramAccessors = binder.constrParamAccessors
737
747
// binders corresponding to mutable fields should be stored (SI-5158, SI-6070)
738
748
val mutableBinders =
@@ -741,7 +751,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
741
751
else Nil
742
752
743
753
// 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 )
745
755
}
746
756
747
757
// 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
763
773
def resultType = tpe.finalResultType
764
774
def isSeq = extractorCall.symbol.name == nme.unapplySeq
765
775
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 = {
767
782
// the extractor call (applied to the binder bound by the flatMap corresponding to the previous (i.e., enclosing/outer) pattern)
768
783
val extractorApply = atPos(pos)(spliceApply(patBinderOrCasted))
769
784
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
1081
1096
case class ProductExtractorTreeMaker (prevBinder : Symbol , extraCond : Option [Tree ])(
1082
1097
val subPatBinders : List [Symbol ],
1083
1098
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 {
1085
1101
1086
1102
import CODE ._
1087
1103
val nextBinder = prevBinder // just passing through
@@ -1092,8 +1108,17 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
1092
1108
1093
1109
def chainBefore (next : Tree )(casegen : Casegen ): Tree = {
1094
1110
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
+ }
1097
1122
}
1098
1123
1099
1124
override def toString = " P" + (prevBinder.name, extraCond getOrElse " " , localSubstitution)
0 commit comments