Skip to content

UnnecessaryExplicitTypeArguments incorrectly removes type parameter needed for dependent type parameters. #783

Description

@motlin

The UnnecessaryExplicitTypeArguments recipe incorrectly removed an explicit type parameter in a location where it was necessary (specifically, a method with type parameters where one type parameter extends another).

Minimal Reproduction

import java.util.Comparator;
import java.util.List;

public class MinimalReproOpenRewriteBug {

    /**
     * A method with stricter type bounds than standard Java APIs.
     * The type parameter S extends T, which requires explicit type specification
     * when T cannot be inferred from the Comparator argument alone.
     */
    public static <T, S extends T> Comparator<Iterable<S>> lexicographical(Comparator<T> comparator) {
        return (list1, list2) -> {
            var it1 = list1.iterator();
            var it2 = list2.iterator();
            while (it1.hasNext() && it2.hasNext()) {
                int cmp = comparator.compare(it1.next(), it2.next());
                if (cmp != 0) {
                    return cmp;
                }
            }
            return Boolean.compare(it1.hasNext(), it2.hasNext());
        };
    }

    // This works - explicit type parameter
    private static final Comparator<Iterable<Integer>> WORKS =
        lexicographical(Comparator.<Integer>naturalOrder());

    // This fails to compile - type parameter removed by OpenRewrite
    private static final Comparator<Iterable<Integer>> FAILS =
        lexicographical(Comparator.naturalOrder());

    record Example(List<Integer> numbers) implements Comparable<Example> {
        private static final Comparator<Example> COMPARATOR =
            Comparator.comparing(Example::numbers, WORKS);

        @Override
        public int compareTo(Example other) {
            return COMPARATOR.compare(this, other);
        }
    }
}

OpenRewrite should preserve the explicit type parameters here. What actually happened it changed:

Comparator.<Integer>naturalOrder()

to:

Comparator.naturalOrder()

This causes the compilation error:

MinimalReproOpenRewriteBug.java:50: error: method lexicographical in class MinimalReproOpenRewriteBug cannot be applied to given types;
        lexicographical(Comparator.naturalOrder());
        ^
  - required: Comparator<T#1>
  - found:    Comparator<T#2>
  - reason: inference variable S has incompatible upper bounds T#3,Comparable<? super T#3>,Object,T#1
  - where T#1,S,T#2,T#3 are type-variables:
    - T#1 extends Object declared in method <T#1,S>lexicographical(Comparator<T#1>)
    - S extends T#1 declared in method <T#1,S>lexicographical(Comparator<T#1>)
    - T#2 extends Comparable<? super T#2>
    - T#3 extends Comparable<? super T#3> declared in method <T#3>naturalOrder()
1 error

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No fields configured for Bug.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions