Skip to content

Commit 5118628

Browse files
committed
refactor constrainPatternType
1 parent ed40359 commit 5118628

File tree

1 file changed

+110
-110
lines changed

1 file changed

+110
-110
lines changed

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

Lines changed: 110 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -74,106 +74,127 @@ trait PatternTypeConstrainer { self: TypeComparer =>
7474
* scrutinee and pattern types. This does not apply if the pattern type is only applied to type variables,
7575
* in which case the subtyping relationship "heals" the type.
7676
*/
77-
def constrainPatternType(pat: Type, scrut: Type, forceInvariantRefinement: Boolean = false, typeMembersTouched: Boolean = false): Boolean = trace(i"constrainPatternType(${scrutRepr(scrut)}, $pat)", gadts, res => s"$res\ngadt = ${ctx.gadt.debugBoundsDescription}") {
78-
79-
def classesMayBeCompatible: Boolean = {
80-
import Flags._
81-
val patCls = pat.classSymbol
82-
val scrCls = scrut.classSymbol
83-
!patCls.exists || !scrCls.exists || {
84-
if (patCls.is(Final)) patCls.derivesFrom(scrCls)
85-
else if (scrCls.is(Final)) scrCls.derivesFrom(patCls)
86-
else if (!patCls.is(Flags.Trait) && !scrCls.is(Flags.Trait))
87-
patCls.derivesFrom(scrCls) || scrCls.derivesFrom(patCls)
88-
else true
77+
def constrainPatternType(pat: Type, scrut: Type, forceInvariantRefinement: Boolean = false): Boolean = trace(i"constrainPatternType(${scrutRepr(scrut)}, $pat)", gadts, res => s"$res\ngadt = ${ctx.gadt.debugBoundsDescription}") {
78+
def recur(pat: Type, scrut: Type): Boolean = {
79+
def classesMayBeCompatible: Boolean = {
80+
import Flags._
81+
val patCls = pat.classSymbol
82+
val scrCls = scrut.classSymbol
83+
!patCls.exists || !scrCls.exists || {
84+
if (patCls.is(Final)) patCls.derivesFrom(scrCls)
85+
else if (scrCls.is(Final)) scrCls.derivesFrom(patCls)
86+
else if (!patCls.is(Flags.Trait) && !scrCls.is(Flags.Trait))
87+
patCls.derivesFrom(scrCls) || scrCls.derivesFrom(patCls)
88+
else true
89+
}
8990
}
90-
}
91-
92-
def stripRefinement(tp: Type): Type = tp match {
93-
case tp: RefinedOrRecType => stripRefinement(tp.parent)
94-
case tp => tp
95-
}
9691

97-
def tryConstrainSimplePatternType(pat: Type, scrut: Type) = {
98-
val patCls = pat.classSymbol
99-
val scrCls = scrut.classSymbol
100-
patCls.exists && scrCls.exists
101-
&& (patCls.derivesFrom(scrCls) || scrCls.derivesFrom(patCls))
102-
&& constrainSimplePatternType(pat, scrut, forceInvariantRefinement)
103-
}
92+
def stripRefinement(tp: Type): Type = tp match {
93+
case tp: RefinedOrRecType => stripRefinement(tp.parent)
94+
case tp => tp
95+
}
10496

105-
def constrainUpcasted(scrut: Type): Boolean = trace(i"constrainUpcasted($scrut)", gadts) {
106-
// Fold a list of types into an AndType
107-
def buildAndType(xs: List[Type]): Type = {
108-
@annotation.tailrec def recur(acc: Type, rem: List[Type]): Type = rem match {
109-
case Nil => acc
110-
case x :: rem => recur(AndType(acc, x), rem)
111-
}
112-
xs match {
113-
case Nil => NoType
114-
case x :: xs => recur(x, xs)
115-
}
97+
def tryConstrainSimplePatternType(pat: Type, scrut: Type) = {
98+
val patCls = pat.classSymbol
99+
val scrCls = scrut.classSymbol
100+
patCls.exists && scrCls.exists
101+
&& (patCls.derivesFrom(scrCls) || scrCls.derivesFrom(patCls))
102+
&& constrainSimplePatternType(pat, scrut, forceInvariantRefinement)
116103
}
117104

118-
scrut match {
119-
case scrut: TypeRef if scrut.symbol.isClass =>
120-
// consider all parents
121-
val parents = scrut.parents
122-
val andType = buildAndType(parents)
123-
!andType.exists || constrainPatternType(pat, andType, typeMembersTouched = true)
124-
case scrut @ AppliedType(tycon: TypeRef, _) if tycon.symbol.isClass =>
125-
val patCls = pat.classSymbol
126-
// find all shared parents in the inheritance hierarchy between pat and scrut
127-
def allParentsSharedWithPat(tp: Type, tpClassSym: ClassSymbol): List[Symbol] = {
128-
var parents = tpClassSym.info.parents
129-
if parents.nonEmpty && parents.head.classSymbol == defn.ObjectClass then
130-
parents = parents.tail
131-
parents flatMap { tp =>
132-
val sym = tp.classSymbol.asClass
133-
if patCls.derivesFrom(sym) then List(sym)
134-
else allParentsSharedWithPat(tp, sym)
135-
}
105+
def constrainUpcasted(scrut: Type): Boolean = trace(i"constrainUpcasted($scrut)", gadts) {
106+
// Fold a list of types into an AndType
107+
def buildAndType(xs: List[Type]): Type = {
108+
@annotation.tailrec def recur(acc: Type, rem: List[Type]): Type = rem match {
109+
case Nil => acc
110+
case x :: rem => recur(AndType(acc, x), rem)
136111
}
137-
val allSyms = allParentsSharedWithPat(tycon, tycon.symbol.asClass)
138-
val baseClasses = allSyms map scrut.baseType
139-
val andType = buildAndType(baseClasses)
140-
!andType.exists || constrainPatternType(pat, andType, typeMembersTouched = true)
141-
case _ =>
142-
def tryGadtBounds = scrut match {
143-
case scrut: TypeRef =>
144-
ctx.gadt.bounds(scrut.symbol) match {
145-
case tb: TypeBounds =>
146-
val hi = tb.hi
147-
constrainPatternType(pat, hi, typeMembersTouched = true)
148-
case null => true
149-
}
150-
case _ => true
112+
xs match {
113+
case Nil => NoType
114+
case x :: xs => recur(x, xs)
151115
}
116+
}
152117

153-
def trySuperType =
154-
val upcasted: Type = scrut match {
155-
case scrut: TypeProxy =>
156-
scrut.superType
157-
case _ => NoType
118+
scrut match {
119+
case scrut: TypeRef if scrut.symbol.isClass =>
120+
// consider all parents
121+
val parents = scrut.parents
122+
val andType = buildAndType(parents)
123+
!andType.exists || recur(pat, andType)
124+
case scrut @ AppliedType(tycon: TypeRef, _) if tycon.symbol.isClass =>
125+
val patCls = pat.classSymbol
126+
// find all shared parents in the inheritance hierarchy between pat and scrut
127+
def allParentsSharedWithPat(tp: Type, tpClassSym: ClassSymbol): List[Symbol] = {
128+
var parents = tpClassSym.info.parents
129+
if parents.nonEmpty && parents.head.classSymbol == defn.ObjectClass then
130+
parents = parents.tail
131+
parents flatMap { tp =>
132+
val sym = tp.classSymbol.asClass
133+
if patCls.derivesFrom(sym) then List(sym)
134+
else allParentsSharedWithPat(tp, sym)
135+
}
136+
}
137+
val allSyms = allParentsSharedWithPat(tycon, tycon.symbol.asClass)
138+
val baseClasses = allSyms map scrut.baseType
139+
val andType = buildAndType(baseClasses)
140+
!andType.exists || recur(pat, andType)
141+
case _ =>
142+
def tryGadtBounds = scrut match {
143+
case scrut: TypeRef =>
144+
ctx.gadt.bounds(scrut.symbol) match {
145+
case tb: TypeBounds =>
146+
val hi = tb.hi
147+
recur(pat, hi)
148+
case null => true
149+
}
150+
case _ => true
158151
}
159-
if (upcasted.exists)
160-
tryConstrainSimplePatternType(pat, upcasted) || constrainUpcasted(upcasted)
161-
else true
162152

163-
tryGadtBounds && trySuperType
153+
def trySuperType =
154+
val upcasted: Type = scrut match {
155+
case scrut: TypeProxy =>
156+
scrut.superType
157+
case _ => NoType
158+
}
159+
if (upcasted.exists)
160+
tryConstrainSimplePatternType(pat, upcasted) || constrainUpcasted(upcasted)
161+
else true
162+
163+
tryGadtBounds && trySuperType
164+
}
165+
}
166+
167+
def dealiasDropNonmoduleRefs(tp: Type) = tp.dealias match {
168+
case tp: TermRef =>
169+
// we drop TermRefs that don't have a class symbol, as they can't
170+
// meaningfully participate in GADT reasoning and just get in the way.
171+
// Their info could, for an example, be an AndType. One example where
172+
// this is important is an enum case that extends its parent and an
173+
// additional trait - argument-less enum cases desugar to vals.
174+
// See run/enum-Tree.scala.
175+
if tp.classSymbol.exists then tp else tp.info
176+
case tp => tp
164177
}
165-
}
166178

167-
def dealiasDropNonmoduleRefs(tp: Type) = tp.dealias match {
168-
case tp: TermRef =>
169-
// we drop TermRefs that don't have a class symbol, as they can't
170-
// meaningfully participate in GADT reasoning and just get in the way.
171-
// Their info could, for an example, be an AndType. One example where
172-
// this is important is an enum case that extends its parent and an
173-
// additional trait - argument-less enum cases desugar to vals.
174-
// See run/enum-Tree.scala.
175-
if tp.classSymbol.exists then tp else tp.info
176-
case tp => tp
179+
dealiasDropNonmoduleRefs(scrut) match {
180+
case OrType(scrut1, scrut2) =>
181+
either(recur(pat, scrut1), recur(pat, scrut2))
182+
case AndType(scrut1, scrut2) =>
183+
recur(pat, scrut1) && recur(pat, scrut2)
184+
case scrut: RefinedOrRecType =>
185+
recur(pat, stripRefinement(scrut))
186+
case scrut => dealiasDropNonmoduleRefs(pat) match {
187+
case OrType(pat1, pat2) =>
188+
either(recur(pat1, scrut), recur(pat2, scrut))
189+
case AndType(pat1, pat2) =>
190+
recur(pat1, scrut) && recur(pat2, scrut)
191+
case pat: RefinedOrRecType =>
192+
recur(stripRefinement(pat), scrut)
193+
case pat =>
194+
tryConstrainSimplePatternType(pat, scrut)
195+
|| classesMayBeCompatible && constrainUpcasted(scrut)
196+
}
197+
}
177198
}
178199

179200
/** Reconstruct subtype constraints for type members of the scrutinee and the pattern. */
@@ -269,28 +290,7 @@ trait PatternTypeConstrainer { self: TypeComparer =>
269290
res
270291
}
271292

272-
def constrainTypeParams =
273-
dealiasDropNonmoduleRefs(scrut) match {
274-
case OrType(scrut1, scrut2) =>
275-
either(constrainPatternType(pat, scrut1, typeMembersTouched = true), constrainPatternType(pat, scrut2, typeMembersTouched = true))
276-
case AndType(scrut1, scrut2) =>
277-
constrainPatternType(pat, scrut1, typeMembersTouched = true) && constrainPatternType(pat, scrut2, typeMembersTouched = true)
278-
case scrut: RefinedOrRecType =>
279-
constrainPatternType(pat, stripRefinement(scrut), typeMembersTouched = true)
280-
case scrut => dealiasDropNonmoduleRefs(pat) match {
281-
case OrType(pat1, pat2) =>
282-
either(constrainPatternType(pat1, scrut, typeMembersTouched = true), constrainPatternType(pat2, scrut, typeMembersTouched = true))
283-
case AndType(pat1, pat2) =>
284-
constrainPatternType(pat1, scrut, typeMembersTouched = true) && constrainPatternType(pat2, scrut, typeMembersTouched = true)
285-
case pat: RefinedOrRecType =>
286-
constrainPatternType(stripRefinement(pat), scrut, typeMembersTouched = true)
287-
case pat =>
288-
tryConstrainSimplePatternType(pat, scrut)
289-
|| classesMayBeCompatible && constrainUpcasted(scrut)
290-
}
291-
}
292-
293-
constrainTypeParams && (typeMembersTouched || constrainTypeMembers)
293+
recur(pat, scrut) && constrainTypeMembers
294294
}
295295

296296
/** Show the scrutinee. Will show the path if available. */

0 commit comments

Comments
 (0)