Skip to content

Stack overflow in TypeComparer #2874

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

Closed
abeln opened this issue Jul 15, 2017 · 6 comments
Closed

Stack overflow in TypeComparer #2874

abeln opened this issue Jul 15, 2017 · 6 comments

Comments

@abeln
Copy link
Contributor

abeln commented Jul 15, 2017

Attempting to compile the following program causes a stack overflow in TypeComparer:

class T

class N[Z]

class C[X] extends N[N[_ >: C[C[X]]]] {
  def cast(c: C[T]): N[_ >: C[T]] = c
}

Stack trace

scalac rejects the program:

anietoro@scslt148:~/src/test$ scalac kk2.scala 
kk2.scala:5: error: illegal cyclic reference involving class C
class C[X] extends N[N[_ >: C[C[X]]]] {
                       ^
kk2.scala:6: error: type mismatch;
 found   : C[T]
 required: N[_ >: C[T]]
Note: T <: Any, but class N is invariant in type Z.
You may wish to define Z as +Z instead. (SLS 4.5)
  def cast(c: C[T]): N[_ >: C[T]] = c
                                    ^
two errors found

How I got to this program: this is Example 2 at the bottom of this paper. Both C# and (I guess) Scala implement a check for "expansive cycles" (see Section 9.2 of the CLR spec) that rejects this kind of program.

Does Dotty implement such a check?

@odersky
Copy link
Contributor

odersky commented Jul 16, 2017

Not yet. It would be important to add it, though. If someone volunteers to do it, would be mucg appreciated.

@abeln
Copy link
Contributor Author

abeln commented Jul 16, 2017

@abeln
Copy link
Contributor Author

abeln commented Jul 16, 2017

@odersky do you have any comments/suggestions regarding porting the above code to Dotty? Why is the implementation of the cycle detection under scala/reflect, as opposed to tools/nsc? (I'm not familiar with the scalac code)

@odersky
Copy link
Contributor

odersky commented Jul 20, 2017

@abeln The logic of scalac is split between the nscandreflect.internalpackages. Large parts ofTypesandSymbols` is also needed for implementing reflection that's why they are there. The particular part you look at could probably just as well go into Typer.

In Dotty, the obvious place for putting these checks is in Checking, with a call from Typer.

@abeln
Copy link
Contributor Author

abeln commented Aug 3, 2017

Ok, taking a look at this.

Here's a simpler example (also from the paper) that doesn't use type refinements:

class N[-Y]
class C[X] extends N[N[C[C[X]]]]

class Foo {
  def foo[T](x: C[T]): N[C[T]] = x
}

The sequence of subtype tests is as follows:

C[T] <:? N[C[T]]
N[N[C[C[T]]]] <:? N[C[T]]
C[T] <:? N[C[C[T]]]
N[N[C[C[T]]]] <:? N[C[C[T]]]
C[C[T]] <:? N[C[C[T]]]
... (a cycle: notice the number of Cs has increased by one w.r.t the original test)

abeln added a commit to abeln/dotty that referenced this issue Aug 15, 2017
Expansive cycles characterize situations where the class hierarchy
of a generic class is potentially infinite. This can lead to nontermination
during subtype checks.

This PR implements the algorithm in
Kennedy, Andrew J., and Benjamin C. Pierce. "On decidability of nominal subtyping with variance." (2006).
for detecting (and disallowing) expansive cycles.
@abeln
Copy link
Contributor Author

abeln commented Jul 25, 2018

Closing, since this is the same as #4805

@abeln abeln closed this as completed Jul 25, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants