Skip to content

Cyclic type error from Java when type argument of superclass references the current class applied to some types #10945

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
Katrix opened this issue Dec 28, 2020 · 2 comments · Fixed by #11471

Comments

@Katrix
Copy link
Contributor

Katrix commented Dec 28, 2020

Minimized code

Java code

public interface Built { 
    interface Builder<A> extends GeneralBuilder<Built, Builder<A>> {}
}

interface GeneralBuilder<R, B extends GeneralBuilder<R, B>> {}

Scala code

def useBuilder[A](builder: Built.Builder[A]): Unit = ???

Note. Mixed compilation seems to not produce the error. To produce it in sbt, I first comment out useBuilder and compile, then uncomment it, and try to compile again.

Output

Cyclic reference involving trait Builder

Expectation

It compiles

@griggt
Copy link
Contributor

griggt commented Dec 28, 2020

Seems related to #10567

@smarter
Copy link
Member

smarter commented Dec 28, 2020

Seems related to #10567

I don't think so, the symptoms are the same but the problem is different (there's many ways to run into cycles!)

The completion printer says:

completing val useBuilder
  completing type A
  completed A in method useBuilder
  completing val builder
    completing type Built$
    completed Built$ in package <empty>
    completing val internal
      completing type internal
      completed internal in package scala.annotation
    completed internal in package scala.annotation
    completing val Built
    completed Built in package <empty>
    completing type Builder
      completing type Builder

and the stack trace is (need -Ydebug and turning on the cyclicErrors printer):

