Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 339478

Summary: [1.7][compiler] support for diamond case
Product: [Eclipse Project] JDT Reporter: Ayushman Jain <amj87.iitr>
Component: CoreAssignee: Srikanth Sankaran <srikanth_sankaran>
Status: VERIFIED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: daniel_megert, deepakazad, markus.kell.r, Olivier_Thomann, satyam.kandula, srikanth_sankaran
Version: 3.7Flags: amj87.iitr: review+
Target Milestone: 3.7.1   
Hardware: All   
OS: All   
Whiteboard:
Attachments:
Description Flags
fix v1.0
none
proposed fix v1.1
none
proposed fix v2.0 + tests
none
proposed fix v2.1 + tests
none
proposed fix v2.2 + tests
none
Patch under consideration
none
Revised patch for rejecting ill formed programs
none
Unreviewed remaining patch fragment
none
Unreviewed remaining patch fragment
none
Unreviewed remaining patch fragment
none
<> Implementation - Phase I
none
Revised Implementation v0.9
none
Revised Implementation v0.95
none
Revised Implementation v0.97
none
Revised Implementation v0.98
none
Revised Implementation v1.0
none
Revised Implementation with tests v1.0 none

Description Ayushman Jain CLA 2011-03-10 04:09:23 EST
With the current contents of BETA_JAVA7 stream, a simple declaration using the diamond semantics fails to compile
public Test<T> {
    public void foo() {
       Test<String> test = new Test<>();
    }
}

The grammar and parsing is correct, issues arise during resolution wherever Test<String> is expected and Test<> is obtained instead.

I'm looking into this.
Comment 1 Ayushman Jain CLA 2011-03-10 07:28:05 EST
Created attachment 190845 [details]
fix v1.0

These are the changes required to make the most basic case work, i.e. class instance creation where the class has only the default constructor.

Other complex cases still don't work. The  updated substitution algorithm will have to be implemented to find out the correct constructor.
Comment 2 Ayushman Jain CLA 2011-03-16 14:47:07 EDT
Created attachment 191332 [details]
proposed fix v1.1

This patch goes a little further by making sure that all cases where <> is illegal give an error.
+ Added tests pertaining to the usage of <>, and also to verify the difference in using <> vs. using just the raw type. Some tests are currently disabled because this patch does not implement the substitution mechanism to find the correct constructor, and hence leads to some exceptions.
+ Introduced a new error message for using <> in anonymous type declaration.
Also verified that we get an error on using <> in compliance 1.6 or below
Comment 3 Ayushman Jain CLA 2011-03-17 15:16:43 EDT
Created attachment 191458 [details]
proposed fix v2.0 + tests

This patch
+ Implemens, in part the strategy to find out the correct constructor. So, it successfully transfers the type argument to the class instance creation expression when used for the default constructor.
So , cases such as
ArrayList<String> a = new ArrayList<>();
a.add(""); // OK
a.add(1);  // ERROR

work as expected. Also, these work if its a qualified reference (java.util.ArrayList).

Main changes for these are in ParameterizedSingleTypeRef, ParameterizedQualifiedTypeRef and AllocationExpression.

+ Fixes stray IAE's and NPE's arising due to calls to TypeRef#getParameterizedTypeName() method by jdt.ui

+ Introduces a configurable option to warn the user when the diamond construct can be used but hasnt been used.
eg.    ArrayList<String> a = new ArrayList<String>();
                                 ^^^^^^^^^^^^^^^^^^^
will warn "Redundant declaration of type arguments <String>. See GenericsRegressionTest_1_7#test013().
Comment 4 Ayushman Jain CLA 2011-03-17 15:18:31 EDT
Changes in comment 3 are in addition to those in comment 2.
Comment 5 Ayushman Jain CLA 2011-03-22 15:09:42 EDT
Created attachment 191707 [details]
proposed fix v2.1 + tests

Improved patch. Fixed some bugs with the previous patch. Added more tests
Comment 6 Srikanth Sankaran CLA 2011-03-23 07:36:30 EDT
I have started looking into this. Ayush, to simplify matters and
help retain focus, I would like to see two changes:

