scala / scala3

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

Parameters are not substituted in lambdas in type annotation #19846

Open mbovel opened 4 months ago

mbovel commented 4 months ago

Compiler version

Scala 3.4.2-RC1-bin-20240229-9fe0111-NIGHTLY-git-9fe0111 (17.0.8, Java OpenJDK 64-Bit Server VM)

Minimized code

Let dependentAnnotation.scala contain:

package dependentAnnotation

class lambdaAnnot(g: () => Int) extends annotation.StaticAnnotation
def f(x: Int): Int @lambdaAnnot(() => x + 1) = x

@main def main =
  val y: Int = 5
  val z = f(y)

Output

scala-cli compile -S 3.nightly -Xprint:typer --server=false dependentAnnotation.scala

outputs

...
val z:

      Int @lambdaAnnot(
        {
          def $anonfun(): Int = x.+(1) // Not substituted 😱
          closure($anonfun)
        }
      )

    = dependentAnnotation.f(y)
  ()
}
...

Expectation

x should be substituted to y.

This is the case if the annotation takes an Int parameter instead of () => Int.

Example without a lambda ```scala package dependentAnnotation2 class intAnnot(predicate: Int) extends annotation.StaticAnnotation def f(x: Int): Int @intAnnot(x + 1) = x @main def main = val y: Int = 5 val z = f(y) ``` ``` scala-cli compile -S 3.nightly -Xprint:typer --server=false dependentAnnotation2.scala ``` ```scala ... val z: Int @intAnnot(y.+(1)) = dependentAnnotation2.f(y) ... ```
mbovel commented 4 months ago

Maybe related: #18064.

mbovel commented 2 months ago

Also fails to pickle, similarly to #20035:

class qualified[T](predicate: T => Boolean) extends annotation.StaticAnnotation

class EqualPair(val x: Int, val y: Int @qualified[Int](it => it == x))

@main def main =
  val p = EqualPair(42, 42)
  val y = p.y
  println(42)
java.lang.AssertionError: assertion failed: unresolved symbols: <span class="ansi-color-yellow">parameter</span> <span class="ansi-color-magenta">x</span> (line 3) #7588 when pickling /tmp/scastie5434625360140563661/src/main/scala/main.scala
    at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
    at dotty.tools.dotc.core.tasty.TreePickler.pickle(TreePickler.scala:829)
    at dotty.tools.dotc.transform.Pickler.run$$anonfun$1$$anonfun$1(Pickler.scala:90)
    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:333)
    at dotty.tools.dotc.transform.Pickler.run$$anonfun$1(Pickler.scala:142)
    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:333)
    at dotty.tools.dotc.transform.Pickler.run(Pickler.scala:142)
    at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:327)
    at scala.collection.immutable.List.map(List.scala:246)
    at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:331)
    at dotty.tools.dotc.transform.Pickler.runOn(Pickler.scala:150)
    at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:246)
    at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
    at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)