JDK-7022069 : Invalid compiler error - scoping rules
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: linux
  • CPU: x86
  • Submitted: 2011-02-24
  • Updated: 2012-03-20
  • Resolved: 2011-02-25
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b130)
Java HotSpot(TM) Server VM (build 21.0-b02, mixed mode)


A DESCRIPTION OF THE PROBLEM :
Code that previously compiled fine under JDK 1.6 no longer compiles

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Try to compile the given code

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code should compile
ACTUAL -
The code doesn't compile

ERROR MESSAGES/STACK TRACES THAT OCCUR :
cannot find symbol

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package bugs;

// Note explicit import (for this example we import from the same package, but it could be a different package)
import bugs.Type;

public class JavacBug extends javax.swing.JFrame
{
	// Compiler thinks I'm talking about java.awt.Window.Type
	private Type t = Type.VALUE;
}

enum Type
{
	VALUE
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Rename affected class

Comments
EVALUATION First, a member type is in scope in the body of the class in which it is declared _and_ in the bodies of subclasses. See JLS3 8.1.6, repeated in 6.3. Second, a type imported by the compilation unit of a class is in scope in the body of that class. JLS3 6.3.1 tells us which type "wins" when multiple type names have the same scope and are referred to by their simple name. It would be bad if an imported type name shadowed the type name of an inherited member. So a type-import-on-demand declaration is extremely cautious: it never causes any other declaration to be shadowed. A single-type-import is less cautious, but still only shadows top-level types of the importer's package (+ some rules about which import statement "wins" if there are different kinds). Inherited member types are not shadowed by an import. Which is to say, the language trusts the maintainer of a type hierarchy not to add member types whose names might conflict with arbitrary type names appearing in subtypes (probably imported, but also from declarations in the same compilation unit). The "fix" is to fully qualify Type as bugs.Type.
25-02-2011

EVALUATION FYI, the CR covering the change to java.awt.Window is 6402325.
25-02-2011

EVALUATION This is not a regression in JDK 7 - the apparent problem has been caused by the fact that the enum Type has been added to java.awt.Window starting from JDK 7 b78. Leaving Swing aside for a moment, the equivalent test case is the one below: package bugs; import bugs.Type; class A { enum Type { } } class B extends A { //How is Type resolved? Type t = Type.VALUE; } enum Type { VALUE } The import doesn't really do anything, since the top-level enum type "Type" is already in scope throughout the compilation unit. Here is a more realistic example, where the imported type "Type" is in a different compilation unit (and package, for maximum separation): -- A.java import bugs.Type; class A { enum Type { } } class B extends A { //How is Type resolved? Type t = Type.VALUE; } -- bugs/Type.java package bugs; public enum Type { VALUE }
24-02-2011