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

bug: Java8 "Foo[]::new" cannot be resolved #1883

Closed
monperrus opened this issue Feb 25, 2018 · 8 comments · Fixed by #1945
Closed

bug: Java8 "Foo[]::new" cannot be resolved #1883

monperrus opened this issue Feb 25, 2018 · 8 comments · Fixed by #1945
Labels

Comments

@monperrus
Copy link
Collaborator

Assuming a Java8 new ArrayList().stream().toArray(Foo[]::new)

The Foo[]::new is a CtExRefExpression which cannot be resolved with getExecutableDeclaration even if Foo is in the classpath.

See failing test in master...monperrus:bug-execrefexpr

@monperrus monperrus added the bug label Feb 25, 2018
surli added a commit to surli/spoon that referenced this issue Apr 3, 2018
@surli
Copy link
Collaborator

surli commented Apr 3, 2018

So I started to dig into it but it's actually a tricky one!
The thing is: there's is no constructor that we can use to resolve the new here.
When you type Foo[]::new in that lambda, it's transformed in the bytecode in something like i -> new Foo[i]. And an expression like new Foo[i] in Spoon is a CtNewArray which is not a CtExecutable.

IMHO the only way to get a CtExecutable is to point to Array.newInstance, but I'm not sure we want to put that in the Spoon model, so we would have to create an instance of this CtExecutable at each call of getExecutable...
WDYT?

@pvojtechovsky
Copy link
Collaborator

What about new spoon element

interface CtNewArrayReferenceExpression extends CtExecutableReferenceExpression {}

which might implement derived, unsettable getExecutable(), which would return null. Because reference to Array.newInstance is not correct too, because the number of parameters is not fitting

  • new Foo[i] has one integer parameter
  • Array.newInstance(Class, int) has two parameters ...

Check if that idea is correct, because I am really not sure ;-)

@surli
Copy link
Collaborator

surli commented Apr 4, 2018

the number of parameters is not fitting

  • new Foo[i] has one integer parameter
  • Array.newInstance(Class, int) has two parameters ...

It's fitting if you consider that the first parameter will always be the type of the array, here Foo.class.

@pvojtechovsky
Copy link
Collaborator

It's fitting

It is fitting in my mind too, but it is not fitting from concept point of view.

@surli
Copy link
Collaborator

surli commented Apr 4, 2018

but it is not fitting from concept point of view.

Yeah I agree that's why I don't think we should put it in the model.
Maybe a middle-way is to indeed define a new interface like you propose, with derived getExecutable returning Array.newInstance

@pvojtechovsky
Copy link
Collaborator

derived getExecutable returning Array.newInstance

What is purpose of the return value of getExecutable?
A) client knows what method will be called by that method reference
B) ?

If A), then returning Array.newInstance is confusing, because it is really not the method which is called. There is called no method at all, because array allocation is primitive operation of java same like allocation of place for a single int value. So I think that returning null is better then returning something confusing.

When you type Foo[]::new in that lambda, it's transformed in the bytecode in something like (int i) -> new Foo[i]

Note: that lambda expression has one parameter, while Array.newInstance has two parameters. So if any client would like to analyze value returned by CtNewArrayReferenceExpression#getExecutable, then he might get confused by that wrong number of parameters.

If we really want to return something there, then we should return something correct - may be new model element again? ... but that would need extra handling by client anyway ... same like null value. So null is KISS.

WDYT?

@monperrus
Copy link
Collaborator Author

what about returning a singleton object InvisibleArrayConstructor extends CtConstructorImpl?

@pvojtechovsky
Copy link
Collaborator

So if I summarize it then Foo[]::new is represented as CtNewArrayReferenceExpression
And CtNewArrayReferenceExpression#getExecutable will return an CtExecutableReference (do we need a new model type here too?), whose getExecutableDeclaration returns an instance of InvisibleArrayConstructor
What about other attributes of this InvisibleArrayConstructor? type, parameters,... ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants