Bug 520048 - [1.8][inference] A type witness should not be required to call a method in a lambda when the bound is known
Summary: [1.8][inference] A type witness should not be required to call a method in a ...
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.7   Edit
Hardware: PC Mac OS X
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords: helpwanted
Depends on:
Blocks:
 
Reported: 2017-07-21 20:05 EDT by David Elliott CLA
Modified: 2022-08-10 09:46 EDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description David Elliott CLA 2017-07-21 20:05:52 EDT
This is a new bug in Oxygen; Neon is able to compile this code, as is javac.

The problem occurs when a generic class BoundedClass<T extends SomeInterface> is used in a generic mapping function (i.e. <T extends SomeInterface> T mappingFunction(BoundedClass<? extends T> bounded)) and that mapping function is called from a lambda giving it an additional parameter (in this example, only the implicit this parameter, but in our real example there are additional arguments).

Although avoidable with a type witness, or perhaps by other means, this seems like a no-brainer.

*** Steps to reproduce

import java.util.List;
import java.util.stream.Collectors;

/**
 * Demonstrates that a type witness is needlessly required in Eclipse Oxygen that wasn't
 * required in Eclipse Neon.
 * 
 * @author  David Elliott (dfe)
 */
public class BoundedTypeInferenceBug {

    List<SomeInterface> test(final List<? extends BoundedClass<?>> boundedClassList) {
        final List<SomeInterface> interfaceList = boundedClassList.stream()
                .map(bounded -> this. /* WTF --> */ <SomeInterface> /* <-- WTF */ mappingFunction(bounded))
                .collect(Collectors.toList());
        return interfaceList;
    }

    <T extends SomeInterface> T mappingFunction(BoundedClass<? extends T> bounded) {
        // In the real implementation this does something.
        return null;
    }

}

class SomeInterface {
}

class BoundedClass<T extends SomeInterface> {
}
Comment 1 Stephan Herrmann CLA 2017-07-22 03:42:53 EDT
I was about to close as WORKSFORME but then I noticed you posted the version that does compile, but deleting the type argument makes it fail :)

Status is:
- javac (version 8 and 9 ea) accept
- ecj up-to 4.6.3 accept, but 4.7 reports:

The method mappingFunction(BoundedClass<? extends T>) in the type BoundedTypeInferenceBug is not applicable for the arguments (capture#1-of ? extends BoundedClass<?>)

At this point please be warned: with wildcards and captures in the context of type inference there is no such thing as a "no-brainer".
Comment 2 David Elliott CLA 2017-07-22 04:09:09 EDT
My apologies. I've read the spec and it is indeed very hard to follow.  Nothing is a "no-brainer".

What I should have said is that "this seems like an obvious candidate for a test case".

Also my apologies for submitting the code in a state that did compile rather than in a state that did not compile.

That is the error I get when I remove the witness.  The witness clearly seems like it should not be necessary to a coder who doesn't write Java compilers-- after all, the type I need inferred for the mapping function is simply the declared bound of both BoundedClass and the mapping function itself. I'm not doing anything fancy like further constraining the bound of BoundedClass in the input List and expecting that the output list could be similarly bounded and for the compiler to properly infer the bound of the mapping function (although... I would expect that).

I can also confirm my experience that javac 8 was able to compile it, as was Eclipse Neon, but not Eclipse Oxygen.

The lingering question in my mind is whether it is lambda-specific or if a non-lambda test case could illustrate the same problem.  But I didn't want to diverge too much from the original code.
Comment 3 Stephan Herrmann CLA 2017-07-22 05:40:55 EDT
(In reply to David Elliott from comment #2)

Your test is useful indeed.

We'll look into this after (support for) Java 9 has sailed.
Comment 4 Manoj N Palat CLA 2018-05-17 03:23:05 EDT
bulk move out of 4.8
Comment 5 Manoj N Palat CLA 2018-08-16 00:08:40 EDT
Bulk move out of 4.9
Comment 6 Mat Gessel CLA 2019-11-04 18:18:29 EST
Still happens in 2019-09 R (4.13.0) • JDT 3.18.100.v20190916-1045 • tried ecj 1.8, 12.

Issue applies to regular methods too. Requires a bounded wildcard rv being used for a bounded wildcard arg.

In the following code example, only the commented statement generates an error.


//------------------

void testCovariant(Supplier<? extends BoundedClass<?>> boundedSupplier)
{
  // ERROR: The method mappingFunction(_520048.BoundedClass<? extends T>) in the type _520048 is not applicable for the arguments (capture#41-of ? extends _520048.BoundedClass<?>) _520048.java
  // type of boundedSupplier.get() is being treated as "? extends BoundedClass<?>"
  mappingFunction(boundedSupplier.get());
  
  Supplier<? extends BoundedClass<?>> bs1 = boundedSupplier;
  Supplier<? extends BoundedClass<? extends SomeInterface>> bs2 = boundedSupplier;
  bs1 = bs2;
  bs2 = bs1;
  
  BoundedClass<?> bounded = boundedSupplier.get();
  mappingFunction(bounded);
  
  mappingFunction((BoundedClass<?>) boundedSupplier.get());
  
  mappingFunction2(boundedSupplier.get());
  
  mappingFunction3(boundedSupplier.get());
}

<T extends SomeInterface> T mappingFunction(BoundedClass<? extends T> bounded) { return null; }

SomeInterface mappingFunction2(BoundedClass<? extends SomeInterface> bounded) { return null; }

SomeInterface mappingFunction3(BoundedClass<?> unbounded) { return null; }

class SomeInterface {}

class BoundedClass<T extends SomeInterface> {}

//--------------------
Comment 7 Eclipse Genie CLA 2022-08-10 09:46:16 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.