United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-5060485 : The scope of a class type parameter is too wide

Details
Type:
Bug
Submit Date:
2004-06-09
Status:
Closed
Updated Date:
2010-07-09
Project Name:
JDK
Resolved Date:
2011-03-08
Component:
tools
OS:
solaris_2.6
Sub-Component:
javac
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
5.0
Fixed Versions:

Related Reports
Backport:
Relates:
Relates:
Relates:

Sub Tasks

Description
Name: akR10088			Date: 06/09/2004


The JLS3 Draft 8.1.2 Generic Classes and Type Parameters reads:

The scope of a class type parameter is the entire declaration of the class,
except any static members or initializers of the class or of any classes nested within it,
but including the type parameter section itself. Therefore, type parameters can appear
as parts of their own bounds, or as bounds of other type parameters declared in the same
section.

But the following example shows that not only a class type parameter is visible
in a static member, but is not shadowed by a nested declaration.

This test compiles OK:

------------------------------ file X.java
public class X<Z> {

  static public class Y {}

  static public class Y1 <T extends X<Y>> {
  }

}
------------------------
But if we change in the 1st line "Z" to "Y", this "Y" interfere with the
name of a nested class:

------------------------------ file X.java
public class X<Y> {

  static public class Y {}

  static public class Y1 <T extends X<Y>> {
  }

}
------------------------
novo64% javac -source 1.5 X.java
X.java:5: non-static class Y cannot be referenced from a static context
  static public class Y1 <T extends X<Y>> {
                                      ^
1 error
novo64%  

The used JDK version is:

novo64% java -version
java version "1.5.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta3-b54)
Java HotSpot(TM) Client VM (build 1.5.0-beta3-b54, mixed mode)


======================================================================

                                    

Comments
SUGGESTED FIX

It turns out that the changes to Resolve.java to fix 5046972 were incorrect.
See
http://javac.sfbay/java/jdk/ws/tools/gjc/FIXES/2004/05/24/5046972/webrev/src/share/classes/com/sun/tools/javac/comp/Resolve.java.udiff.html

Part of the changes for 5046972 are fine: the local variable staticOnly is
set more correctly and that is actually enough to fix 5046972.

However, the fix for 5046972 also changes when to look at member types
which is not correct.  Type variables are not membertypes.  So the fix for
this bug is to undo some of the changes made for 5046972:

@@ -928,13 +928,8 @@
                     return e.sym;
                 }
             }
-
-            JCClassDecl encl;
-            if (env1.baseClause) {
-                encl = (JCClassDecl)env1.tree;
-            } else {
-                sym = findMemberType(env1, env1.enclClass.sym.type, name,
-                                     env1.enclClass.sym);
+            sym = findMemberType(
+                env1, env1.enclClass.sym.type, name, env1.enclClass.sym);
                 if (staticOnly && sym.kind == TYP &&
                     sym.type.tag == CLASS &&
                     sym.type.getEnclosingType().tag == CLASS &&
@@ -943,8 +938,8 @@
                     return new StaticError(sym);
                 else if (sym.exists()) return sym;
                 else if (sym.kind < bestSoFar.kind) bestSoFar = sym;
-                encl = env1.enclClass;
-            }
+
+            JCClassDecl encl = env1.baseClause ? (JCClassDecl)env1.tree : env1.enclClass;
             if ((encl.sym.flags() & STATIC) != 0)
                 staticOnly = true;
         }


An alternative view of this situation is to diff against the version
before 5046972 and the suggested fix for this bug.  There are some changes
that were caused by API changes for JSR 269 and com.sun.source.  Ignoring
this, it is clear that the fix now only is concerned with determining
if the current environment is static or not:

@@ -883,19 +932,19 @@
 		env1, env1.enclClass.sym.type, name, env1.enclClass.sym);
 	    if (staticOnly && sym.kind == TYP &&
                 sym.type.tag == CLASS &&
-                sym.type.outer().tag == CLASS &&
+                sym.type.getEnclosingType().tag == CLASS &&
                 env1.enclClass.sym.type.isParameterized() &&
-                sym.type.outer().isParameterized())
+                sym.type.getEnclosingType().isParameterized())
                 return new StaticError(sym);
             else if (sym.exists()) return sym;
 	    else if (sym.kind < bestSoFar.kind) bestSoFar = sym;
 
-	    if ((env1.enclClass.sym.flags() & STATIC) != 0 &&
-                (env1.tree.tag != Tree.CLASSDEF || env1.tree == env1.enclClass))
+            JCClassDecl encl = env1.baseClause ? (JCClassDecl)env1.tree : env1.enclClass;
+            if ((encl.sym.flags() & STATIC) != 0)
                 staticOnly = true;
 	}
 
-	if (env.tree.tag != Tree.IMPORT) {
+        if (env.tree.tag != JCTree.IMPORT) {
 	    sym = findGlobalType(env, env.toplevel.namedImportScope, name);
 	    if (sym.exists()) return sym;
 	    else if (sym.kind < bestSoFar.kind) bestSoFar = sym;
                                     
2006-10-31
SUGGESTED FIX

Webrev of changes: http://sa.sfbay/projects/langtools/bugid_summary.pl?bugid=5060485
See also attachment: 5060485.tar.gz
                                     
2006-10-31
SUGGESTED FIX

No that doesn't work, since this program must compile:

public class Method<T extends Number> {
    static class Y {}
    <Y extends Number> void test() {
        Method<Y> m = null;
        Number n = m.get();
    }
    T get() {
        return null;
    }
}
                                     
2006-10-30
SUGGESTED FIX

The solution is fairly simple: Resolve.findType looks at "any other type"
before looking at member types.  So we just rearrange the code to look
at member types before "any other type".
                                     
2006-10-30
EVALUATION

The exact words are:

"Within a class C, a declaration d of a member type named n shadows the
declarations of any other types named n that are in scope at the point
where d occurs."

http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.5

Since the compiler looks at "any other types" before it looks at
member types, it is incorrect.
                                     
2006-10-30
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
dragon
mustang


                                     
2004-09-07
EVALUATION

This is definitely a bug.  The type parameter should be shadowed, or the
shadowing should be illegal (need to check the JLS).

###@###.### 2004-06-09

The shadowing rules for type parameters are not yet in the JLS.  I'm sure
the compiler is wrong in its current behavior, but I don't know what the correct
behavior should be.  Reassigning to spec for JLS3.

For reference, here is a program that should clearly be an error, for one of
two (or more) reasons, but I don't know which:

  interface I1 {}
  interface I2 {}
  class A<T extends I1> {
    class T implements I2 {}
    void f(T t) {
      I1 i = t;
    }
  }

###@###.### 2004-06-13

JLS 8.5, Member types, states that a declaration of a  member type shadows the 
declarations of any other type of the same name that is in scope.

Hence, the compile is in error, and the smaller example above is illegal 
because if f, T referes to the member type that is a subtype of I2 not I1.


###@###.### 2004-07-09
                                     
2004-07-09



Hardware and Software, Engineered to Work Together