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

recursive type member cause assertion failure #12731

Closed
xuwei-k opened this issue Jun 7, 2021 · 6 comments
Closed

recursive type member cause assertion failure #12731

xuwei-k opened this issue Jun 7, 2021 · 6 comments

Comments

@xuwei-k
Copy link
Contributor

xuwei-k commented Jun 7, 2021

Compiler version

3.0.2-RC1-bin-20210605-f1252d8-NIGHTLY, 3.0.1-RC1, 3.0.0

Minimized code

trait A {
  type B <: A {
    type B <: A.this.B
  }

  def c: B
}

object Main {
  def x: A = null

  def main(args: Array[String]): Unit = {
    x.c.c.c
  }
}

Output (click arrow to expand)

[info] compiling 1 Scala source to /Users/kenji/recursion-type-member-scala-3/target/scala-3.0.2-RC1-bin-20210605-f1252d8-NIGHTLY/classes ...
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure for type bounds [... (caught cyclic reference) ...] <:< type bounds [ <: A{B <: (A{B <: A#B#B} & A#B)#B} & A#B], frozen = true
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure for A{B <: A#B#B} & A#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A{B <: A#B#B} <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A{B <: A#B#B} & A#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A{B <: A#B#B} <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A{B <: A#B#B} & A#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A{B <: A#B#B} <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A{B <: A#B#B} & A#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A{B <: A#B#B} <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A{B <: A#B#B} & A#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A{B <: A#B#B} <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A{B <: A#B#B} & A#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure for A#B#B <:< A{B <: A{B <: A#B#B}#B}, frozen = true
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure for type bounds [... (caught cyclic reference) ...] <:< type bounds [ <: A{B <: (A{B <: A#B#B} & A#B)#B} & A#B], frozen = true
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since java.lang.AssertionError: assertion failed was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[info] assertion failure [[cannot display since dotty.tools.dotc.core.CyclicReference:  was thrown]]
[error] -- Error: /Users/kenji/recursion-type-member-scala-3/A.scala:13:8 --------------
[error] 13 |    x.c.c.c
[error]    |        ^
[error]    |Recursion limit exceeded.
[error]    |Maybe there is an illegal cyclic reference?
[error]    |If that's not the case, you could also try to increase the stacksize using the -Xss JVM option.
[error]    |A recurring operation is (inner to outer):
[error]    |
[error]    |  subtype ... (caught cyclic reference) ... <:< ... (caught cyclic reference) ...
[error]    |  subtype ... (caught cyclic reference) ... <:< ... (caught cyclic reference) ...
[error]    |  subtype ... (caught cyclic reference) ... <:< ... (caught cyclic reference) ...
[error]    |  subtype ... (caught cyclic reference) ... <:< ... (caught cyclic reference) ...
[error]    |  subtype ... (caught cyclic reference) ... <:< ... (caught cyclic reference) ...
[error]    |  subtype ... (caught cyclic reference) ... <:< ... (caught cyclic reference) ...
[error]    |  subtype ... (caught cyclic reference) ... <:< ... (caught cyclic reference) ...
[error]    |  subtype ... (caught cyclic reference) ... <:< ... (caught cyclic reference) ...
[error]    |  subtype ... (caught cyclic reference) ... <:< ... (caught cyclic reference) ...
[error]    |  subtype ... (caught cyclic reference) ... <:< ... (caught cyclic reference) ...
[error]    |  ...
[error]    |
[error]    |  subtype A#B#B <:< A{B <: A{B <: A#B#B}#B}
[error]    |  subtype A{B <: A#B#B} & A#B <:< A{B <: A{B <: A#B#B}#B}
[error]    |  subtype A#B#B <:< A{B <: A{B <: A#B#B}#B}
[error]    |  subtype A{B <: A#B#B} & A#B <:< A{B <: A{B <: A#B#B}#B}
[error]    |  subtype A#B#B <:< A{B <: A{B <: A#B#B}#B}
[error]    |  subtype A{B <: A#B#B} & A#B <:< A{B <: A{B <: A#B#B}#B}
[error]    |  subtype A#B#B <:< A{B <: A{B <: A#B#B}#B}
[error]    |  subtype A{B <: A#B#B} & A#B <:< [cannot display due to assertion failed, raw string = RefinedType(TypeRef(ThisType(TypeRef(NoPrefix,module class <empty>)),trait A),B,TypeBounds(TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Nothing),LazyRef(null)))]
[error]    |  subtype A#B#B <:< ... (caught cyclic reference) ...
[error]    |  subtype (A#B#c : => A#B#B) <:< ?{ c: ? }
[error] one error found

@mkurz
Copy link
Contributor

mkurz commented Aug 27, 2021

Is this something that needs and can be fixed in a 3.0.x release?

@odersky
Copy link
Contributor

odersky commented Aug 27, 2021

It could be fixed in a patch release. The question is who will fix it. I unfortunately won't have the time. F-bounds is an area where Scala 2 and Scala 3 differ quite a bit. Scala 3 has to do more checks and therefore is more likely to fall into cyclic references.

I have advocated elsewhere that F-bounds should be replaced by intersection types. @japgolly has tried that out with positive results.

@odersky odersky removed their assignment Aug 27, 2021
@japgolly
Copy link
Contributor

@japgolly has tried that out with positive results.

Yep! (And thanks again to @odersky 's guidance btw). The issue we're talking about is #13133. You can implement f-bounds using intersection types. It was wary as to whether it would work in Scala 2 where with is non-commutative but my little experiment worked out fine! I think as long as no user of your api is explicitly swapping the order around themselves, if you're consistent in the way your order your A with Bs within your own api then the solution works in Scala 2 just as well as it does in Scala 3! (Not to mention that cross-compilation works too).

@smarter
Copy link
Member

smarter commented Aug 31, 2021

type B <: A.this.B

If you replace this line by:

type B = A.this.B

Then the example works (and I think this preserves the behavior that was intended?)

@smarter
Copy link
Member

smarter commented Aug 31, 2021

I think this preserves the behavior that was intended?

For reference, this is the same pattern that is used in akka-stream (https://github.com/akka/akka/blob/06594e537b453d1f44267598e3014c61a852b48a/akka-stream/src/main/scala/akka/stream/scaladsl/Flow.scala#L789-L794) which we managed to support in scala 3 (after some effort: #9564), so it should be good enough for all your f-bounded type member needs :).

@smarter
Copy link
Member

smarter commented Sep 18, 2021

Closing since I believe #12731 (comment) supports the same usecases and does not require us to further complicate the f-bounds handling in the compiler.

@smarter smarter closed this as completed Sep 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants