Skip to content

UseLambdaForFunctionalInterface converts anonymous class to lambda when target type is var #895

@protocol7

Description

@protocol7

What version of OpenRewrite are you using?

  • rewrite-static-analysis: 2.34.1
  • rewrite-core: 8.81.13
  • rewrite-java: 8.81.13

What is the smallest, simplest way to reproduce the problem?

class Main {
  interface Action {
    String run(String input);
  }

  void execute() {
    final var action =
        new Action() {
          @Override
          public String run(String input) {
            return input.toUpperCase();
          }
        };
    action.run("hello");
  }
}

Run org.openrewrite.staticanalysis.UseLambdaForFunctionalInterface.

What did you expect to see?

Either no change, or the recipe should replace var with the explicit interface type (Action) when performing the conversion.

var can hold a functional interface only when the right-hand side provides an explicit target type, such as new Action() { ... }. A lambda expression is not a standalone expression and requires its target type to come from the declaration. With var, that target type is absent (JLS 14.4.1, 15.27.1).

What did you see instead?

The recipe converts the anonymous class to a lambda while keeping var:

void execute() {
    final var action =
            input -> input.toUpperCase();
    action.run("hello");
}

The rewritten code no longer compiles:

error: cannot infer type for local variable action
    final var action =
              ^

What is the full stack trace of any errors you encountered?

Downstream compilation fails with:

CampaignStoreImplTest.java:1472: error: cannot infer type for local variable campaignUpdate
    final var campaignUpdate =
              ^
CampaignStoreImplTest.java:1510: error: cannot infer type for local variable stateUpdate
    final var stateUpdate =
              ^
CampaignStoreImplTest.java:1512: error: cannot infer type for local variable livePeriodUpdate
    final var livePeriodUpdate =
              ^

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions