scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.89k stars 1.06k forks source link

Compiler fails in generic inline method that uses macro with 'safe-init' #21176

Open st33v3 opened 4 months ago

st33v3 commented 4 months ago

Compiler version

compiler version: version 3.4.2 settings: -Ysafe-init true

Minimized code

class Macro:
    def tuple[T](name: String): (String, List[T]) = (name, List[T]())
    inline def nameTuple[T]: (String, List[T]) = tuple(Macro.named)

object Macro:
    def namedMacro(using q: Quotes): Expr[String] = 
        Expr("test")

    inline def named: String = ${Macro.namedMacro}

// In another file

class Test extends Macro:
    val abc = nameTuple[Int]

@main
def run(): Unit =
    println(new Test().abc)

Output (click arrow to expand)

``` Exception while compiling /home/stepan/macro-test/src/test/Macro.scala, /home/stepan/macro-test/src/test/Test.scala An unhandled exception was thrown in the compiler. Please file a crash report here: https://github.com/scala/scala3/issues/new/choose For non-enriched exceptions, compile with -Yno-enrich-error-messages. while compiling: during phase: parser mode: Mode() library version: version 2.13.12 compiler version: version 3.4.2 settings: -Ysafe-init true -bootclasspath /home/stepan/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar -classpath /home/stepan/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.4.2/scala3-library_3-3.4.2.jar:/home/stepan/macro-test/compile-resources:/home/stepan/macro-test/out/compile.dest/classes -d /home/stepan/macro-test/out/compile.dest/classes [error] ## Exception when compiling 2 sources to /home/stepan/macro-test/out/compile.dest/classes [error] scala.MatchError: PolyType(List(T1, T2), List(TypeBounds(TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Nothing),TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Any)), TypeBounds(TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Nothing),TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Any))), MethodType(List(_1, _2), List(TypeParamRef(T1), TypeParamRef(T2)), AppliedType(TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Tuple2),List(TypeParamRef(T1), TypeParamRef(T2))))) (of class dotty.tools.dotc.core.Types$PolyType) [error] dotty.tools.dotc.transform.init.Util$Call$.unapply(Util.scala:44) [error] dotty.tools.dotc.transform.init.Util$NewExpr$.unapply(Util.scala:64) [error] dotty.tools.dotc.transform.init.Semantic$.cases(Semantic.scala:1215) [error] dotty.tools.dotc.transform.init.Semantic$.eval$$anonfun$1(Semantic.scala:1175) [error] dotty.tools.dotc.transform.init.Cache.cachedEval(Cache.scala:126) [error] dotty.tools.dotc.transform.init.Semantic$.eval(Semantic.scala:1175) [error] dotty.tools.dotc.transform.init.Semantic$.$anonfun$10(Semantic.scala:704) [error] dotty.tools.dotc.transform.init.Semantic$.call(Semantic.scala:703) [error] dotty.tools.dotc.transform.init.Semantic$.$anonfun$44(Semantic.scala:1253) [error] dotty.tools.dotc.transform.init.Semantic$.cases(Semantic.scala:1253) [error] dotty.tools.dotc.transform.init.Semantic$.eval$$anonfun$1(Semantic.scala:1175) [error] dotty.tools.dotc.transform.init.Cache.cachedEval(Cache.scala:112) [error] dotty.tools.dotc.transform.init.Semantic$.eval(Semantic.scala:1175) [error] dotty.tools.dotc.transform.init.Semantic$.cases(Semantic.scala:1294) [error] dotty.tools.dotc.transform.init.Semantic$.eval$$anonfun$1(Semantic.scala:1175) [error] dotty.tools.dotc.transform.init.Cache.cachedEval(Cache.scala:112) [error] dotty.tools.dotc.transform.init.Semantic$.eval(Semantic.scala:1175) [error] dotty.tools.dotc.transform.init.Semantic$.$anonfun$55(Semantic.scala:1361) [error] dotty.tools.dotc.transform.init.Semantic$.cases(Semantic.scala:1361) [error] dotty.tools.dotc.transform.init.Semantic$.eval$$anonfun$1(Semantic.scala:1175) [error] dotty.tools.dotc.transform.init.Cache.cachedEval(Cache.scala:112) [error] dotty.tools.dotc.transform.init.Semantic$.eval(Semantic.scala:1175) [error] dotty.tools.dotc.transform.init.Semantic$.init$$anonfun$4(Semantic.scala:1588) [error] scala.collection.immutable.List.foreach(List.scala:333) [error] dotty.tools.dotc.transform.init.Semantic$.init(Semantic.scala:1608) [error] dotty.tools.dotc.transform.init.Semantic$.cases(Semantic.scala:1384) [error] dotty.tools.dotc.transform.init.Semantic$.eval$$anonfun$1(Semantic.scala:1175) [error] dotty.tools.dotc.transform.init.Cache.cachedEval(Cache.scala:112) [error] dotty.tools.dotc.transform.init.Semantic$.eval(Semantic.scala:1175) [error] dotty.tools.dotc.transform.init.Semantic$.iterate$1(Semantic.scala:1124) [error] dotty.tools.dotc.transform.init.Semantic$.checkClass(Semantic.scala:1135) [error] dotty.tools.dotc.transform.init.Semantic$.checkClasses$$anonfun$2(Semantic.scala:1144) [error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) [error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) [error] scala.collection.IterableOnceOps.foreach(IterableOnce.scala:576) [error] scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:574) [error] scala.collection.AbstractIterable.foreach(Iterable.scala:933) [error] scala.collection.IterableOps$WithFilter.foreach(Iterable.scala:903) [error] dotty.tools.dotc.transform.init.Semantic$.checkClasses(Semantic.scala:1144) [error] dotty.tools.dotc.transform.init.Checker.runOn$$anonfun$1(Checker.scala:50) [error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) [error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) [error] dotty.tools.dotc.core.Phases$Phase.cancellable(Phases.scala:495) [error] dotty.tools.dotc.transform.init.Checker.runOn(Checker.scala:55) [error] dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:315) [error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) [error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) [error] scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323) [error] dotty.tools.dotc.Run.runPhases$1(Run.scala:337) [error] dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:350) [error] dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:360) [error] dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:69) [error] dotty.tools.dotc.Run.compileUnits(Run.scala:360) [error] dotty.tools.dotc.Run.compileUnits(Run.scala:267) [error] dotty.tools.dotc.Run.compileSuspendedUnits(Run.scala:371) [error] dotty.tools.dotc.Driver.finish(Driver.scala:57) [error] dotty.tools.dotc.Driver.doCompile(Driver.scala:38) [error] dotty.tools.xsbt.CompilerBridgeDriver.run(CompilerBridgeDriver.java:141) [error] dotty.tools.xsbt.CompilerBridge.run(CompilerBridge.java:22) [error] sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:91) [error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$7(MixedAnalyzingCompiler.scala:193) [error] scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18) [error] sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:248) [error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4(MixedAnalyzingCompiler.scala:183) [error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4$adapted(MixedAnalyzingCompiler.scala:163) [error] sbt.internal.inc.JarUtils$.withPreviousJar(JarUtils.scala:239) [error] sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:163) [error] sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:211) [error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:534) [error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:534) [error] sbt.internal.inc.Incremental$.$anonfun$apply$5(Incremental.scala:180) [error] sbt.internal.inc.Incremental$.$anonfun$apply$5$adapted(Incremental.scala:178) [error] sbt.internal.inc.Incremental$$anon$2.run(Incremental.scala:464) [error] sbt.internal.inc.IncrementalCommon$CycleState.next(IncrementalCommon.scala:116) [error] sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:56) [error] sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:52) [error] sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:263) [error] sbt.internal.inc.Incremental$.$anonfun$incrementalCompile$8(Incremental.scala:419) [error] sbt.internal.inc.Incremental$.withClassfileManager(Incremental.scala:506) [error] sbt.internal.inc.Incremental$.incrementalCompile(Incremental.scala:406) [error] sbt.internal.inc.Incremental$.apply(Incremental.scala:172) [error] sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:534) [error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:488) [error] sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:332) [error] sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:425) [error] sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:137) [error] mill.scalalib.worker.ZincWorkerImpl.compileInternal(ZincWorkerImpl.scala:544) [error] mill.scalalib.worker.ZincWorkerImpl.$anonfun$compileMixed$1(ZincWorkerImpl.scala:334) [error] mill.api.FixSizedCache.withCachedValue(FixSizedCache.scala:66) [error] mill.scalalib.worker.ZincWorkerImpl.withCompilers(ZincWorkerImpl.scala:414) [error] mill.scalalib.worker.ZincWorkerImpl.compileMixed(ZincWorkerImpl.scala:333) [error] mill.scalalib.ScalaModule.$anonfun$compile$2(ScalaModule.scala:280) [error] mill.define.Task$TraverseCtx.evaluate(Task.scala:71) [error] mill.eval.GroupEvaluator.$anonfun$evaluateGroup$11(GroupEvaluator.scala:356) [error] scala.util.DynamicVariable.withValue(DynamicVariable.scala:59) [error] scala.Console$.withErr(Console.scala:193) [error] mill.api.SystemStreams$.$anonfun$withStreams$2(SystemStreams.scala:62) [error] scala.util.DynamicVariable.withValue(DynamicVariable.scala:59) [error] scala.Console$.withOut(Console.scala:164) [error] mill.api.SystemStreams$.$anonfun$withStreams$1(SystemStreams.scala:61) [error] scala.util.DynamicVariable.withValue(DynamicVariable.scala:59) [error] scala.Console$.withIn(Console.scala:227) [error] mill.api.SystemStreams$.withStreams(SystemStreams.scala:60) [error] mill.eval.GroupEvaluator.$anonfun$evaluateGroup$8(GroupEvaluator.scala:356) [error] mill.eval.GroupEvaluator.$anonfun$evaluateGroup$8$adapted(GroupEvaluator.scala:325) [error] scala.collection.immutable.Vector.foreach(Vector.scala:2124) [error] mill.eval.GroupEvaluator.computeAll$1(GroupEvaluator.scala:325) [error] mill.eval.GroupEvaluator.evaluateGroup(GroupEvaluator.scala:380) [error] mill.eval.GroupEvaluator.$anonfun$evaluateGroupCached$22(GroupEvaluator.scala:247) [error] scala.util.DynamicVariable.withValue(DynamicVariable.scala:59) [error] mill.eval.GroupEvaluator.$anonfun$evaluateGroupCached$2(GroupEvaluator.scala:238) [error] mill.eval.GroupEvaluator$synchronizedEval$.$anonfun$apply$1(GroupEvaluator.scala:65) [error] scala.util.Using$.resource(Using.scala:262) [error] mill.eval.GroupEvaluator$synchronizedEval$.apply(GroupEvaluator.scala:64) [error] mill.eval.GroupEvaluator.evaluateGroupCached(GroupEvaluator.scala:83) [error] mill.eval.GroupEvaluator.evaluateGroupCached$(GroupEvaluator.scala:71) [error] mill.eval.EvaluatorImpl.evaluateGroupCached(EvaluatorImpl.scala:15) [error] mill.eval.EvaluatorCore.$anonfun$evaluate0$2(EvaluatorCore.scala:116) [error] scala.concurrent.impl.Promise$Transformation.run(Promise.scala:467) [error] mill.eval.ExecutionContexts$RunNow$.execute(ExecutionContexts.scala:14) [error] scala.concurrent.impl.Promise$Transformation.submitWithValue(Promise.scala:429) [error] scala.concurrent.impl.Promise$DefaultPromise.submitWithValue(Promise.scala:338) [error] scala.concurrent.impl.Promise$DefaultPromise.dispatchOrAddCallbacks(Promise.scala:312) [error] scala.concurrent.impl.Promise$DefaultPromise.map(Promise.scala:182) [error] mill.eval.EvaluatorCore.$anonfun$evaluate0$1(EvaluatorCore.scala:92) [error] mill.eval.EvaluatorCore.$anonfun$evaluate0$1$adapted(EvaluatorCore.scala:90) [error] scala.collection.immutable.Vector.foreach(Vector.scala:2124) [error] mill.eval.EvaluatorCore.evaluate0(EvaluatorCore.scala:90) [error] mill.eval.EvaluatorCore.$anonfun$evaluate$1(EvaluatorCore.scala:43) [error] scala.util.DynamicVariable.withValue(DynamicVariable.scala:59) [error] mill.eval.EvaluatorCore.evaluate(EvaluatorCore.scala:34) [error] mill.eval.EvaluatorCore.evaluate$(EvaluatorCore.scala:26) [error] mill.eval.EvaluatorImpl.evaluate(EvaluatorImpl.scala:15) [error] mill.main.RunScript$.evaluateNamed(RunScript.scala:38) [error] mill.main.RunScript$.$anonfun$evaluateTasksNamed$2(RunScript.scala:26) [error] scala.util.Either.map(Either.scala:382) [error] mill.main.RunScript$.evaluateTasksNamed(RunScript.scala:26) [error] mill.runner.MillBuildBootstrap$.evaluateWithWatches(MillBuildBootstrap.scala:399) [error] mill.runner.MillBuildBootstrap.$anonfun$processFinalTargets$3(MillBuildBootstrap.scala:308) [error] scala.util.DynamicVariable.withValue(DynamicVariable.scala:59) [error] mill.runner.MillBuildBootstrap.processFinalTargets(MillBuildBootstrap.scala:308) [error] mill.runner.MillBuildBootstrap.evaluateRec(MillBuildBootstrap.scala:196) [error] mill.runner.MillBuildBootstrap.$anonfun$evaluate$1(MillBuildBootstrap.scala:49) [error] scala.util.DynamicVariable.withValue(DynamicVariable.scala:59) [error] mill.runner.MillBuildBootstrap.evaluate(MillBuildBootstrap.scala:48) [error] mill.runner.MillMain$.$anonfun$main0$6(MillMain.scala:234) [error] mill.runner.Watching$.watchLoop(Watching.scala:27) [error] mill.runner.MillMain$.$anonfun$main0$1(MillMain.scala:219) [error] scala.util.DynamicVariable.withValue(DynamicVariable.scala:59) [error] scala.Console$.withErr(Console.scala:193) [error] mill.api.SystemStreams$.$anonfun$withStreams$2(SystemStreams.scala:62) [error] scala.util.DynamicVariable.withValue(DynamicVariable.scala:59) [error] scala.Console$.withOut(Console.scala:164) [error] mill.api.SystemStreams$.$anonfun$withStreams$1(SystemStreams.scala:61) [error] scala.util.DynamicVariable.withValue(DynamicVariable.scala:59) [error] scala.Console$.withIn(Console.scala:227) [error] mill.api.SystemStreams$.withStreams(SystemStreams.scala:60) [error] mill.runner.MillMain$.main0(MillMain.scala:101) [error] mill.runner.MillMain$.liftedTree1$1(MillMain.scala:78) [error] mill.runner.MillMain$.main(MillMain.scala:69) [error] mill.runner.MillMain.main(MillMain.scala) [error] java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) [error] java.base/java.lang.reflect.Method.invoke(Method.java:580) [error] mill.main.client.IsolatedMillMainLoader.runMain(IsolatedMillMainLoader.java:58) [error] mill.main.client.MillClientMain.main(MillClientMain.java:78) ```
KacperFKorban commented 4 months ago

