projectlombok / lombok

Very spicy additions to the Java programming language.
https://projectlombok.org/
Other
12.88k stars 2.39k forks source link

Random javac compilation error: Cannot use 'val' here #729

Closed lombokissues closed 9 years ago

lombokissues commented 9 years ago

Migrated from Google Code (issue 694)

lombokissues commented 9 years ago

:bust_in_silhouette: rtiernay   :clock8: Jun 13, 2014 at 18:14 UTC

What steps will reproduce the problem?

  1. git clone https://github.com/icgc-dcc/dcc.git
  2. git checkout 5df0ba29beb8779fa75ae28c55aff40cbb5c2cb3
  3. mvn clean package -am -pl dcc-etl/dcc-etl-indexer -DskipTests

You may need to repeat 3. multiple times to observe the error

What is the expected output? What do you see instead?

I expect the build to complete successfully, but see the following output instead:

ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project dcc-etl-indexer: Compilation failure [ERROR] dcc/dcc-etl/dcc-etl-indexer/src/main/java/org/icgc/dcc/etl/indexer/document/core/DocumentProcessor.java:[121,9] Cannot use 'val' here because initializer expression does not have a representable type: Type cannot be resolved

Please provide any additional information below.

I have given access to my private github repo to one of the core developers (rzwitserloot) who has confirmed that this occurs randomly.

Using Lombok 1.12.6

mvn -v
Apache Maven 3.2.1 (ea8b2b07643dbb1b84b6d16e1f08391b666bc1e9; 2014-02-14T12:37:52-05:00) Maven home: /usr/local/Cellar/maven/3.2.1/libexec Java version: 1.7.0_55, vendor: Oracle Corporation Java home: /Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre Default locale: en_US, platform encoding: UTF-8 OS name: "mac os x", version: "10.9.2", arch: "x86_64", family: "mac"

lombokissues commented 9 years ago

:bust_in_silhouette: reinierz   :clock8: Jun 28, 2014 at 22:52 UTC

After A LOT of searching and trying things, it looks like this is caused by the following:

1) The order in which source files are processed is semi-random, probably because a map with undefined order is in the process somewhere, and it sorts on memory position which is non-deterministic.

2) You use val x = new Foo() {} syntax someplace (as in, the RHS of a val-typed local variable declaration is or contains an anonymous inner class literal), AND this is evaluated BEFORE Foo itself. In this case, all usage of 'val' in Foo will cause errors.

We're not 100% sure if that really is it, but so far it looks like it is. In the original sources, the relevant line is:

dcc/dcc-etl/dcc-etl-indexer/src/main/java/org/icgc/dcc/etl/indexer/document/schema/ForwardSchemaGenerator.java:115 (method: createProcessor), which uses 'val' along with an anonymous inner class literal of DocumentProcessor on the right hand side. The actual errors which usually (but not always) occur, occur during val usage of DocumentProcessor.

So far, on successful runs, DocumentProcessor is done first and ForwardSchemaGenerator later, and on failing runs, it's the reverse. 'unvalling' the assignment on line 115 so far has resulted in 10 successful runs and no failures, so seems like bingo.

We're going to try and 'fix' this by eliminating the anonymous inner class aspect of any RHS expression and then attribing it, and if that does not work, we're probably going to declare any usage of AICLs in the RHS as invalid. Note that our preferred solution does mean that this:

val x = new Object() { public int someNewMethodThatDoesntOverrideAnything() { return 5; }}.someNewMethodThatDoesntOverrideAnything();

would NOT be equivalent to 'final int x = ...' even though it should be, but we'll assume that the above is pretty much never used by any java programmers ever. So, that particular bit being broken is fine in my book, I think.

lombokissues commented 9 years ago

:bust_in_silhouette: r.spilker   :clock8: Jun 28, 2014 at 23:15 UTC

CONFIRM previous hypothesis. This test case proves it. It requires 3 files:

File1.java:

public class File1 {{
    lombok.val f2 = new File2() {};
}}

File2.java:

public class File2 {{
    lombok.val f3 = 0;
}}

now compile with:

javac -cp lombok.jar *.java

in a dir with just the above 2 files.

Half of the time it fails, the other half it succeeds. (It succeeds if File2 is processed first, fails if File1 is processed first). If you remove the {} on line 2 of File1.java (remove the anonymous inner class literal aspect of it), the problem ceases to exist, and all compiles always succeed, regardless of whether File1 or File2 ends up getting processed first.

NB: The following replacement for File1.java also causes the compile run to fail 50% of the time:

public class File1 {{
    class F2 extends File2 {}
    lombok.val f2 = new File2();
}}

essentially, any method local thing that extends a source-path type will 'ruin' val in that source-path type if ANY attributing is done of any member anywhere in that scope. Most likely the solution is to update our tree copier to be more careful about how to handle this, because right now evidently the 'real' File2 nodes are being modified somehow.

lombokissues commented 9 years ago

:bust_in_silhouette: rtiernay   :clock8: Jul 07, 2014 at 14:00 UTC

Wow, I really appreciate all your hard work here. Great investigating!

Any idea on when you might be able to handle this or throw an error in eclipse / cli?

Thanks again

lombokissues commented 9 years ago

:bust_in_silhouette: reinierz   :clock8: Jan 31, 2015 at 03:54 UTC

Hold on to your hats... I think I fixed this thing.

Give this edge build a shot?

https://projectlombok.org/download-edge.html

lombokissues commented 9 years ago

End of migration