Skip to content

CyclicReference exception when working with toExprOfList in context of Reflection #6765

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
anatoliykmetyuk opened this issue Jun 28, 2019 · 2 comments
Assignees

Comments

@anatoliykmetyuk
Copy link
Contributor

anatoliykmetyuk commented Jun 28, 2019

minimized code

Macro:

import scala.quoted._
import delegate scala.quoted._
import scala.tasty._

delegate for Toolbox = Toolbox.make(getClass.getClassLoader)

inline def crash = ${crashImpl}
def crashImpl given (refl: Reflection) = {
  import refl._  // Works if commented out
  val res = List('{"One"}).toExprOfList  // Works if replaced with '{"One" :: Nil}
  println(res.show)  // Works if commented out
  res
}

Usage:

object Main {
  def main(args: Array[String]): Unit = {
    val res = crash  // Works if these two lines are commented out at the same time
    println(res)     // Works if these two lines are commented out at the same time
    
    println(crash)
  }
}

If as much as one of the four pointed out comments is applied, the code works.

Stack trace
[error] -- Error: /Users/anatolii/Projects/dotty/playground/core/src/main/scala/playground/Main.scala:35:14
[error] 35 |    val res = crash
[error]    |              ^^^^^
[error]    |An exception occurred while executing macro expansion
[error]    |
[error]    |dotty.tools.dotc.core.CyclicReference:
[error]    |	at dotty.tools.dotc.core.CyclicReference$.apply(TypeErrors.scala:157)
[error]    |	at dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:237)
[error]    |	at dotty.tools.dotc.core.Denotations$Denotation.completeInfo$1(Denotations.scala:180)
[error]    |	at dotty.tools.dotc.core.Denotations$Denotation.info(Denotations.scala:182)
[error]    |	at dotty.tools.dotc.core.SymDenotations$SymDenotation.ensureCompleted(SymDenotations.scala:345)
[error]    |	at dotty.tools.dotc.core.SymDenotations$SymDenotation.flags(SymDenotations.scala:150)
[error]    |	at dotty.tools.dotc.tastyreflect.KernelImpl.Symbol_flags(KernelImpl.scala:1476)
[error]    |	at dotty.tools.dotc.tastyreflect.KernelImpl.Symbol_flags(KernelImpl.scala:1476)
[error]    |	at scala.tasty.reflect.SymbolOps$SymbolAPI.flags(SymbolOps.scala:15)
[error]    |	at scala.tasty.reflect.Printers$SourceCodePrinter$Buffer.printType(Printers.scala:1506)
[error]    |	at scala.tasty.reflect.Printers$SourceCodePrinter$Buffer.printTypeAndAnnots$1(Printers.scala:1412)
[error]    |	at scala.tasty.reflect.Printers$SourceCodePrinter$Buffer.printTypeTree(Printers.scala:1414)
[error]    |	at scala.tasty.reflect.Printers$SourceCodePrinter$Buffer.printTree(Printers.scala:703)
[error]    |	at scala.tasty.reflect.Printers$SourceCodePrinter$Buffer.printSeparated$2(Printers.scala:1045)
[error]    |	at scala.tasty.reflect.Printers$SourceCodePrinter$Buffer.printStats(Printers.scala:1051)
[error]    |	at scala.tasty.reflect.Printers$SourceCodePrinter$Buffer.printFlatBlock$$anonfun$1(Printers.scala:1014)
[error]    |	at dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error]    |	at scala.tasty.reflect.Printers$SourceCodePrinter$Buffer.indented(Printers.scala:502)
[error]    |	at scala.tasty.reflect.Printers$SourceCodePrinter$Buffer.printFlatBlock(Printers.scala:1015)
[error]    |	at scala.tasty.reflect.Printers$SourceCodePrinter$Buffer.printTree(Printers.scala:893)
[error]    |	at scala.tasty.reflect.Printers$SourceCodePrinter.showTree(Printers.scala:443)
[error]    |	at scala.tasty.reflect.Printers$TreeShowDeco.show(Printers.scala:30)
[error]    |	at scala.tasty.reflect.QuotedOps$QuotedExprAPI.show(QuotedOps.scala:17)
[error]    |	at playground.macros$.crashImpl(macros.scala:41)
[error]    |	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error]    |	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error]    |	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error]    |	at java.lang.reflect.Method.invoke(Method.java:498)
[error]    |	at dotty.tools.dotc.transform.Splicer$Interpreter.interpretStaticMethodCall$$anonfun$1(Splicer.scala:135)
[error]    |	at dotty.tools.dotc.transform.Splicer$Interpreter.stopIfRuntimeException(Splicer.scala:188)
[error]    |	at dotty.tools.dotc.transform.Splicer$Interpreter.interpretStaticMethodCall(Splicer.scala:135)
[error]    |	at dotty.tools.dotc.transform.Splicer$AbstractInterpreter.interpretTree(Splicer.scala:343)
[error]    |	at dotty.tools.dotc.transform.Splicer$Interpreter.interpret(Splicer.scala:90)
[error]    |	at dotty.tools.dotc.transform.Splicer$.splice(Splicer.scala:44)
[error]    |	at dotty.tools.dotc.typer.Inliner.dotty$tools$dotc$typer$Inliner$$expandMacro(Inliner.scala:1160)
[error]    |	at dotty.tools.dotc.typer.Inliner$InlineTyper.typedApply(Inliner.scala:1000)
[error]    |	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2151)
[error]    |	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2205)
[error]    |	at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:124)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2239)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2237)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2251)
[error]    |	at dotty.tools.dotc.typer.Inliner.inlined(Inliner.scala:512)
[error]    |	at dotty.tools.dotc.typer.Inliner$.inlineCall(Inliner.scala:109)
[error]    |	at dotty.tools.dotc.typer.Typer.adaptNoArgsOther$6(Typer.scala:2821)
[error]    |	at dotty.tools.dotc.typer.Typer.adaptNoArgs$1(Typer.scala:2918)
[error]    |	at dotty.tools.dotc.typer.Typer.adapt1(Typer.scala:3127)
[error]    |	at dotty.tools.dotc.typer.Typer.adapt(Typer.scala:2539)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2239)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2251)
[error]    |	at dotty.tools.dotc.typer.Namer.typedAheadExpr$$anonfun$1(Namer.scala:1173)
[error]    |	at dotty.tools.dotc.typer.Namer.typedAhead(Namer.scala:1163)
[error]    |	at dotty.tools.dotc.typer.Namer.typedAheadExpr(Namer.scala:1173)
[error]    |	at dotty.tools.dotc.typer.Namer.rhsType$2(Namer.scala:1308)
[error]    |	at dotty.tools.dotc.typer.Namer.cookedRhsType$1(Namer.scala:1320)
[error]    |	at dotty.tools.dotc.typer.Namer.lhsType$1(Namer.scala:1321)
[error]    |	at dotty.tools.dotc.typer.Namer.inferredType$1(Namer.scala:1339)
[error]    |	at dotty.tools.dotc.typer.Namer.valOrDefDefSig(Namer.scala:1347)
[error]    |	at dotty.tools.dotc.typer.Namer$Completer.typeSig(Namer.scala:756)
[error]    |	at dotty.tools.dotc.typer.Namer$Completer.completeInCreationContext(Namer.scala:873)
[error]    |	at dotty.tools.dotc.typer.Namer$Completer.complete(Namer.scala:786)
[error]    |	at dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:239)
[error]    |	at dotty.tools.dotc.core.Denotations$Denotation.completeInfo$1(Denotations.scala:180)
[error]    |	at dotty.tools.dotc.core.Denotations$Denotation.info(Denotations.scala:182)
[error]    |	at dotty.tools.dotc.core.SymDenotations$SymDenotation.ensureCompleted(SymDenotations.scala:345)
[error]    |	at dotty.tools.dotc.typer.Typer.retrieveSym(Typer.scala:2103)
[error]    |	at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2128)
[error]    |	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2204)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2239)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2251)
[error]    |	at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2270)
[error]    |	at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2316)
[error]    |	at dotty.tools.dotc.typer.Typer.typedBlockStats(Typer.scala:711)
[error]    |	at dotty.tools.dotc.typer.Typer.typedBlock(Typer.scala:714)
[error]    |	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2158)
[error]    |	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2205)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2239)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2251)
[error]    |	at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:2329)
[error]    |	at dotty.tools.dotc.typer.Typer.typedDefDef(Typer.scala:1549)
[error]    |	at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2138)
[error]    |	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2204)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2239)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2251)
[error]    |	at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2270)
[error]    |	at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2316)
[error]    |	at dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:1678)
[error]    |	at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2141)
[error]    |	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2204)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2239)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2251)
[error]    |	at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2270)
[error]    |	at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2316)
[error]    |	at dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:1802)
[error]    |	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2181)
[error]    |	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2205)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2239)
[error]    |	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2251)
[error]    |	at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:2329)
[error]    |	at dotty.tools.dotc.typer.FrontEnd.typeCheck$$anonfun$1(FrontEnd.scala:75)
[error]    |	at dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error]    |	at dotty.tools.dotc.typer.FrontEnd.monitor(FrontEnd.scala:41)
[error]    |	at dotty.tools.dotc.typer.FrontEnd.typeCheck(FrontEnd.scala:79)
[error]    |	at dotty.tools.dotc.typer.FrontEnd.runOn$$anonfun$3(FrontEnd.scala:109)
[error]    |	at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error]    |	at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error]    |	at scala.collection.immutable.List.foreach(List.scala:392)
[error]    |	at dotty.tools.dotc.typer.FrontEnd.runOn(FrontEnd.scala:109)
[error]    |	at dotty.tools.dotc.Run.runPhases$4$$anonfun$4(Run.scala:158)
[error]    |	at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error]    |	at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error]    |	at scala.collection.IndexedSeqOptimized.foreach(IndexedSeqOptimized.scala:36)
[error]    |	at scala.collection.IndexedSeqOptimized.foreach$(IndexedSeqOptimized.scala:33)
[error]    |	at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:198)
[error]    |	at dotty.tools.dotc.Run.runPhases$5(Run.scala:170)
[error]    |	at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:178)
[error]    |	at dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error]    |	at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:102)
[error]    |	at dotty.tools.dotc.Run.compileUnits(Run.scala:185)
[error]    |	at dotty.tools.dotc.Run.compileSources(Run.scala:120)
[error]    |	at dotty.tools.dotc.Run.compile(Run.scala:104)
[error]    |	at dotty.tools.dotc.Driver.doCompile(Driver.scala:34)
[error]    |	at dotty.tools.dotc.Driver.process(Driver.scala:172)
[error]    |	at dotty.tools.dotc.Main.process(Main.scala)
[error]    |	at xsbt.CachedCompilerImpl.run(CachedCompilerImpl.java:69)
[error]    |	at xsbt.CompilerInterface.run(CompilerInterface.java:41)
[error]    |	at sun.reflect.GeneratedMethodAccessor14.invoke(Unknown Source)
[error]    |	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error]    |	at java.lang.reflect.Method.invoke(Method.java:498)
[error]    |	at sbt.internal.inc.AnalyzingCompiler.call(AnalyzingCompiler.scala:237)
[error]    |	at sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:111)
[error]    |	at sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:90)
[error]    |	at sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$3(MixedAnalyzingCompiler.scala:82)
[error]    |	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error]    |	at sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:133)
[error]    |	at sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:73)
[error]    |	at sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:116)
[error]    |	at sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:307)
[error]    |	at sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:307)
[error]    |	at sbt.internal.inc.Incremental$.doCompile(Incremental.scala:106)
[error]    |	at sbt.internal.inc.Incremental$.$anonfun$compile$4(Incremental.scala:87)
[error]    |	at sbt.internal.inc.IncrementalCommon.recompileClasses(IncrementalCommon.scala:116)
[error]    |	at sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:63)
[error]    |	at sbt.internal.inc.Incremental$.$anonfun$compile$3(Incremental.scala:89)
[error]    |	at sbt.internal.inc.Incremental$.manageClassfiles(Incremental.scala:134)
[error]    |	at sbt.internal.inc.Incremental$.compile(Incremental.scala:80)
[error]    |	at sbt.internal.inc.IncrementalCompile$.apply(Compile.scala:67)
[error]    |	at sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:311)
[error]    |	at sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:269)
[error]    |	at sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:159)
[error]    |	at sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:238)
[error]    |	at sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:69)
[error]    |	at sbt.Defaults$.compileIncrementalTaskImpl(Defaults.scala:1549)
[error]    |	at sbt.Defaults$.$anonfun$compileIncrementalTask$1(Defaults.scala:1523)
[error]    |	at scala.Function1.$anonfun$compose$1(Function1.scala:44)
[error]    |	at sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:40)
[error]    |	at sbt.std.Transform$$anon$4.work(System.scala:67)
[error]    |	at sbt.Execute.$anonfun$submit$2(Execute.scala:269)
[error]    |	at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
[error]    |	at sbt.Execute.work(Execute.scala:278)
[error]    |	at sbt.Execute.$anonfun$submit$1(Execute.scala:269)
[error]    |	at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:178)
[error]    |	at sbt.CompletionService$$anon$2.call(CompletionService.scala:37)
[error]    |	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error]    |	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[error]    |	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error]    |	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
[error]    |	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
[error]    |	at java.lang.Thread.run(Thread.java:745)
[error]    |
[error]    | This location is in code that was inlined at Main.scala:35
@anatoliykmetyuk
Copy link
Contributor Author

