Compiling Java 9 (take 2)

Stephan Herrmann stephan.herrmann at
Wed Jan 4 20:44:13 UTC 2017

I have started to dig through the JLS changes (2016-12-16) to figure out requirements for a Java 9 compiler without consulting 
javac, but I'm having some difficulties understanding the interplay of scope, visibility, importing, accessibility and observability 
at this level.

For instance, this already starts when re-reading unchanged parts from 6.3 and 6.4.1:
     The scope of a declaration is the region of the program within which the entity declared by the declaration can be referred to 
using a simple name, provided it is visible (§6.4.1).
     A declaration d is said to be visible at point p in a program if the scope of d includes p, and d is not shadowed by any other 
declaration at p.
=> For a declaration to be in scope it must be visible, and for being visible it must be in scope. This is beyond me.

Is it correct (and intended) that "visibility of a declaration" (6.3) is a different concept than "visibility of a compilation unit" 
(7.3)? (Are we so entangled with overloading that we need to overload the terms in our spec, too? :) ).
I'm also surprised that some requirements are indeed specified with regard to compilation units. Modules export packages, and types 
are declared in packages. Isn't it possible to define requirements due to JPMS solely in those terms (modules, packages, types), and 
avoid to mention compilation units in these rules? What do compilation units add conceptually to JPMS (besides adding complexity)?

As I already mentioned overloading, here's my example of the day:

//--- Base/
module Base {
	exports base;
//--- Base/other/
package other;

/** I'm not exported */
public class Other {
	public void test() {
//--- Base/base/
package base;

import other.Other;

/** I'm exported */
public class Base {
	public void test(Object other) {
	public void test(Other other) {

//--- Test/
module Test {
	requires Base;
//--- Test/other/
package other;

public class Other {
//--- Test/test/
package test;

import base.Base;
import other.Other;

public class Test {
	void test(Base b, Other other, Object o) {
		b.test(o); // OK
		b.test(other); // ??
	public static void main(String[] args) {
		new Test().test(new Base(), new Other(), new Object());

Firstly, I'm surprised that javac (ea-149) compiles this fine but trying to run the program under JPMS crashes with
Error occurred during initialization of VM
java.lang.reflect.LayerInstantiationException: Package other in both module Base and module Test
         at at 9-ea/
         at java.lang.reflect.Layer.checkBootModulesForDuplicatePkgs(java.base at 9-ea/
         at java.lang.reflect.Layer.defineModules(java.base at 9-ea/
         at java.lang.reflect.Layer.defineModules(java.base at 9-ea/
         at jdk.internal.module.ModuleBootstrap.boot(java.base at 9-ea/
         at java.lang.System.initPhase2(java.base at 9-ea/

Is that because the compiler knows nothing about layers?
Is there any tool that statically checks whether a given modular program can possibly run in the default Layer implementation?

Secondly, I'm confused how overload resolution for b.test(..) should happen.
We have two candidates, where one parameter type is accessible (Object) and the other is not (other.Other).
In all of JLS chapter 15 (2016-12-16) I cannot find anything that would allow the compiler to consider accessibility of parameter 
types during overload resolution.

Hence, I see two possible answers by a compiler:
(1) resolve b.test(other) to test(Other) because both types other.Other appear to be the same type, and hence test(Other) is 
applicable and more specific than test(Object).
(2) reject the program because of a name clash on other.Other.

Javac (ea-149) does neither, but resolves b.test(other) to test(Object).
Apparently, javac "knows" that Base/other.Other and Test/other.Other are distinct types. Given that types are identified by 
qualified names that do not contain the module name, this distinction doesn't seem to be possible per JLS.
Or javac marks the method test(Other) as inaccessible, but JLS determines accessibility of a method only using the method's modifiers.

So, what JLS rules lead javac to selecting test(Object)?


More information about the jigsaw-dev mailing list