@@ -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 ._
@@ -5074,6 +5076,7 @@ object Types {
5074
5076
case SubTypeTest (origMatchCase : Type , pattern : Type , body : Type )
5075
5077
case SpeccedPatMat (origMatchCase : HKTypeLambda , captureCount : Int , pattern : MatchTypeCasePattern , body : Type )
5076
5078
case LegacyPatMat (origMatchCase : HKTypeLambda )
5079
+ case MissingCaptures (origMatchCase : HKTypeLambda , missing : ju.BitSet )
5077
5080
5078
5081
def origMatchCase : Type
5079
5082
end MatchTypeCaseSpec
@@ -5083,16 +5086,45 @@ object Types {
5083
5086
cas match
5084
5087
case cas : HKTypeLambda =>
5085
5088
val defn .MatchCase (pat, body) = cas.resultType: @ unchecked
5086
- val specPattern = tryConvertToSpecPattern (cas, pat)
5087
- if specPattern != null then
5088
- SpeccedPatMat (cas, cas.paramNames.size, specPattern, body )
5089
+ val missing = checkCapturesPresent (cas, pat)
5090
+ if ! missing.isEmpty then
5091
+ MissingCaptures (cas, missing )
5089
5092
else
5090
- LegacyPatMat (cas)
5093
+ val specPattern = tryConvertToSpecPattern(cas, pat)
5094
+ if specPattern != null then
5095
+ SpeccedPatMat (cas, cas.paramNames.size, specPattern, body)
5096
+ else
5097
+ LegacyPatMat (cas)
5091
5098
case _ =>
5092
5099
val defn .MatchCase (pat, body) = cas : @ unchecked
5093
5100
SubTypeTest (cas, pat, body)
5094
5101
end analyze
5095
5102
5103
+ /** Checks that all the captures of the case are present in the case.
5104
+ *
5105
+ * Sometimes, because of earlier substitutions of an abstract type constructor,
5106
+ * we can end up with patterns that do not mention all their captures anymore.
5107
+ * This can happen even when the body still refers to these missing captures.
5108
+ * In that case, we must always consider the case to be unmatchable, i.e., to
5109
+ * become `Stuck`.
5110
+ *
5111
+ * See pos/i12127.scala for an example.
5112
+ */
5113
+ def checkCapturesPresent (cas : HKTypeLambda , pat : Type )(using Context ): ju.BitSet =
5114
+ val captureCount = cas.paramNames.size
5115
+ val missing = new java.util.BitSet (captureCount)
5116
+ missing.set(0 , captureCount)
5117
+ new CheckCapturesPresent (cas).apply(missing, pat)
5118
+
5119
+ private class CheckCapturesPresent (cas : HKTypeLambda )(using Context ) extends TypeAccumulator [ju.BitSet ]:
5120
+ def apply (missing : ju.BitSet , tp : Type ): ju.BitSet = tp match
5121
+ case TypeParamRef (binder, num) if binder eq cas =>
5122
+ missing.clear(num)
5123
+ missing
5124
+ case _ =>
5125
+ foldOver(missing, tp)
5126
+ end CheckCapturesPresent
5127
+
5096
5128
private def tryConvertToSpecPattern (caseLambda : HKTypeLambda , pat : Type )(using Context ): MatchTypeCasePattern | Null =
5097
5129
var typeParamRefsAccountedFor : Int = 0
5098
5130
0 commit comments