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

Type inference problem on sort { }.each { } #387

Closed
mauromol opened this issue Nov 16, 2017 · 10 comments
Closed

Type inference problem on sort { }.each { } #387

mauromol opened this issue Nov 16, 2017 · 10 comments
Labels

Comments

@mauromol
Copy link

This seems to be some sort of regression, because it was fixed with GRECLIPSE-1695.

Consider the following Groovy class:

package test10

class Bar {
	void bar() {
		List<String> myList = new ArrayList<String>()
		myList.each {  
			it.trim() // it detected as String correctly here
		}
		myList.sort {  a, b ->
			a.trim() <=> b.trim() // a and b detected as String correctly here
		}

		myList.sort {  a, b ->
			a.trim() <=> b.trim() // a and b detected as String correctly here
		}.each {   
			it.trim() // it not detected as String here!
		}
	}
}

As you can see, the last it.trim() is underlined because it is not recognized as String. Probably this is because the call to myList.sort { } is wrongly recognized as a call to Java 8 java.util.List.sort(Comparator<? super E>), which returns void.

@eric-milles
Copy link
Member

eric-milles commented Nov 16, 2017 via email

@eric-milles
Copy link
Member

Which of these is more applicable? Can you see why there is confusion for the tool?
default void sort(Comparator<? super E> c) from List
static <T> List<T> sort(Collection<T> self, Comparator<T> c) from DefaultGroovyMethods

@mauromol
Copy link
Author

I think Greclipse should choose what Groovy runtime does... I don't know how it behaves in this case.
However my call should not be ambiguous, I'm passing a closure to sort.

@eric-milles
Copy link
Member

eric-milles commented Nov 17, 2017 via email

@eric-milles
Copy link
Member

Here is the selection algorithm for multiple matches. List.sort has a parameter distance of 276824064 and DGM.sort has a distance of 201326592 which is lower and so it's preferred.

    private Object chooseMostSpecificParams(String name, List matchingMethods, Class[] arguments) {
        long matchesDistance = -1;
        LinkedList matches = new LinkedList();
        for (Object method : matchingMethods) {
            ParameterTypes paramTypes = (ParameterTypes) method;
            long dist = MetaClassHelper.calculateParameterDistance(arguments, paramTypes);
            if (dist == 0) return method;
            if (matches.isEmpty()) {
                matches.add(method);
                matchesDistance = dist;
            } else if (dist < matchesDistance) {
                matchesDistance = dist;
                matches.clear();
                matches.add(method);
            } else if (dist == matchesDistance) {
                matches.add(method);
            }
        }

@eric-milles
Copy link
Member

eric-milles commented Nov 17, 2017

So it's actually this DGM that satisfies: static <T> List<T> sort(Iterable<T> self, Closure closure). Closure a closer match than Comparator.

@eric-milles
Copy link
Member

eric-milles commented Nov 17, 2017

It is this block in SimpleTypeLookup that lets member matches defer to category method matches. All the hard work of comparing arguments to parameters happened within org.eclipse.jdt.groovy.search.SimpleTypeLookup.findDeclaration and very, very little information about those comparisons is returned.

    // check if the arguments and parameters are mismatched; a category method may make a better match
    if (((MethodNode) declaration).getParameters().length != scope.getMethodCallNumberOfArguments()) {
        confidence = TypeConfidence.LOOSELY_INFERRED;
    }

@mauromol
Copy link
Author

So it's actually this DGM that satisfies: static <T> List<T> sort(Iterable<T> self, Closure closure). Closure a closer match than Comparator.

Exactly what I expect: in that code I actually want to invoke the sort variant that takes a Closure and returns a List<String>, but Greclipse thinks I'm invoking Java 8 sort (try to hit F2 or F3 over the last sort call), and hence the subsequent each call fails at determining the correct it type.

@mauromol mauromol reopened this Nov 17, 2017
@groovy groovy deleted a comment from mauromol Nov 18, 2017
@groovy groovy deleted a comment from mauromol Nov 18, 2017
@groovy groovy deleted a comment from mauromol Nov 18, 2017
@eric-milles
Copy link
Member

ready to test

@mauromol
Copy link
Author

Tested with 2.9.2.xx-201711191708-e46, works fine, thank you! 👍

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

No branches or pull requests

2 participants