Skip to content

Commit 000d9e9

Browse files
committed
Capture convert only if LHS is a path
Capture conversion is generally sound only if the LHS of a comparison is a path.
1 parent 83eedaf commit 000d9e9

File tree

1 file changed

+30
-10
lines changed

1 file changed

+30
-10
lines changed

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

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,20 +130,30 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
130130
}
131131
}
132132

133-
private[this] var approx: ApproxState = NoApprox
133+
private[this] var approx: ApproxState = FreshApprox
134134
protected def approxState: ApproxState = approx
135135

136+
private [this] var leftRoot: Type = null
137+
136138
protected def isSubType(tp1: Type, tp2: Type, a: ApproxState): Boolean = {
137-
val saved = approx
138-
this.approx = a
139+
val savedApprox = approx
140+
val savedLeftRoot = leftRoot
141+
if (a == FreshApprox) {
142+
this.approx = NoApprox
143+
this.leftRoot = tp1
144+
}
145+
else this.approx = a
139146
try recur(tp1, tp2)
140147
catch {
141148
case ex: Throwable => handleRecursive("subtype", i"$tp1 <:< $tp2", ex, weight = 2)
142149
}
143-
finally this.approx = saved
150+
finally {
151+
this.approx = savedApprox
152+
this.leftRoot = savedLeftRoot
153+
}
144154
}
145155

146-
def isSubType(tp1: Type, tp2: Type)(implicit nc: AbsentContext): Boolean = isSubType(tp1, tp2, NoApprox)
156+
def isSubType(tp1: Type, tp2: Type)(implicit nc: AbsentContext): Boolean = isSubType(tp1, tp2, FreshApprox)
147157

148158
protected def recur(tp1: Type, tp2: Type): Boolean = trace(s"isSubType ${traceInfo(tp1, tp2)} $approx", subtyping) {
149159

@@ -277,7 +287,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
277287
case tp2: SuperType =>
278288
def compareSuper = tp1 match {
279289
case tp1: SuperType =>
280-
isSubType(tp1.thistpe, tp2.thistpe) &&
290+
recur(tp1.thistpe, tp2.thistpe) &&
281291
isSameType(tp1.supertpe, tp2.supertpe)
282292
case _ =>
283293
secondTry
@@ -355,7 +365,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
355365
}
356366
case tp1: SkolemType =>
357367
tp2 match {
358-
case tp2: SkolemType if !ctx.phase.isTyper && isSubType(tp1.info, tp2.info) => true
368+
case tp2: SkolemType if !ctx.phase.isTyper && recur(tp1.info, tp2.info) => true
359369
case _ => thirdTry
360370
}
361371
case tp1: TypeVar =>
@@ -449,7 +459,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
449459
// So if the constraint is not yet frozen, we do the same comparison again
450460
// with a frozen constraint, which means that we get a chance to do the
451461
// widening in `fourthTry` before adding to the constraint.
452-
if (frozenConstraint) isSubType(tp1, bounds(tp2).lo)
462+
if (frozenConstraint) recur(tp1, bounds(tp2).lo)
453463
else isSubTypeWhenFrozen(tp1, tp2)
454464
alwaysTrue || {
455465
if (canConstrain(tp2) && !approx.low)
@@ -879,7 +889,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
879889
compareLower(info2, tyconIsTypeRef = true)
880890
case info2: ClassInfo =>
881891
tycon2.name.toString.startsWith("Tuple") &&
882-
defn.isTupleType(tp2) && isSubType(tp1, tp2.toNestedPairs) ||
892+
defn.isTupleType(tp2) && recur(tp1, tp2.toNestedPairs) ||
883893
tryBaseType(info2.cls)
884894
case _ =>
885895
fourthTry
@@ -1029,7 +1039,14 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
10291039
arg2.contains(arg1norm)
10301040
case _ =>
10311041
arg1 match {
1032-
case arg1: TypeBounds => false
1042+
case arg1: TypeBounds =>
1043+
tparam match {
1044+
case tparam: Symbol if leftRoot.isStable =>
1045+
val captured = TypeRef(leftRoot, tparam)
1046+
isSubArg(captured, arg2)
1047+
case _ =>
1048+
false
1049+
}
10331050
case _ =>
10341051
(v > 0 || isSubType(arg2, arg1)) &&
10351052
(v < 0 || isSubType(arg1, arg2))
@@ -1809,6 +1826,8 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
18091826

18101827
object TypeComparer {
18111828

1829+
val oldScheme = true
1830+
18121831
/** Class for unification variables used in `natValue`. */
18131832
private class AnyConstantType extends UncachedGroundType with ValueType {
18141833
var tpe: Type = NoType
@@ -1835,6 +1854,7 @@ object TypeComparer {
18351854
}
18361855

18371856
val NoApprox: ApproxState = new ApproxState(0)
1857+
val FreshApprox: ApproxState = new ApproxState(4)
18381858

18391859
/** Show trace of comparison operations when performing `op` as result string */
18401860
def explaining[T](say: String => Unit)(op: Context => T)(implicit ctx: Context): T = {

0 commit comments

Comments
 (0)