@@ -1219,6 +1219,17 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
12191219 fix(tp)
12201220 }
12211221
1222+ /** Returns true iff the result of evaluating either `op1` or `op2` is true and approximates resulting constraints.
1223+ *
1224+ * If we're _not_ in GADTFlexible mode, we try to keep the smaller of the two constraints.
1225+ * If we're _in_ GADTFlexible mode, we keep the smaller constraint if any, or no constraint at all.
1226+ *
1227+ * @see [[sufficientEither ]] for the normal case
1228+ * @see [[necessaryEither ]] for the GADTFlexible case
1229+ */
1230+ private def either (op1 : => Boolean , op2 : => Boolean ): Boolean =
1231+ if (ctx.mode.is(Mode .GADTflexible )) necessaryEither(op1, op2) else sufficientEither(op1, op2)
1232+
12221233 /** Returns true iff the result of evaluating either `op1` or `op2` is true,
12231234 * trying at the same time to keep the constraint as wide as possible.
12241235 * E.g, if
@@ -1247,13 +1258,79 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
12471258 *
12481259 * Here, each precondition leads to a different constraint, and neither of
12491260 * the two post-constraints subsumes the other.
1261+ *
1262+ * Note that to be complete when it comes to typechecking, we would instead need to backtrack
1263+ * and attempt to typecheck with the other constraint.
1264+ *
1265+ * Method name comes from the notion that we are keeping a constraint which is sufficient to satisfy
1266+ * one of subtyping relationships.
12501267 */
1251- private def either (op1 : => Boolean , op2 : => Boolean ): Boolean = {
1268+ private def sufficientEither (op1 : => Boolean , op2 : => Boolean ): Boolean = {
1269+ val preConstraint = constraint
1270+ op1 && {
1271+ val leftConstraint = constraint
1272+ constraint = preConstraint
1273+ if (! (op2 && subsumes(leftConstraint, constraint, preConstraint))) {
1274+ if (constr != noPrinter && ! subsumes(constraint, leftConstraint, preConstraint))
1275+ constr.println(i " CUT - prefer $leftConstraint over $constraint" )
1276+ constraint = leftConstraint
1277+ }
1278+ true
1279+ } || op2
1280+ }
1281+
1282+ /** Returns true iff the result of evaluating either `op1` or `op2` is true, keeping the smaller constraint if any.
1283+ * E.g., if
1284+ *
1285+ * tp11 <:< tp12 = true with constraint c1 and GADT constraint g1
1286+ * tp12 <:< tp22 = true with constraint c2 and GADT constraint g2
1287+ *
1288+ * We keep:
1289+ * - (c1, g1) if c2 subsumes c1 and g2 subsumes g1
1290+ * - (c2, g2) if c1 subsumes c2 and g1 subsumes g2
1291+ * - neither constraint pair otherwise.
1292+ *
1293+ * Like [[sufficientEither ]], this method is used to approximate a solution in one of the following cases:
1294+ *
1295+ * T1 & T2 <:< T3
1296+ * T1 <:< T2 | T3
1297+ *
1298+ * Unlike [[sufficientEither ]], this method is used in GADTFlexible mode, when we are attempting to infer GADT
1299+ * constraints that necessarily follow from the subtyping relationship. For instance, if we have
1300+ *
1301+ * enum Expr[T] {
1302+ * case IntExpr(i: Int) extends Expr[Int]
1303+ * case StrExpr(s: String) extends Expr[String]
1304+ * }
1305+ *
1306+ * and `A` is an abstract type and we know that
1307+ *
1308+ * Expr[A] <: IntExpr | StrExpr
1309+ *
1310+ * (the case with &-type is analogous) then this may follow either from
1311+ *
1312+ * Expr[A] <: IntExpr or Expr[A] <: StrExpr
1313+ *
1314+ * Since we don't know which branch is true, we need to give up and not keep either constraint. OTOH, if one
1315+ * constraint pair is subsumed by the other, we know that it is necessary for both cases and therefore we can
1316+ * keep it.
1317+ *
1318+ * Like [[sufficientEither ]], this method is not complete because sometimes, the necessary constraint
1319+ * is neither of the pairs. For instance, if
1320+ *
1321+ * g1 = { A = Int, B = String }
1322+ * g2 = { A = Int, B = Int }
1323+ *
1324+ * then the necessary constraint is { A = Int }, but correctly inferring that is, as far as we know, too expensive.
1325+ *
1326+ * Method name comes from the notion that we are keeping the constraint which is necessary to satisfy both
1327+ * subtyping relationships.
1328+ */
1329+ private def necessaryEither (op1 : => Boolean , op2 : => Boolean ): Boolean = {
12521330 val preConstraint = constraint
12531331
1254- if (ctx.mode.is(Mode .GADTflexible )) {
12551332 val preGadt = ctx.gadt.fresh
1256- // if GADTflexible mode is on, we always have a ProperGadtConstraint
1333+ // if GADTflexible mode is on, we expect to always have a ProperGadtConstraint
12571334 val pre = preGadt.asInstanceOf [ProperGadtConstraint ]
12581335 if (op1) {
12591336 val leftConstraint = constraint
@@ -1284,18 +1361,6 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
12841361 true
12851362 }
12861363 } else op2
1287- } else {
1288- op1 && {
1289- val leftConstraint = constraint
1290- constraint = preConstraint
1291- if (! (op2 && subsumes(leftConstraint, constraint, preConstraint))) {
1292- if (constr != noPrinter && ! subsumes(constraint, leftConstraint, preConstraint))
1293- constr.println(i " CUT - prefer $leftConstraint over $constraint" )
1294- constraint = leftConstraint
1295- }
1296- true
1297- } || op2
1298- }
12991364 }
13001365
13011366 /** Does type `tp1` have a member with name `name` whose normalized type is a subtype of
0 commit comments