Open Katrix opened 2 years ago
It turns out that opaque types are not necessary to reproduce this. And with a bit of simplification and reorganization, we can show this is purely a separate compilation (pickling) issue:
fileA_1.scala
class DiscordRecord[Obj]
trait DiscordRecordCompanion[AbsStructural[A], Supertypes] {
type R = AbsStructural[this.type] & Supertypes
}
type ChannelR[Obj] = DiscordRecord[Obj]
type Channel = Channel.R
object Channel extends DiscordRecordCompanion[ChannelR, Any]
type GuildChannelR[Obj] = ChannelR[Obj] {
val id: SnowflakeType[GuildChannel]
}
type GuildChannel = GuildChannel.R
object GuildChannel extends DiscordRecordCompanion[GuildChannelR, Channel]
type TopLevelGuildChannelR[Obj] = GuildChannelR[Obj]
type TopLevelGuildChannel = TopLevelGuildChannel.R
object TopLevelGuildChannel extends DiscordRecordCompanion[TopLevelGuildChannelR, GuildChannel]
type SnowflakeType[A] = Long
fileB_2.scala
//def bar: GuildChannel = ??? // problem goes away if this is uncommented
def foo: TopLevelGuildChannel = ???
val ev = summon[GuildChannel <:< Channel]
// joint compilation succeeds
$ scalac -3.1.0 fileA_1.scala fileB_2.scala
// separate compilation fails
$ scalac -3.1.0 fileA_1.scala && scalac -3.1.0 fileB_2.scala
-- Error: fileB_2.scala:3:41 ---------------------------------------------------
3 |val ev = summon[GuildChannel <:< Channel]
| ^
| Cannot prove that GuildChannel <:< Channel.
Since #14884, we get an additional error which may help shed some light:
$ scalac -3.head fileA_1.scala && scalac -3.head fileB_2.scala
-- Error: fileB_2.scala:2:9 ----------------------------------------------------
2 |def foo: TopLevelGuildChannel = ???
| ^
|Could not read definition of type TopLevelGuildChannel in ./fileA_1$package.class
|An exception was encountered:
| dotty.tools.dotc.core.TypeError: Could not read definition of type TopLevelGuildChannelR in ./fileA_1$package.class
|An exception was encountered:
| dotty.tools.dotc.core.TypeError: Could not read definition of type GuildChannelR in ./fileA_1$package.class
|An exception was encountered:
| dotty.tools.dotc.core.TypeError: Could not read definition of type GuildChannel in ./fileA_1$package.class
|An exception was encountered:
| dotty.tools.dotc.core.CyclicReference:
|Run with -Ydebug-unpickling to see full stack trace.
|Run with -Ydebug-unpickling to see full stack trace.
|Run with -Ydebug-unpickling to see full stack trace.
|Run with -Ydebug-unpickling to see full stack trace.
-- Error: fileB_2.scala:3:41 ---------------------------------------------------
3 |val ev = summon[GuildChannel <:< Channel]
| ^
| Cannot prove that GuildChannel <:< Channel.
2 errors found
Interestingly, compiling with -Ydebug-unpickling
does not show the full stack trace as suggested, but instead just suppresses the error; the re-thrown CyclicReference exception ends up swallowed here: https://github.com/lampepfl/dotty/blob/1a4db8910e0c808d7323796efcd610a050dd70bb/compiler/src/dotty/tools/dotc/typer/Checking.scala#L328-L332
Compiling with -Ylog:all -Ydebug -Ydebug-unpickling
shows
[log parser] cycle detected for GuildChannel, false, false
Turning on the completion printer we see
completing type TopLevelGuildChannel
completing val TopLevelGuildChannel
completed TopLevelGuildChannel in package object fileA_1$package
completing type TopLevelGuildChannel
completing type DiscordRecordCompanion
completed DiscordRecordCompanion in package <empty>
completed TopLevelGuildChannel in package object fileA_1$package
completing type DiscordRecordCompanion
completed DiscordRecordCompanion in package <empty>
completing type R
completed R in trait DiscordRecordCompanion
completing type TopLevelGuildChannelR
completing type GuildChannelR
completing type ChannelR
completing type DiscordRecord
completed DiscordRecord in package <empty>
completing type DiscordRecord
completed DiscordRecord in package <empty>
completed ChannelR in package object fileA_1$package
completing type SnowflakeType
completed SnowflakeType in package object fileA_1$package
completing val fileA_1$package
completed fileA_1$package in package <empty>
completing type GuildChannel
completing val GuildChannel
completed GuildChannel in package object fileA_1$package
completing type GuildChannel
completed GuildChannel in package object fileA_1$package
completing type GuildChannelR
completed GuildChannel in package object fileA_1$package
completed GuildChannelR in package object fileA_1$package
completed TopLevelGuildChannelR in package object fileA_1$package
completed TopLevelGuildChannel in package object fileA_1$package
-- Error: tests/pos/i13904/fileB_2.scala:2:9 -----------------------------------
2 |def foo: TopLevelGuildChannel = ???
| ^
|Could not read definition of type TopLevelGuildChannel in ./fileA_1$package.class
|An exception was encountered:
| dotty.tools.dotc.core.TypeError: Could not read definition of type TopLevelGuildChannelR in ./fileA_1$package.class
|An exception was encountered:
| dotty.tools.dotc.core.TypeError: Could not read definition of type GuildChannelR in ./fileA_1$package.class
|An exception was encountered:
| dotty.tools.dotc.core.TypeError: Could not read definition of type GuildChannel in ./fileA_1$package.class
|An exception was encountered:
| dotty.tools.dotc.core.CyclicReference:
Uncommenting the definition of bar
in fileB_2.scala
causes GuildChannel
to be completed earlier and avoids the CyclicReference error.
Compiler version
3.1.0
This feels very much like #13190, except it has a few more moving parts I haven't been able to remove while minimizing it.
Minimized code
Steps to reproduce
ev2
infileB.scala
ev1
andev2
Output
Expectation
It should compile in both cases, also when using incremental compilation.