Skip to content

Commit 343235b

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 81a97bb commit 343235b

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
@@ -3337,16 +3337,14 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
33373337
val innerScrutIsWidenedAbstract =
33383338
scrutIsWidenedAbstract
33393339
|| (needsConcreteScrut && !isConcrete(scrut)) // no point in checking concreteness if it does not need to be concrete
3340+
matchArgs(argPatterns, baseArgs, classType.typeParams, innerScrutIsWidenedAbstract)
3341+
case _ =>
3342+
false
33403343

3341-
def matchArgs(argPatterns: List[MatchTypeCasePattern], baseArgs: List[Type], tparams: List[TypeParamInfo]): Boolean =
3342-
if argPatterns.isEmpty then
3343-
true
3344-
else
3345-
rec(argPatterns.head, baseArgs.head, tparams.head.paramVarianceSign, innerScrutIsWidenedAbstract)
3346-
&& matchArgs(argPatterns.tail, baseArgs.tail, tparams.tail)
3347-
3348-
matchArgs(argPatterns, baseArgs, classType.typeParams)
3349-
3344+
case MatchTypeCasePattern.AbstractTypeConstructor(tycon, argPatterns) =>
3345+
scrut.dealias match
3346+
case scrutDealias @ AppliedType(scrutTycon, args) if scrutTycon =:= tycon =>
3347+
matchArgs(argPatterns, args, tycon.typeParams, scrutIsWidenedAbstract)
33503348
case _ =>
33513349
false
33523350

@@ -3358,6 +3356,13 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
33583356
false
33593357
end rec
33603358

3359+
def matchArgs(argPatterns: List[MatchTypeCasePattern], args: List[Type], tparams: List[TypeParamInfo], scrutIsWidenedAbstract: Boolean): Boolean =
3360+
if argPatterns.isEmpty then
3361+
true
3362+
else
3363+
rec(argPatterns.head, args.head, tparams.head.paramVarianceSign, scrutIsWidenedAbstract)
3364+
&& matchArgs(argPatterns.tail, args.tail, tparams.tail, scrutIsWidenedAbstract)
3365+
33613366
// This might not be needed
33623367
val constrainedCaseLambda = constrained(spec.origMatchCase, ast.tpd.EmptyTree)._1.asInstanceOf[HKTypeLambda]
33633368

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

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5096,6 +5096,7 @@ object Types {
50965096
case TypeTest(tpe: Type)
50975097
case BaseTypeTest(classType: TypeRef, argPatterns: List[MatchTypeCasePattern], needsConcreteScrut: Boolean)
50985098
case CompileTimeS(argPattern: MatchTypeCasePattern)
5099+
case AbstractTypeConstructor(tycon: Type, argPatterns: List[MatchTypeCasePattern])
50995100

51005101
def isTypeTest: Boolean =
51015102
this.isInstanceOf[TypeTest]
@@ -5171,25 +5172,15 @@ object Types {
51715172
case pat @ AppliedType(tycon: TypeRef, args) if variance == 1 =>
51725173
val tyconSym = tycon.symbol
51735174
if tyconSym.isClass then
5174-
val cls = tyconSym.asClass
5175-
if cls.name.startsWith("Tuple") && defn.isTupleNType(pat) then
5175+
if tyconSym.name.startsWith("Tuple") && defn.isTupleNType(pat) then
51765176
rec(pat.toNestedPairs, variance)
51775177
else
5178-
val tparams = tycon.typeParams
5179-
val argPatterns = args.zip(tparams).map { (arg, tparam) =>
5180-
rec(arg, tparam.paramVarianceSign)
5178+
recArgPatterns(pat) { argPatterns =>
5179+
val needsConcreteScrut = argPatterns.zip(tycon.typeParams).exists {
5180+
(argPattern, tparam) => tparam.paramVarianceSign != 0 && argPattern.needsConcreteScrutInVariantPos
5181+
}
5182+
MatchTypeCasePattern.BaseTypeTest(tycon, argPatterns, needsConcreteScrut)
51815183
}
5182-
if argPatterns.exists(_ == null) then
5183-
null
5184-
else
5185-
val argPatterns1 = argPatterns.asInstanceOf[List[MatchTypeCasePattern]] // they are not null
5186-
if argPatterns1.forall(_.isTypeTest) then
5187-
MatchTypeCasePattern.TypeTest(pat)
5188-
else
5189-
val needsConcreteScrut = argPatterns1.zip(tparams).exists {
5190-
(argPattern, tparam) => tparam.paramVarianceSign != 0 && argPattern.needsConcreteScrutInVariantPos
5191-
}
5192-
MatchTypeCasePattern.BaseTypeTest(tycon, argPatterns1, needsConcreteScrut)
51935184
else if defn.isCompiletime_S(tyconSym) && args.sizeIs == 1 then
51945185
val argPattern = rec(args.head, variance)
51955186
if argPattern == null then
@@ -5199,12 +5190,39 @@ object Types {
51995190
else
52005191
MatchTypeCasePattern.CompileTimeS(argPattern)
52015192
else
5202-
null
5193+
tycon.info match
5194+
case _: RealTypeBounds => recAbstractTypeConstructor(pat)
5195+
case _ => null
5196+
5197+
case pat @ AppliedType(tycon: TypeParamRef, _) if variance == 1 =>
5198+
recAbstractTypeConstructor(pat)
52035199

52045200
case _ =>
52055201
MatchTypeCasePattern.TypeTest(pat)
52065202
end rec
52075203

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

0 commit comments

Comments
 (0)