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

Macro calling the apply of a case class nested in a trait leads to a typer error #14001

Closed
987Nabil opened this issue Nov 25, 2021 · 1 comment · Fixed by #14924
Closed

Macro calling the apply of a case class nested in a trait leads to a typer error #14001

987Nabil opened this issue Nov 25, 2021 · 1 comment · Fixed by #14924
Assignees
Labels
area:metaprogramming:reflection Issues related to the quotes reflection API

Comments

@987Nabil
Copy link

987Nabil commented Nov 25, 2021

Compiler version

3.1.0

Minimized code

package test
trait B {
  case class C(i: Int)
}

object A extends B

object X {
  val z = Y.testStuff[A.C]
}
package test
object Y {
  inline def testStuff[T]: T =
    ${testStuffImpl}

  def testStuffImpl[T: Type](using Quotes): Expr[T] = {
    import quotes.reflect.*

    Apply(
      Ref(Symbol.requiredMethod("test.A.C.apply")),
      List(Literal(IntConstant(1)))
    ).asExpr.asInstanceOf[Expr[T]]
  }
}

Output

exception while typing C.this of class class dotty.tools.dotc.ast.Trees$This # -1
exception while typing C.this.apply of class class dotty.tools.dotc.ast.Trees$Select # -1
exception while typing C.this.apply(1) of class class dotty.tools.dotc.ast.Trees$Apply # -1
exception while typing C.this.apply(1):test.A.C of class class dotty.tools.dotc.ast.Trees$Typed # -1
exception while typing C.this.apply(1):test.A.C of class class dotty.tools.dotc.ast.Trees$Inlined # -1
exception while typing def z: test.A.C = C.this.apply(1):test.A.C of class class dotty.tools.dotc.ast.Trees$DefDef # -1
exception while typing @scala.annotation.internal.SourceFile(
  "xxx/src/main/scala/test/B.scala"
) final module class X() extends Object() {
  private def writeReplace(): AnyRef = 
    new scala.runtime.ModuleSerializationProxy(classOf[test.X.type])
  def z: test.A.C = C.this.apply(1):test.A.C
} of class class dotty.tools.dotc.ast.Trees$TypeDef # -1
exception while typing package test {
  @scala.annotation.internal.SourceFile(
    "xxx/src/main/scala/test/B.scala"
  ) trait B() extends Object {
    case class C(i: Int) extends Object(), Product, Serializable {
      override def hashCode(): Int = 
        {
          var acc: Int = -889275714
          acc = scala.runtime.Statics#mix(acc, this.productPrefix.hashCode())
          acc = scala.runtime.Statics#mix(acc, C.this.i)
          scala.runtime.Statics#finalizeHash(acc, 1)
        }
      override def equals(x$0: Any): Boolean = 
        this.eq(x$0.$asInstanceOf[Object]).||(
          matchResult1[Boolean]: 
            {
              case val x1: (x$0 : Object) = x$0
              if 
                x1.$isInstanceOf[B.this.C @unchecked].&&(
                  x1.$asInstanceOf[B.this.C @unchecked].test$B$C$$$outer.eq(
                    B.this
                  )
                )
               then 
                {
                  case val x$0: B.this.C = x1.$asInstanceOf[B.this.C @unchecked]
                  return[matchResult1] this.i.==(x$0.i).&&(x$0.canEqual(this))
                }
               else ()
              return[matchResult1] false
            }
        )
      override def toString(): String = 
        scala.runtime.ScalaRunTime._toString(this)
      override def canEqual(that: Any): Boolean = 
        that.isInstanceOf[B.this.C @unchecked]
      override def productArity: Int = 1
      override def productPrefix: String = "C"
      override def productElement(n: Int): Any = 
        matchResult2[Int]: 
          {
            case val x3: (n : Int) = n
            if 0.==(x3) then return[matchResult2] this._1 else ()
            throw new IndexOutOfBoundsException(n.toString())
          }
      override def productElementName(n: Int): String = 
        matchResult3[String]: 
          {
            case val x4: (n : Int) = n
            if 0.==(x4) then return[matchResult3] "i" else ()
            throw new IndexOutOfBoundsException(n.toString())
          }
      def i: Int
      def copy(i: Int): B.this.C = new B.this.C(i)
      def copy$default$1: Int @uncheckedVariance = C.this.i
      def _1: Int = this.i
      private val $outer: test.B
      final def test$B$C$$$outer: test.B = C.this.$outer
    }
    final lazy module def C: B.this.C = new B.this.C()
    final module class C() extends AnyRef(), scala.deriving.Mirror.Product {
      def apply(i: Int): B.this.C = new B.this.C(i)
      def unapply(x$1: B.this.C): B.this.C = x$1
      override def toString: String = "C"
      type MirroredMonoType = B.this.C
      def fromProduct(x$0: Product): test.B.C.MirroredMonoType = 
        new B.this.C(x$0.productElement(0).$asInstanceOf[Int])
      private val $outer: test.B
      final def test$B$C$$$$outer: test.B = test.B.C.$outer
    }
  }
  final lazy module val A: test.A = new test.A()
  @scala.annotation.internal.SourceFile(
    "xxx/src/main/scala/test/B.scala"
  ) final module class A() extends Object(), test.B {
    private def writeReplace(): AnyRef = 
      new scala.runtime.ModuleSerializationProxy(classOf[test.A.type])
  }
  final lazy module val X: test.X = new test.X()
  @scala.annotation.internal.SourceFile(
    "xxx/src/main/scala/test/B.scala"
  ) final module class X() extends Object() {
    private def writeReplace(): AnyRef = 
      new scala.runtime.ModuleSerializationProxy(classOf[test.X.type])
    def z: test.A.C = C.this.apply(1):test.A.C
  }
} of class class dotty.tools.dotc.ast.Trees$PackageDef # -1
java.lang.AssertionError: assertion failed: asTerm called on not-a-Term val <none> while compiling /xxx/src/main/scala/test/B.scala, xxx/src/main/scala/test/Y.scala
[error] ## Exception when compiling 18 sources to xxx/target/scala-3.1.0/classes
[error] java.lang.AssertionError: assertion failed: asTerm called on not-a-Term val <none>
[error] scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
[error] dotty.tools.dotc.core.Symbols$Symbol.asTerm(Symbols.scala:163)
[error] dotty.tools.dotc.transform.ExplicitOuter$.dotty$tools$dotc$transform$ExplicitOuter$$$outerParamAccessor(ExplicitOuter.scala:228)
[error] dotty.tools.dotc.transform.ExplicitOuter$OuterOps$.loop$1(ExplicitOuter.scala:429)
[error] dotty.tools.dotc.transform.ExplicitOuter$OuterOps$.path$extension(ExplicitOuter.scala:438)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedThis(Erasure.scala:805)
[error] dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2756)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2818)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:121)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2883)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2887)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedSelect(Erasure.scala:696)
[error] dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2725)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2817)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:121)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2883)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2887)
[error] dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3003)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedApply(Erasure.scala:837)
[error] dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2755)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2818)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:121)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2883)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2880)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2887)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedTyped(Erasure.scala:658)
[error] dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2760)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2818)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:121)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2883)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2880)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2887)
[error] dotty.tools.dotc.typer.Typer.typedInlined(Typer.scala:1793)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedInlined(Erasure.scala:899)
[error] dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2777)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2818)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:121)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2883)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2887)
[error] dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3003)
[error] dotty.tools.dotc.typer.Typer.$anonfun$39(Typer.scala:2211)
[error] dotty.tools.dotc.typer.PrepareInlineable$.dropInlineIfError(PrepareInlineable.scala:225)
[error] dotty.tools.dotc.typer.Typer.typedDefDef(Typer.scala:2211)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedDefDef(Erasure.scala:955)
[error] dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2732)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2817)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:121)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2883)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2887)
[error] dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2909)
[error] dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2959)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:1053)
[error] dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:2409)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedClassDef(Erasure.scala:1043)
[error] dotty.tools.dotc.typer.Typer.typedTypeOrClassDef$2(Typer.scala:2743)
[error] dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2747)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2817)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:121)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2883)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2887)
[error] dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2909)
[error] dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2959)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:1053)
[error] dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:2532)
[error] dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2788)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2818)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:121)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2883)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2887)
[error] dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3003)
[error] dotty.tools.dotc.transform.Erasure.run(Erasure.scala:132)
[error] dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:308)
[error] scala.collection.immutable.List.map(List.scala:246)
[error] dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:309)
[error] dotty.tools.dotc.Run.runPhases$4$$anonfun$4(Run.scala:261)
[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$5(Run.scala:272)
[error] dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:280)
[error] scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
[error] dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:68)
[error] dotty.tools.dotc.Run.compileUnits(Run.scala:289)
[error] dotty.tools.dotc.Run.compileUnits(Run.scala:228)
[error] dotty.tools.dotc.Driver.finish(Driver.scala:60)
[error] dotty.tools.dotc.Driver.doCompile(Driver.scala:40)
[error] dotty.tools.xsbt.CompilerBridgeDriver.run(CompilerBridgeDriver.java:88)
[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:192)
[error] scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
[error] sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:247)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4(MixedAnalyzingCompiler.scala:182)
[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:210)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:528)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:528)
[error] sbt.internal.inc.Incremental$.$anonfun$apply$5(Incremental.scala:177)
[error] sbt.internal.inc.Incremental$.$anonfun$apply$5$adapted(Incremental.scala:175)
[error] sbt.internal.inc.Incremental$$anon$2.run(Incremental.scala:461)
[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:416)
[error] sbt.internal.inc.Incremental$.withClassfileManager(Incremental.scala:503)
[error] sbt.internal.inc.Incremental$.incrementalCompile(Incremental.scala:403)
[error] sbt.internal.inc.Incremental$.apply(Incremental.scala:169)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:528)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:482)
[error] sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:332)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:420)
[error] sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:137)
[error] sbt.Defaults$.compileIncrementalTaskImpl(Defaults.scala:2365)
[error] sbt.Defaults$.$anonfun$compileIncrementalTask$2(Defaults.scala:2315)
[error] sbt.internal.server.BspCompileTask$.$anonfun$compute$1(BspCompileTask.scala:30)
[error] sbt.internal.io.Retry$.apply(Retry.scala:46)
[error] sbt.internal.io.Retry$.apply(Retry.scala:28)
[error] sbt.internal.io.Retry$.apply(Retry.scala:23)
[error] sbt.internal.server.BspCompileTask$.compute(BspCompileTask.scala:30)
[error] sbt.Defaults$.$anonfun$compileIncrementalTask$1(Defaults.scala:2313)
[error] scala.Function1.$anonfun$compose$1(Function1.scala:49)
[error] sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:62)
[error] sbt.std.Transform$$anon$4.work(Transform.scala:68)
[error] sbt.Execute.$anonfun$submit$2(Execute.scala:282)
[error] sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:23)
[error] sbt.Execute.work(Execute.scala:291)
[error] sbt.Execute.$anonfun$submit$1(Execute.scala:282)
[error] sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265)
[error] sbt.CompletionService$$anon$2.call(CompletionService.scala:64)
[error] java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
[error] java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
[error] java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
[error] java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
[error] java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
[error] java.base/java.lang.Thread.run(Thread.java:834)
[error]      

Expectation

The apply of the case class can be called and an object can be created.

PS: When using a proxy method to the apply, it works just fine.

@nicolasstucki
Copy link
Contributor

The example code has a bug hidden by the unchecked/unsound cast to Expr[T]. Using the asExprOf checked cast

-    ).asExpr.asInstanceOf[Expr[T]]
+    ).asExprOf[T]

we get

9 |  val z = Y.testStuff[A.C]
  |          ^^^^^^^^^^^^^^^^
  |Exception occurred while executing macro expansion.
  |java.lang.Exception: Expr cast exception: test.A.C.apply(1)
  |of type: test.A.C
  |did not conform to type: scala.Nothing
  |
  |     at scala.quoted.runtime.impl.QuotesImpl.asExprOf(QuotesImpl.scala:71)
  |     at scala.quoted.runtime.impl.QuotesImpl$reflect$TreeMethods$.asExprOf(QuotesImpl.scala:113)
  |     at scala.quoted.runtime.impl.QuotesImpl$reflect$TreeMethods$.asExprOf(QuotesImpl.scala:112)
  |     at test.Y$.testStuffImpl(Bar.scala:23)
  |
  | This location contains code that was inlined from Foo.scala:9

From this, we know that testStuffImpl is called as testStuffImpl[Nothing]. Therefore the code requires the following change to work (and should also use asExprOf)

  inline def testStuff[T]: T =
-   ${ testStuffImpl }
+   ${ testStuffImpl[T] }

@nicolasstucki nicolasstucki added area:metaprogramming:reflection Issues related to the quotes reflection API and removed area:metaprogramming labels Feb 18, 2022
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 13, 2022
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 13, 2022
michelou pushed a commit to michelou/scala3 that referenced this issue Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:metaprogramming:reflection Issues related to the quotes reflection API
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants