Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression in 3.5: Infinite recursion during typecheck of polymorphic-recursion with match types #21015

Closed
Odomontois opened this issue Jul 4, 2024 · 3 comments · Fixed by #21070
Assignees
Labels
area:match-types area:pattern-matching itype:bug regression This worked in a previous version but doesn't anymore
Milestone

Comments

@Odomontois
Copy link

Compiler version

This code breaks compilation on 3.5.0-RC2 but works on 3.4.2

Minimized code

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 _         => ()

Output

Recursion limit exceeded
If that's not the case, you could also try to increase the stacksize using the -Xss JVM option.
For the unprocessed stack trace, compile with -Xno-decode-stacktraces.
A recurring operation is (inner to outer):

  subtype Vector[A] <:< Vector[Vector[A]]
  subtype Vector[Vector[A]] <:< Vector[Vector[Vector[A]]]
  subtype Vector[Vector[Vector[A]]] <:< Vector[Vector[Vector[Vector[A]]]]
  subtype Vector[Vector[Vector[Vector[A]]]] <:< Vector[Vector[Vector[Vector[Vector[A]]]]]
  subtype Vector[Vector[Vector[Vector[Vector[A]]]]] <:< Vector[Vector[Vector[Vector[Vector[Vector[A]]]]]]
  subtype Vector[Vector[Vector[Vector[Vector[Vector[A]]]]]] <:< Vector[Vector[Vector[Vector[Vector[Vector[Vector[A]]]]]]]
  subtype Vector[Vector[Vector[Vector[Vector[Vector[Vector[A]]]]]]] <:< Vector[Vector[Vector[Vector[Vector[Vector[Vector[Vector[A]]]]]]]]
  subtype Vector[Vector[Vector[Vector[Vector[Vector[Vector[Vector[A]]]]]]]] <:< Vector[Vector[Vector[Vector[Vector[Vector[Vector[Vector[Vector[A]]]]]]]]]
  subtype Vector[Vector[Vector[Vector[Vector[Vector[Vector[Vector[Vector[A]]]]]]]]] <:< Vector[Vector[Vector[Vector[Vector[Vector[Vector[Vector[Vector[Vector[A]]]]]]]]]

Expectation

@Odomontois Odomontois added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Jul 4, 2024
@Gedochao Gedochao added regression This worked in a previous version but doesn't anymore area:pattern-matching and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Jul 4, 2024
@Odomontois
Copy link
Author

Note: this version is almost the same but doesn't have mutually recursive match types and compiles ok

type Init[Coll[_], A, T <: Tuple] = T match
    case EmptyTuple   => A
    case head *: rest =>
        head 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[A](size)(x))
                case _: Any    => ()

@WojciechMazur
Copy link
Contributor

Bisect points to d421f88

@EugeneFlesselle
Copy link
Contributor

EugeneFlesselle commented Jul 4, 2024

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] = ???

object Test:
  val _: M1[Int] = m1(1) // error
  val _: M1[Int] = m1[Int](1) // ok
  val _: M1[Int] =
    val x = m1(1)
    x // ok

@EugeneFlesselle EugeneFlesselle self-assigned this Jul 4, 2024
EugeneFlesselle added a commit to dotty-staging/dotty that referenced this issue Jul 5, 2024
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 scala#21015
EugeneFlesselle added a commit that referenced this issue Jul 6, 2024
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
WojciechMazur pushed a commit that referenced this issue Jul 10, 2024
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

[Cherry-picked 2d0e373]
@WojciechMazur WojciechMazur added this to the 3.6.0 milestone Oct 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:match-types area:pattern-matching itype:bug regression This worked in a previous version but doesn't anymore
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants