@@ -2,6 +2,8 @@ package dotty.tools
2
2
package dotc
3
3
package core
4
4
5
+ import java .util as ju
6
+
5
7
import Symbols .*
6
8
import Flags .*
7
9
import Names .*
@@ -5108,6 +5110,7 @@ object Types {
5108
5110
case SubTypeTest (origMatchCase : Type , pattern : Type , body : Type )
5109
5111
case SpeccedPatMat (origMatchCase : HKTypeLambda , captureCount : Int , pattern : MatchTypeCasePattern , body : Type )
5110
5112
case LegacyPatMat (origMatchCase : HKTypeLambda )
5113
+ case MissingCaptures (origMatchCase : HKTypeLambda , missing : ju.BitSet )
5111
5114
5112
5115
def origMatchCase : Type
5113
5116
end MatchTypeCaseSpec
@@ -5117,16 +5120,45 @@ object Types {
5117
5120
cas match
5118
5121
case cas : HKTypeLambda =>
5119
5122
val defn .MatchCase (pat, body) = cas.resultType: @ unchecked
5120
- val specPattern = tryConvertToSpecPattern (cas, pat)
5121
- if specPattern != null then
5122
- SpeccedPatMat (cas, cas.paramNames.size, specPattern, body )
5123
+ val missing = checkCapturesPresent (cas, pat)
5124
+ if ! missing.isEmpty then
5125
+ MissingCaptures (cas, missing )
5123
5126
else
5124
- LegacyPatMat (cas)
5127
+ val specPattern = tryConvertToSpecPattern(cas, pat)
5128
+ if specPattern != null then
5129
+ SpeccedPatMat (cas, cas.paramNames.size, specPattern, body)
5130
+ else
5131
+ LegacyPatMat (cas)
5125
5132
case _ =>
5126
5133
val defn .MatchCase (pat, body) = cas : @ unchecked
5127
5134
SubTypeTest (cas, pat, body)
5128
5135
end analyze
5129
5136
5137
+ /** Checks that all the captures of the case are present in the case.
5138
+ *
5139
+ * Sometimes, because of earlier substitutions of an abstract type constructor,
5140
+ * we can end up with patterns that do not mention all their captures anymore.
5141
+ * This can happen even when the body still refers to these missing captures.
5142
+ * In that case, we must always consider the case to be unmatchable, i.e., to
5143
+ * become `Stuck`.
5144
+ *
5145
+ * See pos/i12127.scala for an example.
5146
+ */
5147
+ def checkCapturesPresent (cas : HKTypeLambda , pat : Type )(using Context ): ju.BitSet =
5148
+ val captureCount = cas.paramNames.size
5149
+ val missing = new java.util.BitSet (captureCount)
5150
+ missing.set(0 , captureCount)
5151
+ new CheckCapturesPresent (cas).apply(missing, pat)
5152
+
5153
+ private class CheckCapturesPresent (cas : HKTypeLambda )(using Context ) extends TypeAccumulator [ju.BitSet ]:
5154
+ def apply (missing : ju.BitSet , tp : Type ): ju.BitSet = tp match
5155
+ case TypeParamRef (binder, num) if binder eq cas =>
5156
+ missing.clear(num)
5157
+ missing
5158
+ case _ =>
5159
+ foldOver(missing, tp)
5160
+ end CheckCapturesPresent
5161
+
5130
5162
private def tryConvertToSpecPattern (caseLambda : HKTypeLambda , pat : Type )(using Context ): MatchTypeCasePattern | Null =
5131
5163
var typeParamRefsAccountedFor : Int = 0
5132
5164
0 commit comments