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.