JDK-8273350 : TypeSymbol::precedes generates an order that depends on the order in which types are seen by the compiler
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 18
  • Priority: P4
  • Status: Resolved
  • Resolution: Not an Issue
  • Submitted: 2021-09-03
  • Updated: 2022-08-02
  • Resolved: 2021-09-16
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdResolved
Related Reports
Relates :  
Description
Altering the order of the declaration of interface StringLiteral in the code below will make the difference between the code failing at execution time or not.

//interface StringLiteral {}  // in this position fails

interface Variable {}

interface StringLiteral {}  // in this position passes

class MyFact {
    MyFact(StringLiteral stringLiteral) {}
}

interface OneVariableQuery<VarType extends Variable> {
    Object query(VarType var1);
}

class Interpreter {
    <VarType extends Variable> Object query(OneVariableQuery<VarType> query) { return null; }
}

public class Main {
    public static void main(String[] args) {
        Interpreter interpreter = new Interpreter();
        interpreter.query(MyFact::new); // causes exception at execution time
//      interpreter.<StringVariable>query(MyFact::new); // executes correctly
    }
}

The issue I found is that during type inference type variable VarType will be inferred to StringLiteral & Variable or Variable & StringLiteral, depending on the order in which StringLiteral is declared in the source code. It seems to me that the difference is due to the implementation of method TypeSymbol::precedes which is used in this case to sort the components of the to-be-generated intersection type tvar VarType is instanciated to. This instantiation leads to the type of the method reference being erased to (StringLiteral)Object or (Variable)Object.

This seems odd and a potential source of problems that could be made worst if the code is split in different files as successful compilation will depend on the order in which the files are processed by the compiler.