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

"illegal cyclic reference involving class Array" compiling new Array(0) under -no-specialization #7481

Closed
scabug opened this issue May 15, 2013 · 6 comments · Fixed by scala/scala#10182

Comments

@scabug
Copy link

scabug commented May 15, 2013

 tail test/files/pos/no-spec-array-cycle.*
==> test/files/pos/no-spec-array-cycle.flags <==
-no-specialization
==> test/files/pos/no-spec-array-cycle.scala <==
object Test {
  // val fixesCompile = Array(1, 2, 3)

  private def foo: Any =
    new Array[Byte](0)
}
2.10.x /code/scala2 pt test/files/pos/no-spec-array-cycle.scala

Testing individual files
exception when typing new Array[Byte]/class scala.reflect.internal.Trees$New
illegal cyclic reference involving class Array in file test/files/pos/no-spec-array-cycle.scala
scala.reflect.internal.Symbols$CyclicReference: illegal cyclic reference involving class Array
	at scala.reflect.internal.Symbols$TypeSymbol.tpe(Symbols.scala:2759)
	at scala.reflect.internal.Symbols$Symbol.typeOfThis(Symbols.scala:1743)
	at scala.reflect.internal.Types$ThisType.underlying(Types.scala:1433)
	at scala.reflect.internal.Types$SimpleTypeProxy$class.baseType(Types.scala:248)
	at scala.reflect.internal.Types$SingletonType.baseType(Types.scala:1327)
	at scala.reflect.internal.Types$AsSeenFromMap.toPrefix$1(Types.scala:4547)
	at scala.reflect.internal.Types$AsSeenFromMap.apply(Types.scala:4549)
	at scala.reflect.internal.Types$TypeMap.mapOver(Types.scala:4176)
	at scala.reflect.internal.Types$AsSeenFromMap.apply(Types.scala:4631)
	at scala.reflect.internal.Types$TypeMap.mapOver(Types.scala:4190)
	at scala.reflect.internal.Types$AsSeenFromMap.apply(Types.scala:4631)
	at scala.reflect.internal.Types$Type.asSeenFrom(Types.scala:754)
	at scala.reflect.internal.Types$Type.computeMemberType(Types.scala:788)
	at scala.reflect.internal.Symbols$MethodSymbol.typeAsMemberOf(Symbols.scala:2646)
	at scala.reflect.internal.Types$Type.memberType(Types.scala:779)
	at scala.reflect.internal.Symbols$Symbol.scala$reflect$internal$Symbols$Symbol$$qualifies$1(Symbols.scala:2039)
	at scala.reflect.internal.Symbols$Symbol.matchingSymbol(Symbols.scala:2040)
	at scala.reflect.internal.Symbols$Symbol.overriddenSymbol(Symbols.scala:2054)
	at scala.reflect.internal.Symbols$Symbol$$anonfun$allOverriddenSymbols$1.apply(Symbols.scala:2066)
	at scala.reflect.internal.Symbols$Symbol$$anonfun$allOverriddenSymbols$1.apply(Symbols.scala:2066)
	at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
	at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
	at scala.collection.immutable.List.foreach(List.scala:318)
	at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
	at scala.collection.AbstractTraversable.map(Traversable.scala:105)
	at scala.reflect.internal.Symbols$Symbol.allOverriddenSymbols(Symbols.scala:2066)
	at scala.tools.nsc.transform.SpecializeTypes.scala$tools$nsc$transform$SpecializeTypes$$needsSpecialOverride$1(SpecializeTypes.scala:949)
	at scala.tools.nsc.transform.SpecializeTypes$$anonfun$specialOverrides$3.apply(SpecializeTypes.scala:971)
	at scala.tools.nsc.transform.SpecializeTypes$$anonfun$specialOverrides$3.apply(SpecializeTypes.scala:970)
	at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
	at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
	at scala.collection.immutable.List.foreach(List.scala:318)
	at scala.reflect.internal.Scopes$Scope.foreach(Scopes.scala:315)
	at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:251)
	at scala.reflect.internal.Scopes$Scope.flatMap(Scopes.scala:44)
	at scala.tools.nsc.transform.SpecializeTypes.specialOverrides(SpecializeTypes.scala:970)
	at scala.tools.nsc.transform.SpecializeTypes.transformInfo(SpecializeTypes.scala:1168)
	at scala.tools.nsc.transform.InfoTransform$Phase$$anon$1.transform(InfoTransform.scala:38)
	at scala.reflect.internal.Symbols$Symbol.rawInfo(Symbols.scala:1312)
	at scala.reflect.internal.Symbols$Symbol$$anonfun$unsafeTypeParams$1.apply(Symbols.scala:1468)
	at scala.reflect.internal.Symbols$Symbol$$anonfun$unsafeTypeParams$1.apply(Symbols.scala:1468)
	at scala.reflect.internal.SymbolTable.atPhase(SymbolTable.scala:207)
	at scala.reflect.internal.Symbols$Symbol.unsafeTypeParams(Symbols.scala:1468)
	at scala.reflect.internal.Symbols$TypeSymbol.tpe(Symbols.scala:2768)
	at scala.tools.nsc.typechecker.Typers$Typer.typedNew$1(Typers.scala:4399)
	at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5539)
	at scala.tools.nsc.transform.Erasure$Eraser.typed1(Erasure.scala:840)
	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5604)
	at scala.tools.nsc.typechecker.Typers$Typer.typedQualifier(Typers.scala:5689)
	at scala.tools.nsc.typechecker.Typers$Typer.typedQualifier(Typers.scala:5697)
	at scala.tools.nsc.transform.Erasure$Eraser.adaptMember(Erasure.scala:810)
	at scala.tools.nsc.transform.Erasure$Eraser.typed1(Erasure.scala:840)
	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5604)
	at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$92.apply(Typers.scala:4570)
	at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$92.apply(Typers.scala:4570)
	at scala.tools.nsc.typechecker.Typers$Typer.silent(Typers.scala:728)
	at scala.tools.nsc.typechecker.Typers$Typer.normalTypedApply$1(Typers.scala:4570)
	at scala.tools.nsc.typechecker.Typers$Typer.typedApply$1(Typers.scala:4621)
	at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5526)
	at scala.tools.nsc.transform.Erasure$Eraser.typed1(Erasure.scala:840)
	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5604)
	at scala.tools.nsc.typechecker.Typers$Typer.transformedOrTyped(Typers.scala:5807)
	at scala.tools.nsc.typechecker.Typers$Typer.typedDefDef(Typers.scala:2255)
	at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5531)
	at scala.tools.nsc.transform.Erasure$Eraser.typed1(Erasure.scala:840)
	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5604)
	at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$typedStat$1(Typers.scala:2926)
	at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3030)
	at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3030)
	at scala.collection.immutable.List.loop$1(List.scala:170)
	at scala.collection.immutable.List.mapConserve(List.scala:186)
	at scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:3030)
	at scala.tools.nsc.typechecker.Typers$Typer.typedTemplate(Typers.scala:1919)
	at scala.tools.nsc.typechecker.Typers$Typer.typedClassDef(Typers.scala:1759)
	at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5545)
	at scala.tools.nsc.transform.Erasure$Eraser.typed1(Erasure.scala:840)
	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5604)
	at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$typedStat$1(Typers.scala:2926)
	at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3030)
	at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3030)
	at scala.collection.immutable.List.loop$1(List.scala:170)
	at scala.collection.immutable.List.mapConserve(List.scala:186)
	at scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:3030)
	at scala.tools.nsc.typechecker.Typers$Typer.typedPackageDef$1(Typers.scala:5263)
	at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5549)
	at scala.tools.nsc.transform.Erasure$Eraser.typed1(Erasure.scala:840)
	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5604)
	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5666)
	at scala.tools.nsc.transform.Erasure$ErasureTransformer$$anonfun$transform$2.apply(Erasure.scala:1296)
	at scala.tools.nsc.transform.Erasure$ErasureTransformer$$anonfun$transform$2.apply(Erasure.scala:1292)
	at scala.reflect.internal.SymbolTable.atPhase(SymbolTable.scala:207)
	at scala.reflect.internal.SymbolTable.afterPhase(SymbolTable.scala:216)
	at scala.tools.nsc.Global.afterErasure(Global.scala:1098)
	at scala.tools.nsc.transform.Erasure$ErasureTransformer.transform(Erasure.scala:1292)
	at scala.tools.nsc.transform.Erasure$ErasureTransformer.transform(Erasure.scala:893)
	at scala.tools.nsc.ast.Trees$Transformer.transformUnit(Trees.scala:227)
	at scala.tools.nsc.transform.Transform$Phase.apply(Transform.scala:30)
	at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:464)
	at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:431)
	at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:431)
	at scala.collection.Iterator$class.foreach(Iterator.scala:727)
	at scala.collection.AbstractIterator.foreach(Iterator.scala:1157)
	at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:431)
	at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1583)
	at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1557)
	at scala.tools.nsc.Global$Run.compileSources(Global.scala:1553)
	at scala.tools.nsc.Global$Run.compile(Global.scala:1662)
	at scala.tools.partest.nest.DirectCompiler.compile(CompileManager.scala:143)
	at scala.tools.partest.nest.CompileManager.attemptCompile(CompileManager.scala:163)
	at scala.tools.partest.nest.RunnerManager$Runner$$anonfun$runTestCommon$1.apply(RunnerManager.scala:365)
	at scala.tools.partest.nest.RunnerManager$Runner$$anonfun$runTestCommon$1.apply(RunnerManager.scala:362)
	at scala.tools.partest.nest.RunnerManager$Runner.runInContext(RunnerManager.scala:323)
	at scala.tools.partest.nest.RunnerManager$Runner.runTestCommon(RunnerManager.scala:362)
	at scala.tools.partest.nest.RunnerManager$Runner.processSingleFile(RunnerManager.scala:485)
	at scala.tools.partest.nest.RunnerManager$Runner.run(RunnerManager.scala:805)
	at scala.tools.partest.nest.RunnerManager$$anonfun$29.apply(RunnerManager.scala:837)
	at scala.tools.partest.nest.RunnerManager$$anonfun$29.apply(RunnerManager.scala:837)
	at scala.tools.partest.package$.timed(package.scala:38)
	at scala.tools.partest.nest.RunnerManager.runTest(RunnerManager.scala:837)
	at scala.tools.partest.nest.DirectRunner$$anonfun$2$$anonfun$apply$1.apply(DirectRunner.scala:60)
	at scala.tools.partest.nest.DirectRunner$$anonfun$2$$anonfun$apply$1.apply(DirectRunner.scala:60)
	at scala.tools.partest.package$$anon$1.call(package.scala:44)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:680)
