Skip to content

Commit aa8d348

Browse files
committed
Use the specced match types for abstract tycons in patterns.
An abstract tycon can be matched if it is exactly equal to the scrutinee's tycon.
1 parent 067b828 commit aa8d348

File tree

2 files changed

+49
-26
lines changed

2 files changed

+49
-26
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3345,16 +3345,14 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
33453345
val innerScrutIsWidenedAbstract =
33463346
scrutIsWidenedAbstract
33473347
|| (needsConcreteScrut && !isConcrete(scrut)) // no point in checking concreteness if it does not need to be concrete
3348+
matchArgs(argPatterns, baseArgs, classType.typeParams, innerScrutIsWidenedAbstract)
3349+
case _ =>
3350+
false
33483351

3349-
def matchArgs(argPatterns: List[MatchTypeCasePattern], baseArgs: List[Type], tparams: List[TypeParamInfo]): Boolean =
3350-
if argPatterns.isEmpty then
3351-
true
3352-
else
3353-
rec(argPatterns.head, baseArgs.head, tparams.head.paramVarianceSign, innerScrutIsWidenedAbstract)
3354-
&& matchArgs(argPatterns.tail, baseArgs.tail, tparams.tail)
3355-
3356-
matchArgs(argPatterns, baseArgs, classType.typeParams)
3357-
3352+
case MatchTypeCasePattern.AbstractTypeConstructor(tycon, argPatterns) =>
3353+
scrut.dealias match
3354+
case scrutDealias @ AppliedType(scrutTycon, args) if scrutTycon =:= tycon =>
3355+
matchArgs(argPatterns, args, tycon.typeParams, scrutIsWidenedAbstract)
33583356
case _ =>
33593357
false
33603358

@@ -3366,6 +3364,13 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
33663364
false
33673365
end rec
33683366

3367+
def matchArgs(argPatterns: List[MatchTypeCasePattern], args: List[Type], tparams: List[TypeParamInfo], scrutIsWidenedAbstract: Boolean): Boolean =
3368+
if argPatterns.isEmpty then
3369+
true
3370+
else
3371+
rec(argPatterns.head, args.head, tparams.head.paramVarianceSign, scrutIsWidenedAbstract)
3372+
&& matchArgs(argPatterns.tail, args.tail, tparams.tail, scrutIsWidenedAbstract)
3373+
33693374
// This might not be needed
33703375
val constrainedCaseLambda = constrained(spec.origMatchCase, ast.tpd.EmptyTree)._1.asInstanceOf[HKTypeLambda]
33713376

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5093,6 +5093,7 @@ object Types extends TypeUtils {
50935093
case TypeTest(tpe: Type)
50945094
case BaseTypeTest(classType: TypeRef, argPatterns: List[MatchTypeCasePattern], needsConcreteScrut: Boolean)
50955095
case CompileTimeS(argPattern: MatchTypeCasePattern)
5096+
case AbstractTypeConstructor(tycon: Type, argPatterns: List[MatchTypeCasePattern])
50965097

50975098
def isTypeTest: Boolean =
50985099
this.isInstanceOf[TypeTest]
@@ -5167,25 +5168,15 @@ object Types extends TypeUtils {
51675168
case pat @ AppliedType(tycon: TypeRef, args) if variance == 1 =>
51685169
val tyconSym = tycon.symbol
51695170
if tyconSym.isClass then
5170-
val cls = tyconSym.asClass
5171-
if cls.name.startsWith("Tuple") && defn.isTupleNType(pat) then
5171+
if tyconSym.name.startsWith("Tuple") && defn.isTupleNType(pat) then
51725172
rec(pat.toNestedPairs, variance)
51735173
else
5174-
val tparams = tycon.typeParams
5175-
val argPatterns = args.zip(tparams).map { (arg, tparam) =>
5176-
rec(arg, tparam.paramVarianceSign)
5174+
recArgPatterns(pat) { argPatterns =>
5175+
val needsConcreteScrut = argPatterns.zip(tycon.typeParams).exists {
5176+
(argPattern, tparam) => tparam.paramVarianceSign != 0 && argPattern.needsConcreteScrutInVariantPos
5177+
}
5178+
MatchTypeCasePattern.BaseTypeTest(tycon, argPatterns, needsConcreteScrut)
51775179
}
5178-
if argPatterns.exists(_ == null) then
5179-
null
5180-
else
5181-
val argPatterns1 = argPatterns.asInstanceOf[List[MatchTypeCasePattern]] // they are not null
5182-
if argPatterns1.forall(_.isTypeTest) then
5183-
MatchTypeCasePattern.TypeTest(pat)
5184-
else
5185-
val needsConcreteScrut = argPatterns1.zip(tparams).exists {
5186-
(argPattern, tparam) => tparam.paramVarianceSign != 0 && argPattern.needsConcreteScrutInVariantPos
5187-
}
5188-
MatchTypeCasePattern.BaseTypeTest(tycon, argPatterns1, needsConcreteScrut)
51895180
else if defn.isCompiletime_S(tyconSym) && args.sizeIs == 1 then
51905181
val argPattern = rec(args.head, variance)
51915182
if argPattern == null then
@@ -5195,12 +5186,39 @@ object Types extends TypeUtils {
51955186
else
51965187
MatchTypeCasePattern.CompileTimeS(argPattern)
51975188
else
5198-
null
5189+
tycon.info match
5190+
case _: RealTypeBounds => recAbstractTypeConstructor(pat)
5191+
case _ => null
5192+
5193+
case pat @ AppliedType(tycon: TypeParamRef, _) if variance == 1 =>
5194+
recAbstractTypeConstructor(pat)
51995195

52005196
case _ =>
52015197
MatchTypeCasePattern.TypeTest(pat)
52025198
end rec
52035199

5200+
def recAbstractTypeConstructor(pat: AppliedType): MatchTypeCasePattern | Null =
5201+
recArgPatterns(pat) { argPatterns =>
5202+
MatchTypeCasePattern.AbstractTypeConstructor(pat.tycon, argPatterns)
5203+
}
5204+
end recAbstractTypeConstructor
5205+
5206+
def recArgPatterns(pat: AppliedType)(whenNotTypeTest: List[MatchTypeCasePattern] => MatchTypeCasePattern | Null): MatchTypeCasePattern | Null =
5207+
val AppliedType(tycon, args) = pat
5208+
val tparams = tycon.typeParams
5209+
val argPatterns = args.zip(tparams).map { (arg, tparam) =>
5210+
rec(arg, tparam.paramVarianceSign)
5211+
}
5212+
if argPatterns.exists(_ == null) then
5213+
null
5214+
else
5215+
val argPatterns1 = argPatterns.asInstanceOf[List[MatchTypeCasePattern]] // they are not null
5216+
if argPatterns1.forall(_.isTypeTest) then
5217+
MatchTypeCasePattern.TypeTest(pat)
5218+
else
5219+
whenNotTypeTest(argPatterns1)
5220+
end recArgPatterns
5221+
52045222
val result = rec(pat, variance = 1)
52055223
if typeParamRefsAccountedFor == caseLambda.paramNames.size then result
52065224
else null

0 commit comments

Comments
 (0)