Worth noting that List('{"One"}, '{"Two"}).toExprOfList desugars to:

{
  type x$1$_$1
  val x$2: x$1$_$1 = "One"
  {
    type x$1$_$1
    val x$2: x$1$_$1 = "Two"
    scala.Nil.::[x$1$_$1](x$2)
  }.::[x$1$_$1](x$2)
}

Which is not a Scala code that would typecheck. If you try to execute it as is:

[error] -- [E007] Type Mismatch Error: /Users/anatolii/Projects/dotty/playground/core/src/main/scala/playground/Main.scala:42:27
[error] 42 |        val x$2: x$1$_$1 = "Two"
[error]    |                           ^^^^^
[error]    |                           Found:    String("Two")
[error]    |                           Required: x$1$_$1
[error] -- [E007] Type Mismatch Error: /Users/anatolii/Projects/dotty/playground/core/src/main/scala/playground/Main.scala:43:29
[error] 43 |        scala.Nil.::[x$1$_$1](x$2)
[error]    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |        Found:    List[x$1$_$1]
[error]    |        Required: Int

As to toExprOfList, it is currently defined as:

def (list: List[Expr[T]]) toExprOfList[T] given Type[T]: Expr[List[T]] = list match {
  case x :: xs  => '{ $x :: ${xs.toExprOfList} }
  case Nil => '{ Nil }
}

