INRIA / INRIA/spoon

[Bug]: Type inference/applicability error for `Objects.requireNonNullElse(T,T)` with `T=Double` when first argument is `(condition ? null : primitive_double)`

Open
#6,291 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Java
Stars
2k
Forks
393
Avg merge
11h 24m
Merged PRs (30d)
36

Description

### Describe the bug

__Spoon Version(s):__

- `fr.inria.gforge.spoon:spoon-core:11.2.1-beta-13`
- Also reproduced with `fr.inria.gforge.spoon:spoon-core:11.2.1-beta-16`

__Java Version for Parsing:__

- Code being parsed is Java 17.
- Spoon `complianceLevel` is set to `17`.
- The Spoon launcher MRE was run using OpenJDK 21.

__Problem Description:__ Spoon fails to build a model when parsing a call to `java.util.Objects.requireNonNullElse(T, T)` under specific conditions related to its arguments when `T` is `Double`. The failure occurs when the Spoon environment is configured with `setComplianceLevel(17)` and `setNoClasspath(false)` (an explicit source classpath for the MRE's own compiled class is provided).

The error is:

```javascript
spoon.compiler.ModelBuildingException: The method requireNonNullElse(T, T) in the type Objects is not applicable for the arguments (Double, Double) at path/to/MinimalTest.java:XX
at spoon.support.compiler.jdt.JDTBasedSpoonCompiler.report(JDTBasedSpoonCompiler.java:664)
... (full stack trace) ...
```

This error specifically happens for the following pattern for the first argument: `(condition ? null : primitive_double_expression)` where `primitive_double_expression` results from a `.doubleValue()` call on a `Double` wrapper.

### Source code you are trying to analyze/transform

```Java
import java.util.Objects;

public class MinimalTest {

// This method reproduces the parsing failure
public void processFails(Double wrapperInput, Double defaultInput) {
// When wrapperInput is null, first arg to requireNonNullElse is 'null'.
// When wrapperInput is not null, first arg is 'wrapperInput.doubleValue()' (a primitive double).
Double result = Objects.requireNonNullElse(
(wrapperInput == null) ? null : wrapperInput.doubleValue(),
defaultInput
);
}

// For comparison, these variations parse successfully:

// Variation 1: Using the wrapper directly (no .doubleValue())
public void processWorks_WrapperDirectly(Double wrapperInput, Double defaultInput) {
Double result = Objects.requireNonNullElse(
(wrapperInput == null) ? null : wrapperInput, // No .doubleValue()
defaultInput
);
}

// Variation 2: Casting null to (Double)
public void processWorks_CastedNull(Double wrapperInput, Double defaultInput) {
Double result = Objects.requireNonNullElse(
(wrapperInput == null) ? (Double) null : wrapperInput.doubleValue(), // Explicit (Double)null
defaultInput
);
}

// Variation 3: Using a primitive double literal instead of null
public void processWorks_PrimitiveLiteralForNull(Double wrapperInput, Double defaultInput) {
Double result = Objects.requireNonNullElse(
(wrapperInput == null) ? 0.0 : wrapperInput.doubleValue(), // Using 0.0 instead of null
defaultInput
);
}
}
```

### Source code for your Spoon processing

```Java
// Main method to run the Spoon parsing test
public static void main(String[] args) {
// This part is for running the Spoon parser, not for running the logic itself
spoon.Launcher launcher = new spoon.Launcher();
launcher.addInputResource("app/src/test/java/club/cred/codelens/parser/services/MinimalTest.java"); // Adjust path
spoon.compiler.Environment env = launcher.getEnvironment();
env.setComplianceLevel(17); // Crucial
env.setNoClasspath(false); // Simulate compileMode=true
env.setIgnoreSyntaxErrors(true);
try {
System.out.println("Building Spoon model for MRE...");
launcher.buildModel();
System.out.println("Spoon model built successfully for MRE!");
} catch (Exception e) {
System.err.println("Spoon parsing failed for MRE:");
e.printStackTrace(); // This should show the "requireNonNullElse" error if reproduced
}
}
```

### Actual output

```Java
Building Spoon model for MRE...
Spoon parsing failed for MRE:
spoon.compiler.ModelBuildingException: The method requireNonNullElse(T, T) in the type Objects is not applicable for the arguments (Double, Double) at /Users/ganesh/workspace/codelens-java-parser/app/src/test/java/club/cred/codelens/parser/services/MinimalTest.java:11
at spoon.support.compiler.jdt.JDTBasedSpoonCompiler.report(JDTBasedSpoonCompiler.java:664)
at spoon.support.compiler.jdt.JDTBasedSpoonCompiler.reportProblems(JDTBasedSpoonCompiler.java:646)
at spoon.support.compiler.jdt.JDTBasedSpoonCompiler.build(JDTBasedSpoonCompiler.java:120)
at spoon.support.compiler.jdt.JDTBasedSpoonCompiler.build(JDTBasedSpoonCompiler.java:101)
at spoon.Launcher.buildModel(Launcher.java:781)
at club.cred.codelens.parser.services.MinimalTest.main(MinimalTest.java:55)
```

### Expected output

```Java
Building Spoon model for MRE...
Spoon model built successfully for MRE!
```

### Spoon Version

11.2.1-beta-13, 11.2.1-beta-16

### JVM Version

openjdk 17.0.10

### What operating system are you using?

Mac OSx

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the MinimalTest.java reproducer through spoon.Launcher.buildModel with compliance level 17 and no-classpath disabled. Inspect the JDTBasedSpoonCompiler reporting path and compare the failing requireNonNullElse call with the three successful variations; done means the original source builds a Spoon model without the applicability error.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.