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

Enum constants with lambdas are initialized in static initializer block #43

Open
FoxSamu opened this issue May 25, 2020 · 2 comments
Open

Comments

@FoxSamu
Copy link

FoxSamu commented May 25, 2020

Consider the following enum:

public enum Test {
    CLASS_RUNNABLE( new SomeRunnable() ),
    FIELD_RUNNABLE( SomeRunnable.INSTANCE ),
    METHOD_RUNNABLE( SomeRunnable.getInstance() ),
    LAMBDA_RUNNABLE( () -> System.out.println( "Hello" ) ),
    MREF_RUNNABLE( SomeRunnable::runInstance );

    public static Runnable runnable;

    Test( Runnable runnable ) {
        this.runnable = runnable;
    }
}

Compiling this with javac and decompiling this with jd-core produces incorrect java code:

public enum Test {
    CLASS_RUNNABLE(new SomeRunnable()),
    FIELD_RUNNABLE(SomeRunnable.INSTANCE),
    METHOD_RUNNABLE(SomeRunnable.getInstance()),
    LAMBDA_RUNNABLE(SomeRunnable.getInstance()),
    MREF_RUNNABLE(SomeRunnable::runInstance);

    static {
        LAMBDA_RUNNABLE = new Test("LAMBDA_RUNNABLE", 3, () -> System.out.println("Hello"));
    }

    public static Runnable runnable;

    Test(Runnable runnable) {
        this.runnable = runnable;
    }
}

This code is semantically incorrect since enum constructors can't be used directly and enum constants (and static final constants in general) can't be assigned twice.

@FoxSamu
Copy link
Author

FoxSamu commented May 25, 2020

In general, static fields that are initialized with lambdas are initialized in static initializer blocks instead of in fields declarations themselves (which is usually just possible). While this does not necessary produce incorrect code outside of enums, it would be better to move all field initializers to field declarations where possible.

@FoxSamu
Copy link
Author

FoxSamu commented May 25, 2020

It seems that fields are initialized in static blocks once they reference local variables. In most situations this is not the case. In case of lambdas, the parameters of the lambdas are counted as local variables referenced by the field initialization and the field initializer is not moved to the field declaration.
To fix the issue, during moving field initializers to declarations the searching for local variable references should stop once the SearchLocalVariableReferenceVisitor enters a lambda expression and continue once it exits that expression.

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

No branches or pull requests

1 participant