exception when typing new Array[Byte].<arr><init>
exception when typing new Array[Byte].<arr><init>(0)
exception when typing private def foo(): Object = new Array[Byte].<arr><init>(0)
exception when typing object Test extends Object {
  def <init>(): Test.type = {
    Test.super.<init>();
    ()
  };
  private def foo(): Object = new Array[Byte].<arr><init>(0)
}
exception when typing package <empty> {
  object Test extends Object {
    def <init>(): Test.type = {
      Test.super.<init>();
      ()
    };
    private def foo(): Object = new Array[Byte].<arr><init>(0)
  }
}
unhandled exception while transforming no-spec-array-cycle.scala
testing: [...]/files/pos/no-spec-array-cycle.scala                    [FAILED]
1 of 1 tests failed (elapsed time: 00:00:01)

See also:

commit 2e208625a021e52db2e96acc5c3b761c77fc659a
Author: Paul Phillips <paulp@improving.org>
Date:   Sat May 26 10:19:09 2012 -0700

    Remove AnyVal from StringLike parents.

    Otherwise we crash in erasure; there is some kind of
    accidental dependency between the specialization phase and
    value classes, which can be seen in master by trying to
    compile StringOps.scala with -no-specialization.
commit c82bc67737a31f2a639172e677cafdefe8fdbf4e
Author: Jason Zaugg <jzaugg@gmail.com>
Date:   Sat May 26 22:49:12 2012 +0200

    Fix a NSDNHAO in extension methods.

    A bridge method, created when we override a method from
    a superclass and refine the return type, was appearing
    as an overloaded alternative. (`erasure` doesn't create
    new scopes, so the bridges it builds are visible at
    earlier phases.)

    The problem was masked when compiling with specialization,
    which *does* create a new scope, shielding the code in
    question from the artefacts of erasure.

    To fix the problem, we filter out bridge methods from
    the overloaded alternatives returned by `.decl`, as would
    happen internally in `.member`.
