Bug 100293 - 1.5 compiler - Methods using non-generic inner types of concreted generic classes generate wrong signatures
Summary: 1.5 compiler - Methods using non-generic inner types of concreted generic cla...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.1   Edit
Hardware: PC Windows XP
: P3 critical (vote)
Target Milestone: 3.1 RC3   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-06-15 16:10 EDT by Steven Tamm CLA
Modified: 2005-06-16 14:51 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Steven Tamm CLA 2005-06-15 16:10:52 EDT
RC2 isn't correctly generating methods signatures for methods involving the
concrete non-static inner class of a generic method.  

The problem is that ParameterizedTypeBinding is being initialized with a zero
length number of arguments, but every test inside that class is testing for
null.  Since the arguments are substituted from a MemberTypeBinding which uses
TypeConstants.NoTypeVariables, ParameterizedTypeBinding is being initialized
with a zero length array for its arguments which causes the following problem.

If you have the following classes in different files
public class Parent<K extends Parent.Key> {
    public abstract static class Key {
         public abstract String getName();
    }
    public class Holder();
}

Methods that refer to Holder are sometimes generating method signatures of the form

(LParent<LKey;>.Holder<>;)V

The Holder<> is incorrect and causes all of my code that refers to the inner
class to break.  However, I'm finding it nearly impossible to create a reduction
for this test case.  But I tracked it down to
internal.compiler.lookup.ParameterizedTypeBinding.genericTypeSignature (line330)
is testing for this.arguments != null.  this.arguments is set to a zero length
array for the inner type.  

Tracing back, it seems that the problem is in Scope.substitute in the case
Binding.GENERIC_TYPE. The originalGenericType is a MemberTypeBinding which has
it's typeVariable set to NoTypeVariables.  This is being directly substituted
into the ParamaterizedTypeBinding.

The quickest fix for me was to change ParameterizeTypeBinding.initialize() to
test for someArguments != null && someArguments.length > 0.  However this is
probably just a symptom.
Comment 1 Philipe Mulet CLA 2005-06-15 16:21:25 EDT
Good find. This is another symptom of bug 98322, however the consequence is more
drastic.

Need to investigate for RC3.
Comment 2 Steven Tamm CLA 2005-06-15 16:31:58 EDT
It's very much related to 98322, When I try the proposed fix for 98322, it still
fails because someArguments != null, but someArguments.length == 0.
Comment 3 Philipe Mulet CLA 2005-06-15 18:25:26 EDT
I would fix both at once.

Reproducing test would be:
public class X<K extends X.Key> {
    public abstract static class Key {
         public abstract String getName();
    }
    public class Holder {}
    X<K>.Holder foo() { return null; }
    
    static void bar() {
    	Object o = new X<Key>().foo();
    	class Local<U> {
    		X<Key>.Holder field;
    	}
    }
}

The generic signature for 'field' gets the offending trailing '<>' incorrectly.
I am enclined to think that the fix should occur in code performing the
substitution (Scope) since it shouldn't rely on ParameterizedTypeBinding to
clear the mess. Senders have to behave.
Comment 4 Philipe Mulet CLA 2005-06-15 18:29:42 EDT
Problem comes from a caching issue. In order to cause grief, the offending
parameterized type needs to get cached before it gets used elsewhere in a
visible spot where its signature would get corrupted and persisted in some
classfile construct.

1)    	Object o = new X<Key>().foo();

   performs the offending substitution from X<K>.Holder (for msg return  
   type)into: X<Key>.Holder, and caches it.

2)
    	class Local<U> {
    		X<Key>.Holder field;
    	}
    finds binding for 'X<Key>.Holder' already in the cache (as it treats 0 arg 
    as if null), and thus reuses it.

From thereon offending binding (and thus signature) can get persisted into a
classfile.
Comment 5 Philipe Mulet CLA 2005-06-15 19:11:28 EDT
+1 for RC3

Dani - pls cast your vote. Without a fix for it, we generate bogus signatures
which can break incremental compile or tooling rendering signatures.
Comment 6 Philipe Mulet CLA 2005-06-15 19:12:03 EDT
(Forgot to CC Dani)
Dani - pls cast your vote. Without a fix for it, we generate bogus signatures
which can break incremental compile or tooling rendering signatures.
Comment 7 Philipe Mulet CLA 2005-06-15 19:14:06 EDT
Added GenericTypeSignatureTest#test019
Comment 8 Dani Megert CLA 2005-06-16 01:41:43 EDT
+1 for 3.1 RC3.
Comment 9 Philipe Mulet CLA 2005-06-16 05:56:23 EDT
Fixed
Comment 10 Olivier Thomann CLA 2005-06-16 14:51:01 EDT
The signature of the field is:
  // Signature: LX<LX$Key;>.Holder;

instead of:
  // Signature: LX<LX$Key;>.Holder<>;
using RC2.

Verified using N20050616-0010 + JDT/Core HEAD