Bug 110811 - [1.5] Raw type binding for reference to non-generic type
Summary: [1.5] Raw type binding for reference to non-generic type
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.2   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.2 RC1   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 110594
  Show dependency tree
 
Reported: 2005-09-27 11:04 EDT by Markus Keller CLA
Modified: 2006-04-13 10:18 EDT (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Keller CLA 2005-09-27 11:04:14 EDT
I20050923-1000

We have an issue with raw references to a non-generic inner type of a generic type.

public class NodeList<E> {
    public class Cursor { }

    private Cursor raw;
      // wrong non-generic type binding (bug 110806: declaring class is generic)
    
    private NodeList.Cursor rawQualified;
      // raw type binding (an issue for bug 110594)
    
    private NodeList<E>.Cursor parameterized;
      // non-generic type binding, only declaring class is generic (bug 80472)
    
    private NodeList<String>.Cursor parameterizedString;
      // non-generic type binding, only declaring class is parameterized
}

Currently, the javadoc of ITypeBinding#getTypeDeclaration() says that for raw
and parameterized types, it "[..] returns the binding for the corresponding
generic type. For other type bindings, this returns the same binding."

The type of "NodeList.Cursor rawQualified;" is a raw type, whose
getTypeDeclaration() is a non-generic type. This contradicts the javadoc and
confuses clients who assume they always get a generic type from a raw type (e.g.
our bug 110594).

I see that "NodeList.Cursor rawQualified;" is in a way "raw", and that it must
be a different binding than the declaration of Cursor.

IMO, the declaration of Cursor should be a generic binding (without type
parameters, since these are only declared by the enclosing type NodeList).

The alternative would be to make NodeList.Cursor in "NodeList.Cursor
rawQualified;" a non-generic type. But then we would have to update the spec of
getTypeDeclaration() to also explain that it does not necessarily return the
same type for non-generic types.
Comment 1 Markus Keller CLA 2005-11-17 15:00:08 EST
State in I20051116-1332 + jdt.core from HEAD (bug 80472 fixed):

public class NodeList<E> {
    public class Cursor { }

    private Cursor simple;
    private NodeList<E>.Cursor parameterized;
    private NodeList<String>.Cursor parameterizedString;
    // type is non-generic, declaring class is parameterized
    // type declaration of type is non-generic, declaring class is generic
    
    private NodeList.Cursor rawQualified;
    // type is raw, declaring class is raw
    // type is declaration of type is non-generic, declaring class is generic
}

2 issues remaining:

(A) The first group violates the contract of ITypeBinding#getTypeDeclaration(),
which states that for non-generic types, the same binding is returned
=> I don't see a solution other than updating the spec to tell that a different
non-generic binding will be returned when one of the declaring types/methods was
parameterized.

(B) The 'NodeList.Cursor rawQualified' case also violates the contract for 
ITypeBinding#getTypeDeclaration(), since it doesn't return a generic type for
the raw target.
=> Here, the kind of the type binding should be changed to a non-generic type,
whose declaring class is a raw type. Like in (A), the type declaration should be
a different non-generic type, whose declaring class is a generic type.

The type declarations for all kinds of type references to Cursor are currently
correct and identical to the binding we get from the declaration.
Comment 2 Philipe Mulet CLA 2006-04-04 06:58:04 EDT
Olivier - pls align the spec with the implementation along the lines described by Markus. 
Comment 3 Olivier Thomann CLA 2006-04-04 11:38:44 EDT
Would this be fine?

/**
 * Returns the binding for the type declaration corresponding to this type
 * binding.
 * <p>For parameterized types ({@link #isParameterizedType()}),
 * this method returns the binding for the corresponding generic type.</p>
 * <p>For raw types ({@link #isRawType()}), the type declaration is a different
 * non-generic type, whose declaring class is a generic type.</p>
 * <p>A different non-generic binding will be returned when one of the declaring
 * types/methods was parameterized.</p>
 * <p>For other type bindings, this returns the same binding.</p>
 *
 * @return the type binding
 * @since 3.1
 */
Comment 4 Markus Keller CLA 2006-04-05 06:31:53 EDT
JLS3 4.8 specifies that a member type reference is raw if its declaring type is raw (regardless of the member type's parameterization). This supports the current implementation and speaks against the change I proposed in (B), so a javadoc update should be enough.

The proposal in comment 3 does not tell about the case where a raw type is not a member type. I'd propose this change:

/**
 * Returns the binding for the type declaration corresponding to this type
 * binding.
 * <p>For parameterized types ({@link #isParameterizedType()})
 * and most raw types ({@link #isRawType()}), this method returns the binding
 * for the corresponding generic type.</p>
 * <p>For raw member types ({@link #isRawType()}, {@link #isMember()})
 * of a raw declaring class, the type declaration is a generic or a non-generic
 * type.</p>
 * <p>A different non-generic binding will be returned when one of the declaring
 * types/methods was parameterized.</p>
 * <p>For other type bindings, this returns the same binding.</p>
 *
 * @return the type binding
 * @since 3.1
 */
public ITypeBinding getTypeDeclaration();
Comment 5 Olivier Thomann CLA 2006-04-05 13:47:44 EDT
Fixed and released in HEAD.
Thanks Markus.
Comment 6 David Audel CLA 2006-04-13 10:18:02 EDT
Verified for 3.2 RC1 using build I20060413-0010