I believe given Type[T] is an issue here: before encountering this standard function, I tried to implement a similar function on my own:

def flattenExpr[T](exs: List[Expr[T]]) given (tt: Type[T]): Expr[List[T]] =
  exs.foldRight('{Nil: List[$tt]}) { (next, accum) => '{$next :: $accum} }

Bug-wise, it behaves the same way as toExprOfList. However, if you make a non-generic version of it:

def flattenExprStr(exs: List[Expr[String]]): Expr[List[String]] =
  exs.foldRight('{Nil: List[String]}) { (next, accum) => '{$next :: $accum} }

And call it as:

inline def crash = ${crashImpl}
def crashImpl given (refl: Reflection) = {
  import refl._
  // val res = List('{"One"}).toExprOfList
  val res = flattenExprStr(List('{"One"}))
  println(res.show)
  res
}

All works well. This one also works:

def flattenExprStr2(exs: List[Expr[String]]): Expr[List[String]] = {
  val tpe = the[Type[String]]
  exs.foldRight('{Nil: List[${tpe}]}) { (next, accum) => '{$next :: $accum} }
}

However, this one:

def flattenExprStr3(exs: List[Expr[String]]): Expr[List[String]] =
  exs.foldRight('{Nil: List[${the[Type[String]]}]}) { (next, accum) => '{$next :: $accum} }

Says:

[error] -- Error: /Users/anatolii/Projects/dotty/playground/macros/src/main/scala/playground/macros.scala:49:32
[error] 49 |    exs.foldRight('{Nil: List[${the[Type[String]]}]}) { (next, accum) => '{$next :: $accum} }
[error]    |                                ^^^^^^^^^^^^^^^^^
[error]    |                                quoted.Type[String] is not stable

nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jul 1, 2019
@nicolasstucki
Copy link
Contributor

This was fixed in #6700

nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jul 1, 2019
anatoliykmetyuk added a commit that referenced this issue Jul 1, 2019
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

2 participants