From 2d0e37353defcec46206e9f0845c738286aabce5 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Fri, 5 Jul 2024 20:24:44 +0200 Subject: [PATCH] Do not propagate `TypeError`s of ops from `TypeComparer#tryAlso` In pos-deep-subtype/i21015.scala:30, we ask the TypeComparer if `M1[Int] <:< M1[A]` `isMatchingApply` first tries `isSubArgs` which succeeds, but then also checks if a weaker constraint is generated by `recur(tp1.superTypeNormalized, tp2.superTypeNormalized)`. The latter throws a `RecursionOverflow` which, before the changes, bypassed the former successful check, and failed the overall subtype test. Fix #21015 --- .../dotty/tools/dotc/core/TypeComparer.scala | 3 +- tests/pos-deep-subtype/i21015.scala | 36 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/pos-deep-subtype/i21015.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index c53c2238a095..dca8bf206bac 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1954,7 +1954,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling // check whether `op2` generates a weaker constraint than `op1` val leftConstraint = constraint constraint = preConstraint - if !(op && subsumes(leftConstraint, constraint, preConstraint)) then + val res = try op catch case _: TypeError => false + if !(res && subsumes(leftConstraint, constraint, preConstraint)) then if constr != noPrinter && !subsumes(constraint, leftConstraint, preConstraint) then constr.println(i"CUT - prefer $leftConstraint over $constraint") constraint = leftConstraint diff --git a/tests/pos-deep-subtype/i21015.scala b/tests/pos-deep-subtype/i21015.scala new file mode 100644 index 000000000000..390462f19df4 --- /dev/null +++ b/tests/pos-deep-subtype/i21015.scala @@ -0,0 +1,36 @@ + +type Init[Coll[_], A, T <: Tuple] = T match + case EmptyTuple => A + case head *: rest => InitCons[Coll, A, head, rest] + +type InitCons[Coll[_], A, H, Rest <: Tuple] = H match + case Int => Init[Coll, Coll[A], Rest] + case _ => Unit + +def fillVector[A, T <: Tuple](dims: T)(x: => A): Init[Vector, A, T] = + dims match + case _: EmptyTuple => x + case (p : (head *: rest)) => + val (head *: rest) = p + head match + case size: Int => fillVector(rest)(Vector.fill(size)(x)) + case _ => () + + +object Minimization: + + type M1[A] = Int match + case 1 => M2[A] + + type M2[A] = Int match + case 2 => M1[Option[A]] + + def m1[A](x: A): M1[A] = ??? + + val _: M1[Int] = m1(1) // was error + val _: M1[Int] = m1[Int](1) // ok + val _: M1[Int] = + val x = m1(1) + x // ok + +end Minimization