Details
-
JEP
-
Resolution: Delivered
-
P3
-
Jan Lahoda
-
Feature
-
Open
-
Implementation
-
-
S
-
M
-
216
Description
Summary
Fix javac
to properly accept and reject programs regardless of the
order of import
statements and extends
and implements
clauses.
Motivation
In some cases javac
will accept source code with a certain order of
imports and reject the same source code with just the imports reordered
(e.g.,
JDK-7177813). That
is wrong and confusing.
Description
javac
uses several stages when compiling classes. Considering import
handling, the two important stages are:
Type resolution, which looks through the provided AST looking for class and interface declaration, and
Member resolution, which includes:
- (1a) If
T
is toplevel,import
s in the source file definingT
are processed and imported members added inT
's scope - (1b) If
T
is nested, resolution of the class directly enclosingT
(if any) - (2)
extends
/implements
clauses ofT
are type-checked - (3) Type variables of
T
are type-checked
- (1a) If
The above stages are part of javac
's process of resolution of
classes, which includes determining a class's supertypes, type variables,
and members.
To see this in process in action, consider this code:
package P;
import static P.Outer.Nested.*;
import P.Q.*;
public class Outer {
public static class Nested implements I {
}
}
package P.Q;
public interface I {
}
During the type-resolution phase it is recognized that there exist types
P.Outer
, P.Outer.Nested
, and P.Q.I
. Then, if the P.Outer
class
is to be analyzed, the member resolution phase works like this:
1. | Resolution of P.Outer starts |
2. | Processing of the import static P.Outer.Nested.*; starts, per 1a, which means the members of P.Outer.Nested and its transitive supertypes are looked up. |
3. | Resolution of the P.Outer.Nested class starts (the static imports can also import inherited types) |
4. | Triggers resolution of P.Outer , which is skipped as it is already in progress |
5. | Type checking of I (the implements clause) runs, but I cannot be resolved since it is not in the scope yet. |
6. | Resolution of import P.Q.* starts, which takes all member types of P.Q (including the interface I ) and imports them into the current file's scope |
7. | Resolution of P.Outer and other classes continues |
If the imports are swapped then step 6 happens before step 5 and so I
is found during step 5.
The above is not the only problem related to import
handling. The other
known problem is that the bounds of a class's type parameters may validly
refer to possible inner classes of their declaring class. In some cases,
this currently causes unresolvable cycles, for example:
package P;
import static P.Outer.Nested.*;
public class Outer {
public static class Nested<T extends I> {
static class I { }
}
}
The envisioned solution to this problem is to split the existing first
phase of javac
's member resolution into three: The first will analyze
the enclosing file's imports, the second will only build the
class/interface hierarchy, without any type parameters, annotations,
etc., and the third will properly analyze the class headers, including
type parameters.
It is expected that this change will allow javac
to accept programs
that are currently rejected but not reject ones that are currently
accepted.
Attachments
Issue Links
- relates to
-
JDK-7101822 Compiling depends on order of imports
- Closed
-
JDK-7177813 Static import to local nested class fails
- Closed
-
JDK-8041994 8.1.4: Superclass/superinterface "depends" relationship misses imported qualified names
- Closed
-
JDK-8051946 JEP 215: Tiered Attribution for javac
- Closed
-
JDK-8031569 Refactor javac scope implementation to enable lazy imports
- Closed
-
JDK-8048890 Add option to keep track of symbol completion dependencies
- Closed
-
JDK-8075274 Compilation still depends on the order of imports
- Closed