@@ -5107,6 +5107,7 @@ object Types extends TypeUtils {
51075107 case SubTypeTest (origMatchCase : Type , pattern : Type , body : Type )
51085108 case SpeccedPatMat (origMatchCase : HKTypeLambda , captureCount : Int , pattern : MatchTypeCasePattern , body : Type )
51095109 case LegacyPatMat (origMatchCase : HKTypeLambda )
5110+ case MissingCaptures (origMatchCase : HKTypeLambda , missing : collection.BitSet )
51105111
51115112 def origMatchCase : Type
51125113 end MatchTypeCaseSpec
@@ -5116,16 +5117,44 @@ object Types extends TypeUtils {
51165117 cas match
51175118 case cas : HKTypeLambda =>
51185119 val defn .MatchCase (pat, body) = cas.resultType: @ unchecked
5119- val specPattern = tryConvertToSpecPattern (cas, pat)
5120- if specPattern != null then
5121- SpeccedPatMat (cas, cas.paramNames.size, specPattern, body )
5120+ val missing = checkCapturesPresent (cas, pat)
5121+ if ! missing.isEmpty then
5122+ MissingCaptures (cas, missing )
51225123 else
5123- LegacyPatMat (cas)
5124+ val specPattern = tryConvertToSpecPattern(cas, pat)
5125+ if specPattern != null then
5126+ SpeccedPatMat (cas, cas.paramNames.size, specPattern, body)
5127+ else
5128+ LegacyPatMat (cas)
51245129 case _ =>
51255130 val defn .MatchCase (pat, body) = cas : @ unchecked
51265131 SubTypeTest (cas, pat, body)
51275132 end analyze
51285133
5134+ /** Checks that all the captures of the case are present in the case.
5135+ *
5136+ * Sometimes, because of earlier substitutions of an abstract type constructor,
5137+ * we can end up with patterns that do not mention all their captures anymore.
5138+ * This can happen even when the body still refers to these missing captures.
5139+ * In that case, we must always consider the case to be unmatchable, i.e., to
5140+ * become `Stuck`.
5141+ *
5142+ * See pos/i12127.scala for an example.
5143+ */
5144+ def checkCapturesPresent (cas : HKTypeLambda , pat : Type )(using Context ): collection.BitSet =
5145+ val captureCount = cas.paramNames.size
5146+ val missing = new mutable.BitSet (captureCount)
5147+ missing ++= (0 until captureCount)
5148+ new CheckCapturesPresent (cas).apply(missing, pat)
5149+
5150+ private class CheckCapturesPresent (cas : HKTypeLambda )(using Context ) extends TypeAccumulator [mutable.BitSet ]:
5151+ def apply (missing : mutable.BitSet , tp : Type ): mutable.BitSet = tp match
5152+ case TypeParamRef (binder, num) if binder eq cas =>
5153+ missing -= num
5154+ case _ =>
5155+ foldOver(missing, tp)
5156+ end CheckCapturesPresent
5157+
51295158 private def tryConvertToSpecPattern (caseLambda : HKTypeLambda , pat : Type )(using Context ): MatchTypeCasePattern | Null =
51305159 var typeParamRefsAccountedFor : Int = 0
51315160
0 commit comments