@@ -5107,6 +5107,7 @@ object Types extends TypeUtils {
5107
5107
case SubTypeTest (origMatchCase : Type , pattern : Type , body : Type )
5108
5108
case SpeccedPatMat (origMatchCase : HKTypeLambda , captureCount : Int , pattern : MatchTypeCasePattern , body : Type )
5109
5109
case LegacyPatMat (origMatchCase : HKTypeLambda )
5110
+ case MissingCaptures (origMatchCase : HKTypeLambda , missing : collection.BitSet )
5110
5111
5111
5112
def origMatchCase : Type
5112
5113
end MatchTypeCaseSpec
@@ -5116,16 +5117,44 @@ object Types extends TypeUtils {
5116
5117
cas match
5117
5118
case cas : HKTypeLambda =>
5118
5119
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 )
5122
5123
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)
5124
5129
case _ =>
5125
5130
val defn .MatchCase (pat, body) = cas : @ unchecked
5126
5131
SubTypeTest (cas, pat, body)
5127
5132
end analyze
5128
5133
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
+
5129
5158
private def tryConvertToSpecPattern (caseLambda : HKTypeLambda , pat : Type )(using Context ): MatchTypeCasePattern | Null =
5130
5159
var typeParamRefsAccountedFor : Int = 0
5131
5160
0 commit comments