Skip to content

Fix #2797: Don't lift Java annotation arguments out of call #2819

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

Merged
merged 11 commits into from
Jul 11, 2017

Conversation

OlivierBlanvillain
Copy link
Contributor

@OlivierBlanvillain OlivierBlanvillain commented Jun 28, 2017

Here is a minimized version, the reproduction requires loading the annotation from a class file:

2797.java:

public @interface Fork {
  int value() default -1;
  String[] jvmArgs() default { "nope" };
}

2797.scala:

@Fork(jvmArgs = Array("I'm", "hot"))
class SexyScalacBenchmark
rm *.class; javac -d . 2797.java; dotc 2797.scala

@olafurpg
Copy link
Contributor

Thank you for minimizing @OlivierBlanvillain !

The scala/compiler-benchmark project compiles with this workaround and the unit tests pass. The annotations still seem to be emitted weirdly since I hit a new error when running the jmh benchmarks

Annotation @Param is not applicable to methods.
   [org.openjdk.jmh.generators.reflection.RFMethodInfo@20affcd9]

Annotation @Param is not applicable to methods.
   [org.openjdk.jmh.generators.reflection.RFMethodInfo@133b86b1]

I don't know if that error is related to this issue or not, the @Param annotations is defined on vars here https://github.com/scala/compiler-benchmark/blob/d0f038e0a9f367e26dbe9825de9d00e9e699f592/compilation/src/main/scala/scala/tools/nsc/ScalacBenchmark.scala#L18 It seems the annotation is attached to the wrong symbol

@OlivierBlanvillain
Copy link
Contributor Author

@olafurpg Last commit should moves the annotation from getter/setter methods to the actual field, let me know if that's enough to make JMH happy!

@olafurpg
Copy link
Contributor

olafurpg commented Jun 29, 2017

I can confirm that the JMH benchmark runs from the latest commit! Thank you @OlivierBlanvillain

@olafurpg
Copy link
Contributor

Any chance to get this merged? It would help unblock scala/compiler-benchmark#31

@OlivierBlanvillain
Copy link
Contributor Author

It needs a review, @odersky could you have a look?

@DarkDimius
Copy link
Contributor

@odersky could you please review it today so we can get it into next milestone?
It would be nice to have JMH working with the released jar.

@odersky odersky requested review from DarkDimius and removed request for odersky July 10, 2017 14:04
@odersky
Copy link
Contributor

odersky commented Jul 10, 2017

@smarter I am not sure how Scala annotations with default arguments are handled in the backend. Maybe @DarkDimius knows more?

@odersky
Copy link
Contributor

odersky commented Jul 10, 2017

I tried a translation to Scala; seems to work.

@@ -0,0 +1,7 @@
// Test is pending because we have no good way to test it.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this test is pending, since Fork is suffixed with 1 and Test with 2, they should be compiled as you want

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are not. I get: "Not found: Fork" when I compile Test.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed the test. The issue was that the annotation needed to be called Fork_1 since the name of the file is Fork_1.java. The javac error messages are eaten by our test suite, there's a WIP PR to fix that at #2811

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good to know.

@odersky odersky changed the title Workaround #2797 by removing an assertion Fix #2797: Don't lift Java annotation arguments out of call Jul 10, 2017
@odersky odersky added this to the 0.2 Tech Preview milestone Jul 10, 2017
OlivierBlanvillain and others added 9 commits July 10, 2017 19:26
This is nessary for interactiong with java libraries such as JMH. Matches scalac's behavior.
Lifting such arguments breaks the contract with the backend, which
expects to see default getters inline, not lifted out.
 - Java-defined annotation constructors need to have JavaDefined set.
 - Change the points where we suppress lifting. One case slipped through before.
 - Also: Add test.
Test is pending because we have no good way to test it.
We need to: Compile Fork.java, and then compile Test.scala
with Fork.class on the classpath.
Fork_1.java failed to compile before because the class name did not
match the filename.
@smarter
Copy link
Member

smarter commented Jul 10, 2017

It might not crash in the backend, but the Scala test case still generates some weird code:

@{
    <accessor> val value$1: Int = Fork.$lessinit$greater$default$1
    <accessor> val jvmArgs$1: Array{scala$Array$$T = String} = 
      Array.apply[String](["I\'m","hot" : String])(
        scala.reflect.ClassTag.apply[String](classOf[class String])
      )
    new Fork(Test.this.value$1, Test.this.jvmArgs$1)

It looks like scalac does something similar but with a warning:

% scalac tests/pos/i2797a/Fork.scala tests/pos/i2797a/Test.scala
tests/pos/i2797a/Test.scala:4: warning: Usage of named or default arguments transformed this annotation
constructor call into a block. The corresponding AnnotationInfo
will contain references to local values and default getters instead
of the actual argument trees
@Fork(jvmArgs = Array("I'm", "hot"))
 ^

Copy link
Member

@smarter smarter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM since this is an improvement on the current situation

While the test now succeeds under separate compilation, it fails join
compilation (which happens to be tested by the legacy tests currently),
you can reproduce that by running:
dotc tests/pending/pos/i2797/Fork_1.java tests/pending/pos/i2797/Test_2.scala

This fails with:
-- Error: tests/pending/pos/i2797/Test_2.scala:4:0 -------------------------------------
4 |@Fork_1(jvmArgs = Array("I'm", "hot"))
  |^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |missing argument for parameter value of constructor Fork_1: (value:
  |Int, jvmArgs: Array[String]): Fork_1

Because the JavaParsers output a constructor for Fork_1 without default
values, to fix this we need JavaParsers to do something similar to
ClassfileParser#addAnnotationConstructor
@smarter
Copy link
Member

smarter commented Jul 10, 2017

Had to disable i2797 again because of joint compilation failure, see last commit, I'll open an issue for that.

@odersky
Copy link
Contributor

odersky commented Jul 10, 2017

In fact, we could put i2797 in pos-special and have legacyTests not try it.

@smarter
Copy link
Member

smarter commented Jul 10, 2017

Looks like separate compilation is not used with compileDir unfortunately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants