1

I'm trying to get my head around a generic-type problem. But it seems like eclipse is complaining while there isn't a valid complaint.

Consider the following methods

public static <FR extends FilterResult, T> List<? super WrappedFilterResult<? super T, FR>> filter(String check, Collection<T> elements, Function<? super T, String> converter, Filter<? extends FR> filter, ACComparator<? super WrappedFilterResult<? super T, ? super FR>> comparator)
{
    // eclipse says 'filter' doesn't accept these arguments
    return filter(check, elements, new ArrayList<>(), converter, filter, comparator);
    
    // doing a self call will result in the same error?
    // return filter(check, elements, converter, filter, comparator);
    
    // calling without returning doesn't solve it either?
    // filter(check, elements, converter, filter, comparator);
    // return null;
}

// no complaints here
public static <FR extends FilterResult, T, C extends Collection<? super WrappedFilterResult<? super T, FR>>> C filter(String check, Collection<T> elements, C result, Function<? super T, String> converter, Filter<? extends FR> filter, ACComparator<? super WrappedFilterResult<? super T, ? super FR>> comparator)
{
    // content
}

For the first method eclipse is complaining it cannot call the filter method because the method is not applicable for the arguments. But even if I do a self call it will complain.

Thinking it might be the return type I eliminated it by only calling and returning null, but sadly that doesn't solve anything either.

Sorry for the complicated method declaration but I have more similar methods with the same kind/amount of parameters working with no problems. So I have no clue why this wouldn't work.

Info:

  • Windows 10
  • Eclipse oxygen.3a Release (4.7.3a)

I hope its something minor I fail to see atm, any help is appreciated.

Thanks in advance


Edit

The class declarations if someone needs them

public static class FilterResult {}
public interface Filter<FR extends FilterResult> {}
public static class WrappedFilterResult<T, FR extends FilterResult> extends FilterResult {}
public interface ACComparator<FR extends FilterResult> {}

Submitted to Bugzilla

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
n247s
  • 1,898
  • 1
  • 12
  • 30
  • 1
    please define the types `FilterResult`, `WrappedFilterResult` and `ACComparator`, just the basic class declaration, we don't need their implementation. – xtratic Dec 28 '18 at 18:46
  • 1
    Could you also declare and initialize all variables that you are using to call the filter method? – Zach Pedigo Dec 28 '18 at 18:52
  • @xtratic added them to the post – n247s Dec 28 '18 at 19:02
  • @ZachPedigo I just tried it, doesn't change anything strangly enough – n247s Dec 28 '18 at 19:03
  • @ZachPedigo Yea, knowing the variables doesn't add any helpful information. – xtratic Dec 28 '18 at 19:05
  • @xtratic Just wanted to be sure that it wasn't something simple like a wrong variable type, I've done that myself a handful of times. – Zach Pedigo Dec 28 '18 at 19:07
  • @ZachPedigo That's definitely an issue with calling generic methods, but in this case the parameters of the first `filter` are being passed into the second `filter` method, so we already know all the declared types. – xtratic Dec 28 '18 at 19:09
  • @n247s I'm getting `cannot infer type arguments` for the `new ArrayList<>()`, what's its type? `new ArrayList()` or something? – xtratic Dec 28 '18 at 19:13
  • 2
    @xtratic seems like it should be `new ArrayList>()` – Alexander Radchenko Dec 28 '18 at 19:18
  • @AlexanderRadchenko That's what I'm guessing, but would still like a confirmation from OP. – xtratic Dec 28 '18 at 19:18
  • Its type should be compatible with the `C` generic-type argument of the second method – n247s Dec 28 '18 at 19:19
  • As a side note, both the`Collection` and the `ArrayList` are imported correctly, and are used multiple times without problems elsewhere in the same class – n247s Dec 28 '18 at 19:20
  • By trying the parameters one by one, I found that it's the `ACComparator`s fault.. trying to figure out why – xtratic Dec 28 '18 at 19:31

2 Answers2

2

I assume it is an Eclipse JDT compiler bug, though I have not consulted the JLS and also don't really feel like digging around in it.

The reasons for my assumption is threefold:

  1. Your code compiles successfully under javac 8u112

  2. I would expect that a method calling itself with its own parameters should compile.

  3. Earlier, I also ran into a case where Eclipse compiler disagreed with other compilers.

MCVE to reproduce your issue:

public static class FilterResult {}
public static class WrappedFilterResult<T, FR extends FilterResult> extends FilterResult {}
public interface ACComparator<FR extends FilterResult> {}

public static <FR extends FilterResult, T>
  void filter1(ACComparator<? super WrappedFilterResult<? super T, ? super FR>> comparator) {
    // both compile fine with normal Java compiler
    // but error with Eclipse JDT compiler (I'm using Eclipse 4.9.0)
    filter1(comparator);
    filter2(comparator);
}

public static <FR extends FilterResult, T>
  void filter2(ACComparator<? super WrappedFilterResult<? super T, ? super FR>> comparator) {
}

Workaround:

Pulling the offending type (ACComparator<...etc> in this case) into a generic type argument seems to get past this issue for Eclipse.

public static
< FR extends FilterResult, T,
  A extends ACComparator<? super WrappedFilterResult<? super T, ? super FR>> // <-- here
>
void filterSuccess(A comparator) {
    // success!
    filter1(comparator);
    filter2(comparator);
}
xtratic
  • 4,600
  • 2
  • 14
  • 32
  • 1
    Alright, that confirmes the suspicion. So how can we speak the language of the Eclipse JDT compiler / workaround this? If that is even possible? – n247s Dec 28 '18 at 19:55
  • 1
    Well eclipse seemed to have issue with the `ACComparator` so I'm looking into what I can do with that. – xtratic Dec 28 '18 at 19:57
  • 2
    Many thanks for the fast and indepth research! Would this be material for an eclipse bug-report? If so and no one is doing anything with this I'll throw a report on their bugtracker in the upcomming week (after finnishing current stuff). Otherwise feel free to do so – n247s Dec 28 '18 at 20:06
  • 1
    Absolutely send a bug report, this is quite a significant issue imo. You might include the other question I linked in here as well, since it's somewhat related. – xtratic Dec 28 '18 at 20:08
  • 1
    submited at [bugzilla from eclipse](https://bugs.eclipse.org/bugs/show_bug.cgi?id=543081) – n247s Dec 28 '18 at 22:21
  • 1
    Please be careful in your reasoning. Eclipse complains about an incompatibility involving a wildcard capture. Thus the example could also be affected by a long-standing bug in javac: https://bugs.openjdk.java.net/browse/JDK-8016207 - blaming either side without closely consulting JLS should be avoided. – Stephan Herrmann Dec 30 '18 at 18:10
  • @StephanHerrmann You are correct, I had not consulted JLS, this answer was based on the assumption that javac 8u112 was correct and also based on the assumption that a method should be able to call itself with the same arguments without a compile error. I will edit the answer to reflect these assumptions. Thank you for looking into this, and sorry for incorrectly suggesting to include both cases in the potential-bug report. – xtratic Dec 30 '18 at 23:54
  • 1
    I noticed (eventhough its not pretty, and defenitly not recommended) that using a rawtype-cast will also get past the eclipse compiler (when its configured to ignore rawtypes of course). – n247s Jan 04 '19 at 18:30
  • 1
    It turned out to be a bug in ecj indeed (present since Java 8), fixed via https://bugs.eclipse.org/543128. No connection could be found to the other problem linked in this answer. – Stephan Herrmann Jan 05 '19 at 00:26
1

Seems like that is the bug. At list Idea doesn't show any errors on that code.

The problem is in this new ArrayList<>() in the line

return filter(check, elements, new ArrayList<>(), converter, filter, comparator);

If we replace it with result variable, defined as

List<? super WrappedFilterResult<? super T, FR>> result = new ArrayList<>();

it is easier to see that result is appropriate argument for C type, where C extends Collection<? super WrappedFilterResult<? super T, FR>>.

But we should protect ourselves from unchecked assignment somehow...

Anyway, may be there is any possibility to simplify this code? Since it's readability and therefore maintainability is something arguable...