(1) Move all changes relating to OPTION_ReportRedundantDeclarationOfTypeArguments
to a separate bug. I am not even sure at this point we want to support such
an option, but that discussion can come later. Let us retain the current bug
for the core of the <> implementation and relegate various and sundry items
to their own bug.

(2) Similarly I would like to see the changes in CompilerInvocationTests.java
that are not pertinent to <> to be separated out. In this case, if the other
changes are only in the nature of cleanup (i.e, change based on sort order),
you can release them already assuming they pass the tests and post a new patch
on top of it.

(3) Anything else that is not germane to the core of <>, similarly can be moved
out.

Please post an updated patch, so I can start the review.
Comment 7 Srikanth Sankaran CLA 2011-03-23 07:40:15 EDT
(In reply to comment #6)
> I have started looking into this. Ayush, to simplify matters and
> help retain focus, I would like to see two changes:

I would also consider folding org.eclipse.jdt.core.tests.compiler.regression.GenericsRegressionTest_1_7
into org.eclipse.jdt.core.tests.compiler.regression.GenericsRegressionTest.

If necessary we can always skip some tests in 1.6- modes by
	if (this.complianceLevel < ClassFileConstants.JDK1_7)
		return;
Comment 8 Ayushman Jain CLA 2011-03-23 15:17:19 EDT
Created attachment 191785 [details]
proposed fix v2.2 + tests

Apart from the changes mentioned in comments 6 and 7 above, this patch:
+ Adds support for the following case:
class X<T> {
    X(T t) {}
    X(T t, Integer i){}
    public static void main(String[] args) {
         X x1 = new X<>("");
         X x2 = new X<>("",1);
    }
}

(The earlier patched threw an NPE).
Note that the type for x1 and x2 remains as X, and not X<String>. This is consistent with the current javac ( version b134) behaviour, although I think according to spec it should be inferred as X<String>
+ Adds more tests, especially for scenarios in which diamond is used for field initializations.
Comment 9 Srikanth Sankaran CLA 2011-03-24 01:46:32 EDT
(In reply to comment #8)
> Created attachment 191785 [details]
> proposed fix v2.2 + tests
> 
> Apart from the changes mentioned in comments 6 and 7 above, this patch:

Ayush, are all the changes in CompilerInvocationTests.java relevant
for <> implementation ? When reviewing a large patch, including changes
that are not relevant only serves to distract.

Any changes that are clean up in nature can be handled separately ?
Let me know if I have misunderstood something here.
Comment 10 Srikanth Sankaran CLA 2011-03-24 02:08:28 EDT
> Any changes that are clean up in nature can be handled separately ?
> Let me know if I have misunderstood something here.

[Ayush explained that while these changes are not relevant, they come
about because of the way test suite  emits expected output, so we will
live with it.]
Comment 11 Srikanth Sankaran CLA 2011-03-24 09:45:24 EDT
As a first order business, we should focus on correctly and
gracefully rejecting all ill-formed programs.

This requires us to 

(a) Report errors properly in a 1.6- program if the use of <> is encountered.
(b) Report errors properly in a 1.7+ program if the use of <> is encountered
in non-ClassInstanceCreationExpression's.

The patch as it stands now has several problems in this area. I'll try and
propose a patch that tweaks the grammar in such a way that we can cleanly
reject all ill formed programs in a central place rather than checking all
over.

Here are some problems I encountered while working with the current patch:

(1) The following program fails with an internal compiler error
due to AIOOB.

import java.util.Map;
public class X implements Map<> {
	static Map<> foo (Map<> x) { 
		return null;
	}
}
 
(2) The following program compiles successfully, while
it should not.

import java.util.Map;
public class X  {
	static Map<> foo () { 
		return null;
	}
}

(3) The following program compiles successfully while
it should not.

public class X<T>  {
	class Y<K> {
	}
	public static void main(String [] args) {
		X<String>.Y<> [] y = null; 
	}
}

(4) The following illegal program results in an NPE in the
compiler.

public class X<T>  {
	class Y<K> {
	}
	public static void main(String [] args) {
		X<String>.Y<>  y = null; 
	}
}

(5) The following program compiles without an error while it
should not compile.

public class X<T>  {
	public void foo(Object x) {
		if (x instanceof X<>) {	
		}
	}
}

(6) The following program compiles without an error while it
should not compile.

public class X<T>  {
	public void foo(Object x) throws X.Y<>.LException {
	}
	
	static class Y<T> {
	static class LException extends Throwable {}
	}
}

(7) I am not sure if this is supposed to be compiled (javac also does)

public class X<T>  {
	public void foo () {
		Object o = new X<> [10];
	}
}


I am sure there are many more cases like this. If you are curious,
I started with the grammar and derived some strings which will
contain <> in productions having nothing to do with class instance
creation.
Comment 12 Srikanth Sankaran CLA 2011-03-24 13:36:06 EDT
(In reply to comment #11)

[...]

> The patch as it stands now has several problems in this area. I'll try and
> propose a patch that tweaks the grammar in such a way that we can cleanly
> reject all ill formed programs in a central place rather than checking all
> over.

This shouldn't really require a grammar change. Our job is not really to
reject <> in all places where it shouldn't feature (which 1.6 mode *already*
does anyway) but rather to selectively allow <> in the class instance creation
expressions only.

Patch under test.
Comment 13 Srikanth Sankaran CLA 2011-03-25 01:37:19 EDT
(In reply to comment #11)

> (7) I am not sure if this is supposed to be compiled (javac also does)
> 
> public class X<T>  {
>     public void foo () {
>         Object o = new X<> [10];
>     }
> }

I think this is a bug in both eclipse & javac (7b131 - I didn't test
with a later version). Since

    Object o = new X<String> [10];

(for example) is anyway wrong in attempting to create a generic array.
Simply having the compiler infer the generic argument does not make it
acceptable.
Comment 14 Srikanth Sankaran CLA 2011-03-25 05:26:06 EDT
Created attachment 191891 [details]
Patch under consideration

This patches fixes all the issues mentioned in
https://bugs.eclipse.org/bugs/show_bug.cgi?id=339478#c11 and
includes regression tests for them.

This patch is under test.

With this code change we should correctly reject all illegal uses
of <> since we really rely on the 1.6- error reporting behavior and
short circuit that ONLY when we are absolutely sure <> constitutes
diamond and not merely missing type parameters.

This is achieved by marking a type as diamond IFF:

    - it is a 1.7+ program
    - <> occurs in the class instance creation expression not
      involving anonymous types (where the use of <> is precluded
      by the spec).
    - and nowhere else.

This patch also integrates the tests added to 
GenericsRegressionTest.java by the patch at
https://bugs.eclipse.org/bugs/show_bug.cgi?id=339478#c8
(but not the changes introduced by that patch to
GenericsRegressionTest_1_7.java yet)

This patch obviates the need for the changes made by the
prior patch to the following elements:

    - IProblem.java
    - ProblemReporter.java
    - messages.properties
    - CompilerInvocationTests.java
    - SourceTypeBinding.java

See that while this patch is expected to reject all ill formed
programs, it implements very little behavior for well formed
programs that use diamond. So such programs may and will trigger
all manner of problems from the compiler as of now.
Comment 15 Srikanth Sankaran CLA 2011-03-25 07:03:02 EDT
Created attachment 191902 [details]
Revised patch for rejecting ill formed programs

(In reply to comment #14)
> Created attachment 191891 [details]
> Patch under consideration

> This patch is under test.
> 
> With this code change we should correctly reject all illegal uses
> of <> since we really rely on the 1.6- error reporting behavior and
> short circuit that ONLY when we are absolutely sure <> constitutes
> diamond and not merely missing type parameters.

Same patch as before, with improved comments. Also includes a fix
to a DOM/AST test that was failing with the earlier patch.

Passes all JDT/Core tests. Ayush, please review.

Basically, all <> is guilty unless proven innocent and deemed innocent
only if 1.7+ and only if used class instance creation that doesn't involve
an anonymous class.

Ayush, please review, TIA.

If this patch looks alright, I'll release it and can you prepare patch
that contains the rest of the changes from your patch and post it, so
we can continue with the review ? Thanks.
Comment 16 Ayushman Jain CLA 2011-03-25 09:07:07 EDT
(In reply to comment #15)
> Created attachment 191902 [details] [diff]
> Revised patch for rejecting ill formed programs

Patch looks good.
Comment 17 Ayushman Jain CLA 2011-03-25 09:12:52 EDT
(In reply to comment #16)
> (In reply to comment #15)
> > Created attachment 191902 [details] [diff] [details] [diff]
> > Revised patch for rejecting ill formed programs
> 
> Patch looks good.

Released this patch in BETA_JAVA7 branch
Comment 18 Srikanth Sankaran CLA 2011-03-25 18:44:51 EDT
Created attachment 191946 [details]
Unreviewed remaining patch fragment

The portion of Ayush's patch yet to be reviewed is
attached.

I released GenericsRegressionTest_1_7.java from the original
patch after :

    - Moving negative tests that should be run in all modes to
      GenericsRegressionTest.java and

    - Disabling the failing tests.
Comment 19 Srikanth Sankaran CLA 2011-03-25 18:56:14 EDT
Created attachment 191947 [details]
Unreviewed remaining patch fragment

Minimal patch.
Comment 20 Srikanth Sankaran CLA 2011-03-28 05:17:22 EDT
Created attachment 191984 [details]
Unreviewed remaining patch fragment

This patch 

    - Gets rids of the changes in:

        TypeBinding.java,
        ReferenceBinding.java
        LocalDeclaration.java
        FieldDeclaration.java

   - Fixes some issues in QualifiedAllocationExpresssion.java
   - Various cleanups.
   - Enables all the tests in GenericsRegressionTest1_7.java
     that were disabled earlier - all of these pass now.

   - Is still largely unreviewed though.
Comment 21 Srikanth Sankaran CLA 2011-03-28 06:01:46 EDT
The following program fails to compile correctly (javac 7b135 does).
Basically, there is no need for the arity of type arguments to be the
same on LHS and RHS. See that code completions works as expected (i.e
infers correctly).

// ---------------------------8<-------------------------
import java.util.HashMap;
import java.util.Map;

class StringKeyHashMap<V> extends HashMap<String, V>  {  
}

class IntegerValueHashMap<K> extends HashMap<K, Integer>  {  
}

public class X {
	Map<String, Integer> m1 = new StringKeyHashMap<>();
	Map<String, Integer> m2 = new IntegerValueHashMap<>();
}
Comment 22 Srikanth Sankaran CLA 2011-03-28 22:12:45 EDT
Created attachment 192058 [details]
<> Implementation - Phase I

I have reviewed all the changes made by Ayush and the current
patch is a cleaned up version of the uncommitted changes.

    - Cleaned up the APIs around org.eclipse.jdt.internal.compiler.ast.SingleTypeReference.resolveTypeEnclosing(BlockScope, ReferenceBinding, TypeBinding) and org.eclipse.jdt.internal.compiler.ast.TypeReference.resolveType(BlockScope, boolean, TypeBinding) to take the expected type as a parameter instead of
just the type arguments to be used for inference. This is going to necessary
to handle inference in all but the most trivial cases.

    - Copyright message changes, improved comments, fixed new warning introduced
by patch etc.

    - Got rid of dead code, various redundant checks etc.

    - Enabled all but two of the tests in GenericsRegressionTest1_7.java.

    - I withheld the code changes in ParameterizedTypeBinding. These bindings
are to be shared across the AST and so storing any data in these bindings
that is not shared is a bad idea. As a consequence, we have a couple of
test failures, these need to be looked into.

With these changes, we have a basic if naive implementation in place.
The current code simply transfers type arguments from the expected type
to the class instance creation expression. This works ok in straightforward
cases where the class instance creation expression is isomorphic with respected
to the expected type (i.e, same type, or a sub type with the same arity of
type arguments with type arguments at each type level being used to parameterize
the super type.)

Next steps:

    - Study the spec closely to make sure the implementation conforms
      fully to the spec.
    - Generalize the implementation to handle complext cases a la
      https://bugs.eclipse.org/bugs/show_bug.cgi?id=339478#c21
    - Fix the two remaining failures in GRT17.java


Released in BETA_JAVA7 branch.
Comment 23 Srikanth Sankaran CLA 2011-03-29 07:07:53 EDT
I have enabled all the tests and released it into BETA_JAVA7 branch.

Ayush, on the following tests we differ in behavior from javac: 

test001f
test001g
test001i
test007
test008
test0016
test0016b
test0017


some of these were disabled earlier, while some were not. Did you analyze
the case and conclude if eclipse behavior was the reasonable thing ?

I'll investigate these differences.
Comment 24 Ayushman Jain CLA 2011-03-29 10:39:14 EDT
(In reply to comment #23)
> Ayush, on the following tests we differ in behavior from javac: 
> 
> test001f
> test001g
> test001i
> test007
> test008
> test0016
> test0016b
> test0017

All of these except test007 and test008 are, IMHO, cases where the type args can be easily inferred, and I think javac is currently missing the full implementation. Thats why they currenly differ with javac7

Test007 and test008 show the semantic difference between using the diamond case in the instantiation vs. using the raw type, as I inferred from the spec and javac behaviour. I had disabled them because currently we give an incorrect output for these cases. Javac7's output is correct. They should be re-disabled.
Comment 25 Srikanth Sankaran CLA 2011-03-29 23:15:21 EDT
(In reply to comment #24)
> (In reply to comment #23)
> > Ayush, on the following tests we differ in behavior from javac: 
> > 
> > test001f
> > test001g
> > test001i
> > test007
> > test008
> > test0016
> > test0016b
> > test0017
> 
> All of these except test007 and test008 are, IMHO, cases where the type args
> can be easily inferred, and I think javac is currently missing the full
> implementation. Thats why they currenly differ with javac7

In that case, I would have preferred that we had documented that list
here rather than merely making these tests pass with the current
eclipse behavior.

OK, in anycase we have the list now and I'll see what can be done.
Comment 26 Srikanth Sankaran CLA 2011-04-10 07:00:39 EDT
(In reply to comment #22)

> Next steps:
> 
>     - Study the spec closely to make sure the implementation conforms
>       fully to the spec.

At least after a cursory reading, it appears that the current implementation
is way off - There is no notion of "expected type" from the assignment
context influencing the inference in the specification.

I'll follow up on this.
Comment 27 Srikanth Sankaran CLA 2011-04-19 06:42:58 EDT
Comment on attachment 192058 [details]
<> Implementation - Phase I

I have reversed this patch. As noted earlier, this implementation using "expected type" from assignment context is incorrect and doesn't conform to the specifications.
Comment 28 Srikanth Sankaran CLA 2011-04-19 06:45:04 EDT
(In reply to comment #24)
> (In reply to comment #23)
> > Ayush, on the following tests we differ in behavior from javac: 
> > 
> > test001f
> > test001g
> > test001i
> > test007
> > test008
> > test0016
> > test0016b
> > test0017
> 
> All of these except test007 and test008 are, IMHO, cases where the type args
> can be easily inferred, and I think javac is currently missing the full
> implementation. Thats why they currenly differ with javac7

javac implementation is in place and the differences are due to
eclipse not implementing the spec. Working on this.
Comment 29 Srikanth Sankaran CLA 2011-04-21 16:40:22 EDT
Created attachment 193887 [details]
Revised Implementation v0.9


While this will undergo quite a bit of cleanup, bug fixing, polish
and code reorganization (most of the functionality is now in 
compiler.ast while it logically belongs in compiler.lookup), the
current patch has the meat of the revised implementation in place
and working well.

org.eclipse.jdt.internal.compiler.ast.AllocationExpression.inferElidedTypes(ReferenceBinding, TypeBinding[], BlockScope) has the new implementation.

All but 8 (new) tests pass. Even these tests likely need remastering
(see comment# 23).

QualifiedAllocationExpression and ParameterizedQualifiedTypeReference
may have to undergo similar changes as done in AllocationExpression and
ParameterizedSingleTypeReference.

I can see the light at the end of the tunnel, folks !
Comment 30 Srikanth Sankaran CLA 2011-04-22 00:42:42 EDT
Created attachment 193901 [details]
Revised Implementation v0.95

More progress. With this patch, we have only 3 tests that
fail in the JDT/Core test suite, all of them having explicit
type arguments at the generic constructor invocation site.
Comment 31 Srikanth Sankaran CLA 2011-04-22 09:11:26 EDT
Interestingly javac 7b137 rejects the following program:

public class X<T> {
	<E> X(){
	}
	X<String> x = new <String>X<>(); 
}

with : 

C:\jtests>C:\jdk-7-ea-bin-b137-windows-i586-07_apr_2011\jdk7\jdk1.7.0\bin\javac
-Xlint:unchecked -Xlint:rawtypes -Xlint:deprecation -sourcepath c:\jtests X.java

X.java:4: error: cannot infer type arguments for X<>;
        X<String> x = new <String>X<>();
                      ^
  reason: actual and formal argument lists differ in length
1 error


Looks like a bug in javac.
Comment 32 Srikanth Sankaran CLA 2011-04-22 11:59:41 EDT
Created attachment 193918 [details]
Revised Implementation v0.97

This patch fixes all known issues. All tests are enabled now
and are passing. The behavior compares favorably with javac
7b137.

GenericsRegressionTest_1_7.test0016()
GenericsRegressionTest_1_7.test0016b()
GenericsRegressionTest_1_7.test0017()

are the only tests where eclipse behavior differs from
javac. In these cases, I believe javac is the one that
is buggy (see comment# 31)
Comment 33 Srikanth Sankaran CLA 2011-04-23 03:50:16 EDT
Created attachment 193951 [details]
Revised Implementation v0.98

Same patch as before, but is minimal so easier to review.
Ayush, no need to review yet, but you are welcome to glance
through it - I'll send a review request after some more
testing, clean up and reorganization of the code.
Comment 34 Srikanth Sankaran CLA 2011-04-24 03:02:30 EDT
(In reply to comment #31)
> Interestingly javac 7b137 rejects the following program:

[...]

> Looks like a bug in javac.

We have confirmation from Oracle that this is a javac bug (bug number
7030150, supposedly fixed in 7b138)
Comment 35 Srikanth Sankaran CLA 2011-04-24 03:56:55 EDT
Created attachment 193962 [details]
Revised Implementation v1.0

Cleaned up implementation.
Comment 36 Srikanth Sankaran CLA 2011-04-24 03:57:46 EDT
Created attachment 193963 [details]
Revised Implementation with tests v1.0

Earlier patch was just sources. Current one includes tests.
Comment 37 Srikanth Sankaran CLA 2011-04-24 03:59:53 EDT
Ayush, please review. TIA. I'll be releasing this shortly into
the BETA_JAVA7 branch. Apart from review, I would also request
you to verify the implementation - TIA,
Comment 38 Srikanth Sankaran CLA 2011-04-24 07:07:27 EDT
The <> inference implementation is complete. All JDT/Core tests pass.
Implementation compares favorably with javac 7b137. Released patch 
into BETA_JAVA7 branch.

Ayush, please raise separate follow up defects for any issues uncovered
during code review and verification - Thanks.
Comment 39 Srikanth Sankaran CLA 2011-04-25 05:29:34 EDT
(In reply to comment #32)

> GenericsRegressionTest_1_7.test0016()
> GenericsRegressionTest_1_7.test0016b()
> GenericsRegressionTest_1_7.test0017()
> 
> are the only tests where eclipse behavior differs from
> javac. In these cases, I believe javac is the one that
> is buggy (see comment# 31)

Verified that eclipse compiler's behavior is identical to
javac 7b138's behavior.
Comment 40 Ayushman Jain CLA 2011-05-24 07:08:39 EDT
The patch is good. A few fup defects found have been raised in bug 345968 and bug 346959.
Comment 41 Olivier Thomann CLA 2011-06-28 09:34:00 EDT
Comment 31 is rejected by both Eclipse compiler and javac.
Verified.