dotty.tools.dotc.core.CyclicReference$.apply(TypeErrors.scala:155)
dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:148)
dotty.tools.dotc.core.Denotations$Denotation.completeInfo$1(Denotations.scala:188)
dotty.tools.dotc.core.Denotations$Denotation.info(Denotations.scala:190)
dotty.tools.dotc.core.SymDenotations$SymDenotation.ensureCompleted(SymDenotations.scala:370)
dotty.tools.dotc.core.SymDenotations$SymDenotation.flags(SymDenotations.scala:65)
dotty.tools.dotc.core.SymDenotations$SymDenotation.isAllOf(SymDenotations.scala:126)
dotty.tools.dotc.core.Types$Type.isArgPrefixOf(Types.scala:297)
dotty.tools.dotc.core.Types$NamedType.fromDesignator$1(Types.scala:2115)
dotty.tools.dotc.core.Types$NamedType.computeDenot(Types.scala:2134)
dotty.tools.dotc.core.Types$NamedType.denot(Types.scala:2089)
dotty.tools.dotc.core.TypeApplications$.safeDealias$extension(TypeApplications.scala:271)
dotty.tools.dotc.core.TypeApplications$.appliedTo$extension(TypeApplications.scala:311)
dotty.tools.dotc.core.classfile.ClassfileParser.processClassType$1(ClassfileParser.scala:382)
dotty.tools.dotc.core.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:392)
dotty.tools.dotc.core.classfile.ClassfileParser.processClassType$1(ClassfileParser.scala:377)
dotty.tools.dotc.core.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:392)
dotty.tools.dotc.core.classfile.ClassfileParser.dotty$tools$dotc$core$classfile$ClassfileParser$$sigToType(ClassfileParser.scala:516)
dotty.tools.dotc.core.classfile.ClassfileParser$AttributeCompleter.complete(ClassfileParser.scala:658)
dotty.tools.dotc.core.classfile.ClassfileParser.parseClass(ClassfileParser.scala:190)
dotty.tools.dotc.core.classfile.ClassfileParser.run$$anonfun$1(ClassfileParser.scala:87)
dotty.tools.dotc.core.classfile.ClassfileParser.run(ClassfileParser.scala:82)
dotty.tools.dotc.core.ClassfileLoader.load(SymbolLoaders.scala:414)
dotty.tools.dotc.core.ClassfileLoader.doComplete(SymbolLoaders.scala:409)
dotty.tools.dotc.core.SymbolLoader.complete(SymbolLoaders.scala:343)
dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:152)
dotty.tools.dotc.core.SymDenotations$SymDenotation.completeOnce(SymDenotations.scala:362)
dotty.tools.dotc.core.SymDenotations$SymDenotation.isAbsent(SymDenotations.scala:571)
dotty.tools.dotc.core.SymDenotations$SymDenotation.isAccessibleFrom(SymDenotations.scala:864)
dotty.tools.dotc.typer.ProtoTypes$SelectionProto.qualifies$1(ProtoTypes.scala:183)
dotty.tools.dotc.typer.ProtoTypes$SelectionProto.isMatchedBy(ProtoTypes.scala:190)
dotty.tools.dotc.core.TypeComparer.isMatchedByProto(TypeComparer.scala:1789)
dotty.tools.dotc.core.TypeComparer.firstTry$1(TypeComparer.scala:297)
dotty.tools.dotc.core.TypeComparer.recur(TypeComparer.scala:1264)
dotty.tools.dotc.core.TypeComparer.isSubType(TypeComparer.scala:177)
dotty.tools.dotc.core.TypeComparer.isSubType(TypeComparer.scala:187)
dotty.tools.dotc.core.TypeComparer.topLevelSubType(TypeComparer.scala:128)
dotty.tools.dotc.core.TypeComparer.testSubType(TypeComparer.scala:144)
dotty.tools.dotc.core.TypeComparer$.testSubType(TypeComparer.scala:2616)
dotty.tools.dotc.typer.Typer.adaptNoArgsOther$4(Typer.scala:3314)
dotty.tools.dotc.typer.Typer.adaptNoArgs$1(Typer.scala:3394)
dotty.tools.dotc.typer.Typer.adapt1(Typer.scala:3653)
dotty.tools.dotc.typer.Typer.adapt(Typer.scala:2939)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2662)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2666)
dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:2782)
dotty.tools.dotc.typer.Typer.typeSelectOnTerm$1(Typer.scala:575)
dotty.tools.dotc.typer.Typer.typedSelect(Typer.scala:600)
dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2501)
dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2592)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2662)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2666)
dotty.tools.dotc.typer.Typer.typedAppliedTypeTree(Typer.scala:1748)
dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2557)
dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2593)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2662)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2666)
dotty.tools.dotc.typer.Namer.typedAheadType$$anonfun$1(Namer.scala:1266)
dotty.tools.dotc.typer.Namer.typedAhead(Namer.scala:1258)
dotty.tools.dotc.typer.Namer.typedAheadType(Namer.scala:1266)
dotty.tools.dotc.typer.Namer.valOrDefDefSig(Namer.scala:1470)
dotty.tools.dotc.typer.Namer$Completer.typeSig(Namer.scala:700)
dotty.tools.dotc.typer.Namer$Completer.completeInCreationContext(Namer.scala:821)
dotty.tools.dotc.typer.Namer$Completer.complete(Namer.scala:732)
dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:152)
dotty.tools.dotc.core.Denotations$Denotation.completeInfo$1(Denotations.scala:188)
dotty.tools.dotc.core.Denotations$Denotation.info(Denotations.scala:190)
dotty.tools.dotc.core.SymDenotations$SymDenotation.ensureCompleted(SymDenotations.scala:370)
dotty.tools.dotc.typer.Typer.retrieveSym(Typer.scala:2473)
dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2498)
dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2592)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2662)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2666)
dotty.tools.dotc.typer.Namer.typedAheadExpr$$anonfun$1(Namer.scala:1271)
dotty.tools.dotc.typer.Namer.typedAhead(Namer.scala:1258)
dotty.tools.dotc.typer.Namer.typedAheadExpr(Namer.scala:1271)
dotty.tools.dotc.typer.Namer.completeParams$$anonfun$1(Namer.scala:1287)
scala.collection.immutable.List.foreach(List.scala:333)
dotty.tools.dotc.typer.Namer.completeParams(Namer.scala:1287)
dotty.tools.dotc.typer.Namer.defDefSig$$anonfun$3(Namer.scala:1509)
scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
scala.collection.immutable.List.foreach(List.scala:333)
dotty.tools.dotc.typer.Namer.defDefSig(Namer.scala:1509)
dotty.tools.dotc.typer.Namer$Completer.typeSig(Namer.scala:704)
dotty.tools.dotc.typer.Namer$Completer.completeInCreationContext(Namer.scala:821)
dotty.tools.dotc.typer.Namer$Completer.complete(Namer.scala:732)
dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:152)
dotty.tools.dotc.core.Denotations$Denotation.completeInfo$1(Denotations.scala:188)
dotty.tools.dotc.core.Denotations$Denotation.info(Denotations.scala:190)
dotty.tools.dotc.core.SymDenotations$SymDenotation.ensureCompleted(SymDenotations.scala:370)
dotty.tools.dotc.typer.Typer.retrieveSym(Typer.scala:2473)
dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2498)
dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2592)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2662)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2666)
dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2688)
dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2738)
dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:2181)
dotty.tools.dotc.typer.Typer.typedTypeOrClassDef$2(Typer.scala:2519)
dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2523)
dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2592)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2662)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2666)
dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2688)
dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2738)
dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:2316)
dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2564)
dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2593)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2662)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2666)
dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:2782)
dotty.tools.dotc.typer.FrontEnd.liftedTree1$1(FrontEnd.scala:79)
dotty.tools.dotc.typer.FrontEnd.typeCheck$$anonfun$1(FrontEnd.scala:84)
dotty.tools.dotc.typer.FrontEnd.monitor(FrontEnd.scala:43)
dotty.tools.dotc.typer.FrontEnd.typeCheck(FrontEnd.scala:85)
dotty.tools.dotc.typer.FrontEnd.runOn$$anonfun$3(FrontEnd.scala:120)
scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
scala.collection.immutable.List.foreach(List.scala:333)
dotty.tools.dotc.typer.FrontEnd.runOn(FrontEnd.scala:120)
dotty.tools.dotc.Run.runPhases$4$$anonfun$4(Run.scala:185)
scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
dotty.tools.dotc.Run.runPhases$5(Run.scala:195)
dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:203)
scala.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:67)
dotty.tools.dotc.Run.compileUnits(Run.scala:210)
dotty.tools.dotc.Run.compileSources(Run.scala:146)
dotty.tools.dotc.Run.compile(Run.scala:130)
dotty.tools.dotc.Driver.doCompile(Driver.scala:39)
dotty.tools.dotc.Driver.process(Driver.scala:186)
dotty.tools.dotc.Driver.process(Driver.scala:155)
dotty.tools.dotc.Driver.process(Driver.scala:167)
dotty.tools.dotc.Driver.main(Driver.scala:194)
dotty.tools.dotc.Main.main(Main.scala)

I think the issue here is that we call appliedTo in the ClassfileParser:
https://github.com/lampepfl/dotty/blob/029ae77b95e0219cb9477582e1d98e7e520a3d38/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala#L382
appliedTo ends up calling safeDealias which runs into a cycle trying to complete the denotation of the class we're currently unpickling. But since we're dealing with plain Java classes, we don't need to use appliedTo since there's nothing to dealias and no higher-kinded type to reduce, we can directly construct an AppliedType node:

--- compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
+++ compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
@@ -379,7 +379,7 @@ class ClassfileParser(
                   if (argsBuf != null) argsBuf += arg
                 }
                 accept('>')
-                if (skiptvs) tp else tp.appliedTo(argsBuf.toList)
+                if (skiptvs) tp else AppliedType(tp, argsBuf.toList)
               }
               else tp
             case tp =>

@smarter smarter changed the title Cyclic type error from Java Cyclic type error from Java when type argument of superclass references the current class applied to some types Dec 28, 2020
smarter added a commit to smarter/dotty that referenced this issue Dec 28, 2020
liufengyun added a commit to dotty-staging/dotty that referenced this issue Feb 19, 2021
dotbg pushed a commit to dotbg/dotty that referenced this issue Feb 24, 2021
@Kordyjan Kordyjan added this to the 3.0.0 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants