scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

Scaladoc fails where folded constants are required #9532

Closed scabug closed 5 years ago

scabug commented 8 years ago

Scaladoc turns off constant folding, but that affects whether annotations requiring constant expressions can be compiled.

As asked on stack overflow.

class MyAnnotation(val s: String) extends ClassfileAnnotation

trait T {
  final val K = "qux" + "quux" + "frobozz"

  @MyAnnotation(s = K)  // not a constant under scaladoc
  def f = ???
}
scabug commented 8 years ago

Imported From: https://issues.scala-lang.org/browse/SI-9532?orig=1 Reporter: @som-snytt Affected Versions: 2.11.7

scabug commented 8 years ago

@retronym said (edited on Oct 24, 2015 12:14:58 PM UTC): I think the principled solution here is for constant folding to operate on types only and leave terms alone. This is actually on our wishlist for 2.12, but an area where help would be much appreciated!

The idea is to take the best of both worlds terms are left as written, but the types are constant folded.

So 1 + 1 would give (1 + 1): 2.type. Right now, the regular compiler gives: 2 : 2.type, and Scaladoc / pressy gives: 1 + 1: Int.

Here's my moth-balled attempt at this: https://github.com/scala/scala/compare/2.11.x...retronym:topic/const-type-fold

The problem will be to adapt later compiler phases that match on Literal(Constant(...)) to instead check whether the tree has a constant type. This of course gets slightly harder when the code you need to update is in other projects like scala-{ide,refactoring}.

A stepping stone solution would be just to use this new approach for scaladoc, and keep it off by default for other compilation modes. We could then get downstream code changed, before enabling this by default or (by edict).

See https://groups.google.com/forum/#!topic/scala-internals/b95Y-GbXVGA for another beneficiary of such a move, the incremental compiler.

scabug commented 8 years ago

@adriaanm said: And here's my attempt: https://github.com/adriaanm/scala/tree/constantfold-in-type...

som-snytt commented 5 years ago

Before and after:

$ ~/scala-2.12.6/bin/scaladoc -d /tmp t9532.scala
t9532.scala:4: warning: Implementation restriction: subclassing Classfile does not
make your annotation visible at runtime.  If that is what
you want, you must write the annotation class in Java.
class MyAnnotation(val s: String) extends ClassfileAnnotation
      ^
t9532.scala:9: error: annotation argument needs to be a constant; found: T.this.K
  @MyAnnotation(s = K)  // not a constant under scaladoc
                    ^
model contains 4 documentable templates
one warning found
one error found
$ ~/scala-2.13.0-M5/bin/scaladoc -d /tmp t9532.scala
model contains 4 documentable templates

Scaladoc still sees original trees, albeit with folded constant types. Macros that require literal trees will be disappointed. For example,

M.lit(StringContext("hello, " + who).f())

results in

$ ~/scala-2.13.0-M5/bin/scaladoc -d /tmp litcheck.scala
litcheck.scala:13: error: exception during macro expansion:
java.lang.IllegalArgumentException: internal error: argument parts must be a list of string literals
    at scala.tools.reflect.FormatInterpolator.copyPart$1(FormatInterpolator.scala:81)
    at scala.tools.reflect.FormatInterpolator.$anonfun$interpolated$3(FormatInterpolator.scala:175)
    at scala.tools.reflect.FormatInterpolator.interpolated(FormatInterpolator.scala:174)
    at scala.tools.reflect.FormatInterpolator.interpolate(FormatInterpolator.scala:37)

    M.lit(StringContext("hello, " + who).f())
                                          ^
model contains 4 documentable templates