@scabug
Copy link
Author

scabug commented May 15, 2013

Imported From: https://issues.scala-lang.org/browse/SI-7481?orig=1
Reporter: @retronym
Affected Versions: 2.10.0

@scabug
Copy link
Author

scabug commented May 15, 2013

@retronym said (edited on May 15, 2013 10:28:12 AM UTC):
During typechecking in Erasure:

  1. typedNew calls <class Array>.tpe, which calls unsafeTypeParams.

  2. unsafeTypeParams runs the specialization info transformer (Array.class is not in this compilation run, so this is expected, even under -no-specialization)

  3. This info transformer computes <method Array#clone>.allOverriddenSymbols

  4. During an AsSeenFrom, <ThisType(Array)>.underlying calls <class Array>.typeOfThis, which final cycles back into <class Array>.tpe

  at scala.reflect.internal.Symbols$CyclicReference.<init>(Symbols.scala:3338)
	  at scala.reflect.internal.Symbols$TypeSymbol.tpe(Symbols.scala:2759)
	  at scala.reflect.internal.Symbols$Symbol.typeOfThis(Symbols.scala:1743)
	  at scala.reflect.internal.Types$ThisType.underlying(Types.scala:1433)
	  at scala.reflect.internal.Types$SimpleTypeProxy$class.baseType(Types.scala:248)
	  at scala.reflect.internal.Types$SingletonType.baseType(Types.scala:1327)
	  at scala.reflect.internal.Types$AsSeenFromMap.toPrefix$1(Types.scala:4547)
	  at scala.reflect.internal.Types$AsSeenFromMap.apply(Types.scala:4549)
	  at scala.reflect.internal.Types$TypeMap.mapOver(Types.scala:4176)
	  at scala.reflect.internal.Types$AsSeenFromMap.apply(Types.scala:4631)
	  at scala.reflect.internal.Types$TypeMap.mapOver(Types.scala:4190)
	  at scala.reflect.internal.Types$AsSeenFromMap.apply(Types.scala:4631)
	  at scala.reflect.internal.Types$Type.asSeenFrom(Types.scala:754)
	  at scala.reflect.internal.Types$Type.computeMemberType(Types.scala:788)
	  at scala.reflect.internal.Symbols$MethodSymbol.typeAsMemberOf(Symbols.scala:2646)
	  at scala.reflect.internal.Types$Type.memberType(Types.scala:779)
	  at scala.reflect.internal.Symbols$Symbol.scala$reflect$internal$Symbols$Symbol$$qualifies$1(Symbols.scala:2039)
	  at scala.reflect.internal.Symbols$Symbol.matchingSymbol(Symbols.scala:2040)
	  at scala.reflect.internal.Symbols$Symbol.overriddenSymbol(Symbols.scala:2054)
	  at scala.reflect.internal.Symbols$Symbol$$anonfun$allOverriddenSymbols$1.apply(Symbols.scala:2066)
	  at scala.reflect.internal.Symbols$Symbol$$anonfun$allOverriddenSymbols$1.apply(Symbols.scala:2066)
	  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
	  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
	  at scala.collection.immutable.List.foreach(List.scala:318)
	  at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
	  at scala.collection.AbstractTraversable.map(Traversable.scala:105)
	  at scala.reflect.internal.Symbols$Symbol.allOverriddenSymbols(Symbols.scala:2066)
	  at scala.tools.nsc.transform.SpecializeTypes.scala$tools$nsc$transform$SpecializeTypes$$needsSpecialOverride$1(SpecializeTypes.scala:949)
	  at scala.tools.nsc.transform.SpecializeTypes$$anonfun$specialOverrides$3.apply(SpecializeTypes.scala:971)
	  at scala.tools.nsc.transform.SpecializeTypes$$anonfun$specialOverrides$3.apply(SpecializeTypes.scala:970)
	  at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
	  at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
	  at scala.collection.immutable.List.foreach(List.scala:318)
	  at scala.reflect.internal.Scopes$Scope.foreach(Scopes.scala:315)
	  at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:251)
	  at scala.reflect.internal.Scopes$Scope.flatMap(Scopes.scala:44)
	  at scala.tools.nsc.transform.SpecializeTypes.specialOverrides(SpecializeTypes.scala:970)
	  at scala.tools.nsc.transform.SpecializeTypes.transformInfo(SpecializeTypes.scala:1168)
	  at scala.tools.nsc.transform.InfoTransform$Phase$$anon$1.transform(InfoTransform.scala:38)
	  at scala.reflect.internal.Symbols$Symbol.rawInfo(Symbols.scala:1312)
	  at scala.reflect.internal.Symbols$Symbol$$anonfun$unsafeTypeParams$1.apply(Symbols.scala:1468)
	  at scala.reflect.internal.Symbols$Symbol$$anonfun$unsafeTypeParams$1.apply(Symbols.scala:1468)
	  at scala.reflect.internal.SymbolTable.atPhase(SymbolTable.scala:207)
	  at scala.reflect.internal.Symbols$Symbol.unsafeTypeParams(Symbols.scala:1468)
	  at scala.reflect.internal.Symbols$TypeSymbol.tpe(Symbols.scala:2768)
	  at scala.tools.nsc.typechecker.Typers$Typer.typedNew$1(Typers.scala:4399)

@scabug
Copy link
Author

scabug commented Oct 15, 2013

@gkossakowski said:
Unassigning and rescheduling to M7 as previous deadline was missed.

@scabug
Copy link
Author

scabug commented Oct 26, 2013

@retronym said:
Demoting priority. Unfortunately -no-specialization is quite a hard configuration for us to support as omitting that phase leads to subtle bugs like this one.

@scabug
Copy link
Author

scabug commented Feb 9, 2014

@retronym said:
This might be relevant:

    private def updateTypeCache() {
      if (tpeCache eq NoType)
        throw CyclicReference(this, typeConstructor)

      if (isInitialized)
        tpePeriod = currentPeriod

      tpeCache = NoType // cycle marker
      val noTypeParams = phase.erasedTypes && this != ArrayClass || unsafeTypeParams.isEmpty
      tpeCache = newTypeRef(
        if (noTypeParams) Nil
        else unsafeTypeParams map (_.typeConstructor)
      )
      // Avoid carrying around different types in tyconCache and tpeCache
      // for monomorphic types.
      if (noTypeParams && tyconCacheNeedsUpdate)
        setTyconCache(tpeCache)
    }

@scabug
Copy link
Author

scabug commented Feb 9, 2014

@retronym said:
Seems like this is really a corner case with Array.

We could either adjust this to skip pack to superaccessors for Array:

    /** The logic approximately boils down to finding the most recent phase
     *  which immediately follows any of parser, namer, typer, or erasure.
     *  In effect that means this will return one of:
     *
     *    - packageobjects (follows namer)
     *    - superaccessors (follows typer)
     *    - posterasure    (follows erasure)
     *    - null
     */
    private def unsafeTypeParamPhase = {
      var ph = phase
      while (ph.prev.keepsTypeParams)
        ph = ph.prev

      ph
    }

and/or hard-code the specialization info transformer to be a no-op for Array.

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