Skip to content

Commit 61512f1

Browse files
authored
Merge pull request #9641 from dotty-staging/drop-constrain-result
Drop ConstrainResult mode bit
2 parents 9346582 + 812b936 commit 61512f1

File tree

3 files changed

+36
-21
lines changed

3 files changed

+36
-21
lines changed

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ object Mode {
6060
*/
6161
val Printing: Mode = newMode(10, "Printing")
6262

63-
/** We are constraining a method based on its expected type. */
64-
val ConstrainResult: Mode = newMode(11, "ConstrainResult")
65-
6663
/** We are currently in a `viewExists` check. In that case, ambiguous
6764
* implicits checks are disabled and we succeed with the first implicit
6865
* found.

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
6363
private var myInstance: TypeComparer = this
6464
def currentInstance: TypeComparer = myInstance
6565

66+
private var useNecessaryEither = false
67+
6668
/** Is a subtype check in progress? In that case we may not
6769
* permanently instantiate type variables, because the corresponding
6870
* constraint might still be retracted and the instantiation should
@@ -129,6 +131,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
129131
}
130132
}
131133

134+
def necessarySubType(tp1: Type, tp2: Type): Boolean =
135+
val saved = useNecessaryEither
136+
useNecessaryEither = true
137+
try topLevelSubType(tp1, tp2)
138+
finally useNecessaryEither = saved
139+
132140
def testSubType(tp1: Type, tp2: Type): CompareResult =
133141
GADTused = false
134142
if !topLevelSubType(tp1, tp2) then CompareResult.Fail
@@ -1481,7 +1489,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
14811489
* @see [[sufficientEither]] for the normal case
14821490
*/
14831491
protected def either(op1: => Boolean, op2: => Boolean): Boolean =
1484-
if ctx.mode.is(Mode.GadtConstraintInference) || ctx.mode.is(Mode.ConstrainResult) then
1492+
if ctx.mode.is(Mode.GadtConstraintInference) || useNecessaryEither then
14851493
necessaryEither(op1, op2)
14861494
else
14871495
sufficientEither(op1, op2)
@@ -2528,6 +2536,9 @@ object TypeComparer {
25282536
def topLevelSubType(tp1: Type, tp2: Type)(using Context): Boolean =
25292537
comparing(_.topLevelSubType(tp1, tp2))
25302538

2539+
def necessarySubType(tp1: Type, tp2: Type)(using Context): Boolean =
2540+
comparing(_.necessarySubType(tp1, tp2))
2541+
25312542
def isSubType(tp1: Type, tp2: Type)(using Context): Boolean =
25322543
comparing(_.isSubType(tp1, tp2))
25332544

compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Uniques._
1414
import config.Printers.typr
1515
import util.SourceFile
1616
import util.Property
17+
import TypeComparer.necessarySubType
1718

1819
import scala.annotation.internal.sharable
1920

@@ -37,6 +38,14 @@ object ProtoTypes {
3738
def isCompatible(tp: Type, pt: Type)(using Context): Boolean =
3839
(tp.widenExpr relaxed_<:< pt.widenExpr) || viewExists(tp, pt)
3940

41+
/** Like isCompatibe, but using a subtype comparison with necessary eithers
42+
* that don't unnecessarily truncate the constraint space, returning false instead.
43+
*/
44+
def necessarilyCompatible(tp: Type, pt: Type)(using Context): Boolean =
45+
val tpw = tp.widenExpr
46+
val ptw = pt.widenExpr
47+
necessarySubType(tpw, ptw) || tpw.isValueSubType(ptw) || viewExists(tp, pt)
48+
4049
/** Test compatibility after normalization.
4150
* Do this in a fresh typerstate unless `keepConstraint` is true.
4251
*/
@@ -67,24 +76,22 @@ object ProtoTypes {
6776
* fits the given expected result type.
6877
*/
6978
def constrainResult(mt: Type, pt: Type)(using Context): Boolean =
70-
withMode(Mode.ConstrainResult) {
71-
val savedConstraint = ctx.typerState.constraint
72-
val res = pt.widenExpr match {
73-
case pt: FunProto =>
74-
mt match {
75-
case mt: MethodType => constrainResult(resultTypeApprox(mt), pt.resultType)
76-
case _ => true
77-
}
78-
case _: ValueTypeOrProto if !disregardProto(pt) =>
79-
isCompatible(normalize(mt, pt), pt)
80-
case pt: WildcardType if pt.optBounds.exists =>
81-
isCompatible(normalize(mt, pt), pt)
82-
case _ =>
83-
true
84-
}
85-
if !res then ctx.typerState.constraint = savedConstraint
86-
res
79+
val savedConstraint = ctx.typerState.constraint
80+
val res = pt.widenExpr match {
81+
case pt: FunProto =>
82+
mt match {
83+
case mt: MethodType => constrainResult(resultTypeApprox(mt), pt.resultType)
84+
case _ => true
85+
}
86+
case _: ValueTypeOrProto if !disregardProto(pt) =>
87+
necessarilyCompatible(normalize(mt, pt), pt)
88+
case pt: WildcardType if pt.optBounds.exists =>
89+
necessarilyCompatible(normalize(mt, pt), pt)
90+
case _ =>
91+
true
8792
}
93+
if !res then ctx.typerState.constraint = savedConstraint
94+
res
8895

8996
/** Constrain result with special case if `meth` is an inlineable method in an inlineable context.
9097
* In that case, we should always succeed and not constrain type parameters in the expected type,

0 commit comments

Comments
 (0)