The underlying issue seems to be a bug in inlining/typing and can be triggered with -Ycheck:inlining.

Slightly smaller minimization:

// i21176_1.scala
import scala.quoted.*

class Macro:
  inline def nameTuple[NameTuple_T]: (String, List[NameTuple_T]) = Macro.tuple[NameTuple_T](Macro.named)

object Macro:
  def namedMacro(using q: Quotes): Expr[String] = Expr("test")
  inline def named: String = ${Macro.namedMacro}
  def tuple[Tuple_T](name: String): (String, List[Tuple_T]) = (name, List.empty[Tuple_T])
//> using scala 3.nightly
//> using options -Ycheck:inlining
// i21176_2.scala

class Test extends Macro:
  val abc = nameTuple[Int]

Error:

```scala checking ~/bugs/i21176/i21176_1.scala after phase inlining unhandled exception while running Ycheck on ~/bugs/i21176/i21176_1.scala An unhandled exception was thrown in the compiler. Please file a crash report here: https://github.com/scala/scala3/issues/new/choose For non-enriched exceptions, compile with -Xno-enrich-error-messages. while compiling: ~/bugs/i21176/i21176_1.scala during phase: Ycheck mode: Mode(ImplicitsEnabled) library version: version 2.13.14 compiler version: version 3.6.0-RC1-bin-20240711-25ad99c-NIGHTLY-git-25ad99c settings: -Ycheck List(inlining) -classpath ~/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.6.0-RC1-bin-20240711-25ad99c-NIGHTLY/scala3-library_3-3.6.0-RC1-bin-20240711-25ad99c-NIGHTLY.jar:~/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.14/scala-library-2.13.14.jar -d ~/bugs/i21176/.scala-build/i21176_f79cd33f3d/classes/main -java-output-version 11 -sourceroot ~/bugs/i21176 Exception in thread "main" java.lang.AssertionError: assertion failed: non-empty constraint at end of inlining: uninstantiated variables: Tuple_T constrained types: [Tuple_T](name: String): (String, List[Tuple_T]) bounds: Tuple_T ordering: co-deps: contra-deps: , ownedVars = Tuple_T at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8) at dotty.tools.dotc.transform.TreeChecker.check(TreeChecker.scala:119) at dotty.tools.dotc.transform.TreeChecker.run(TreeChecker.scala:111) at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:380) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) at scala.collection.immutable.List.foreach(List.scala:334) at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:373) at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:343) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323) at dotty.tools.dotc.Run.runPhases$1(Run.scala:336) at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:384) at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:396) at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:69) at dotty.tools.dotc.Run.compileUnits(Run.scala:396) at dotty.tools.dotc.Run.compileSources(Run.scala:282) at dotty.tools.dotc.Run.compile(Run.scala:267) at dotty.tools.dotc.Driver.doCompile(Driver.scala:37) at dotty.tools.dotc.Driver.process(Driver.scala:201) at dotty.tools.dotc.Driver.process(Driver.scala:169) at dotty.tools.dotc.Driver.process(Driver.scala:181) at dotty.tools.dotc.Driver.main(Driver.scala:211) at dotty.tools.dotc.Main.main(Main.scala) Compilation failed ```
liufengyun commented 4 months ago

Thank you @KacperFKorban . Indeed, the phase safe-init gets an incorrect tree --- probably related inlining. I changed it to a meta-programming issue.