Skip to content

Commit 0a697f6

Browse files
committed
8344708: Implement JEP 511: Module Import Declarations
Reviewed-by: mcimadamore, vromero, alanb
1 parent b218410 commit 0a697f6

File tree

32 files changed

+358
-216
lines changed

32 files changed

+358
-216
lines changed

src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ public enum Feature {
7676
STRUCTURED_CONCURRENCY,
7777
CLASSFILE_API,
7878
STREAM_GATHERERS,
79-
@JEP(number=494, title="Module Import Declarations", status="Second Preview")
80-
MODULE_IMPORTS,
79+
MODULE_IMPORTS, //remove when the boot JDK is JDK 25
8180
@JEP(number=478, title="Key Derivation Function API", status="Preview")
8281
KEY_DERIVATION,
8382
@JEP(number = 502, title = "Stable Values", status = "Preview")

src/java.base/share/classes/jdk/internal/module/ModuleInfo.java

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -408,24 +408,10 @@ private Builder readModuleAttribute(DataInput in, ConstantPool cpool, int major,
408408
throw invalidModuleDescriptor("The requires entry for java.base"
409409
+ " has ACC_SYNTHETIC set");
410410
}
411-
// requires transitive java.base is illegal unless:
412-
// - the major version is 53 (JDK 9), or:
413-
// - the classfile is a preview classfile, or:
414-
// - the module is deemed to be participating in preview
415-
// (i.e. the module is a java.* module)
416-
// requires static java.base is illegal unless:
417-
// - the major version is 53 (JDK 9), or:
418-
if (major >= 54
419-
&& ((mods.contains(Requires.Modifier.TRANSITIVE)
420-
&& !isPreview
421-
&& !"java.se".equals(mn))
422-
|| mods.contains(Requires.Modifier.STATIC))) {
423-
String flagName;
424-
if (mods.contains(Requires.Modifier.STATIC)) {
425-
flagName = "ACC_STATIC_PHASE";
426-
} else {
427-
flagName = "ACC_TRANSITIVE";
428-
}
411+
// requires static java.base is illegal unless
412+
// the major version is 53 (JDK 9)
413+
if (major >= 54 && mods.contains(Requires.Modifier.STATIC)) {
414+
String flagName = "ACC_STATIC_PHASE";
429415
throw invalidModuleDescriptor("The requires entry for java.base"
430416
+ " has " + flagName + " set");
431417
}

src/jdk.compiler/share/classes/com/sun/source/tree/ImportTree.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525

2626
package com.sun.source.tree;
2727

28-
import jdk.internal.javac.PreviewFeature;
29-
3028
/**
3129
* A tree node for an import declaration.
3230
*
@@ -49,11 +47,11 @@ public interface ImportTree extends Tree {
4947
* @return true if this is a static import
5048
*/
5149
boolean isStatic();
50+
5251
/**
5352
* {@return true if this is an module import declaration.}
54-
* @since 23
53+
* @since 25
5554
*/
56-
@PreviewFeature(feature=PreviewFeature.Feature.MODULE_IMPORTS, reflective=true)
5755
boolean isModule();
5856

5957
/**

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,7 @@ public boolean participatesInPreview(Symtab syms, ModuleSymbol m) {
153153
// s participates in the preview API
154154
return syms.java_base.exports.stream()
155155
.filter(ed -> ed.packge.fullname == names.jdk_internal_javac)
156-
.anyMatch(ed -> ed.modules.contains(m)) ||
157-
//the specification lists the java.se module as participating in preview:
158-
m.name == names.java_se;
156+
.anyMatch(ed -> ed.modules.contains(m));
159157
}
160158

161159
/**
@@ -231,8 +229,6 @@ public boolean isPreview(Feature feature) {
231229
case IMPLICIT_CLASSES -> true;
232230
case FLEXIBLE_CONSTRUCTORS -> true;
233231
case PRIMITIVE_PATTERNS -> true;
234-
case MODULE_IMPORTS -> true;
235-
case JAVA_BASE_TRANSITIVE -> true;
236232
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
237233
//When real preview features will be added, this method can be implemented to return 'true'
238234
//for those selected features, and 'false' for all the others.

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,8 @@ public enum Feature {
267267
UNNAMED_VARIABLES(JDK22, Fragments.FeatureUnnamedVariables, DiagKind.PLURAL),
268268
PRIMITIVE_PATTERNS(JDK23, Fragments.FeaturePrimitivePatterns, DiagKind.PLURAL),
269269
FLEXIBLE_CONSTRUCTORS(JDK22, Fragments.FeatureFlexibleConstructors, DiagKind.NORMAL),
270-
MODULE_IMPORTS(JDK23, Fragments.FeatureModuleImports, DiagKind.PLURAL),
271-
JAVA_BASE_TRANSITIVE(JDK24, Fragments.FeatureJavaBaseTransitive, DiagKind.PLURAL),
270+
MODULE_IMPORTS(JDK25, Fragments.FeatureModuleImports, DiagKind.PLURAL),
271+
JAVA_BASE_TRANSITIVE(JDK25, Fragments.FeatureJavaBaseTransitive, DiagKind.PLURAL),
272272
PRIVATE_MEMBERS_IN_PERMITS_CLAUSE(JDK19),
273273
ERASE_POLY_SIG_RETURN_TYPE(JDK24),
274274
;

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,11 +1202,6 @@ protected void read(Symbol sym, int attrLen) {
12021202
ModuleSymbol rsym = poolReader.getModule(nextChar());
12031203
Set<RequiresFlag> flags = readRequiresFlags(nextChar());
12041204
if (rsym == syms.java_base && majorVersion >= V54.major) {
1205-
if (flags.contains(RequiresFlag.TRANSITIVE) &&
1206-
(majorVersion != Version.MAX().major || !previewClassFile) &&
1207-
!preview.participatesInPreview(syms, msym)) {
1208-
throw badClassFile("bad.requires.flag", RequiresFlag.TRANSITIVE);
1209-
}
12101205
if (flags.contains(RequiresFlag.STATIC_PHASE)) {
12111206
throw badClassFile("bad.requires.flag", RequiresFlag.STATIC_PHASE);
12121207
}

src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
import static jdk.jshell.Snippet.SubKind.TEMP_VAR_EXPRESSION_SUBKIND;
132132
import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND;
133133
import static java.util.stream.Collectors.toMap;
134+
import javax.lang.model.SourceVersion;
134135
import static jdk.internal.jshell.debug.InternalDebugControl.DBG_COMPA;
135136
import static jdk.internal.jshell.debug.InternalDebugControl.DBG_DEP;
136137
import static jdk.internal.jshell.debug.InternalDebugControl.DBG_EVNT;
@@ -642,7 +643,10 @@ Options parse(OptionSet options) {
642643
} else {
643644
String packedStartup = prefs.get(STARTUP_KEY);
644645
boolean preview = previewEnabled(options);
645-
initialStartup = Startup.unpack(packedStartup, preview, new InitMessageHandler());
646+
String sourceLevel = detectSourceLevel(options.valuesOf(argC)
647+
.toArray(String[]::new));
648+
initialStartup = Startup.unpack(packedStartup, sourceLevel,
649+
preview, new InitMessageHandler());
646650
}
647651
if (options.has(argExecution)) {
648652
executionControlSpec = options.valueOf(argExecution);
@@ -2311,7 +2315,8 @@ boolean setStart(ArgTokenizer at) {
23112315
}
23122316
} else if (defaultOption) {
23132317
boolean preview = options.hasOption(OptionKind.ENABLE_PREVIEW);
2314-
startup = Startup.defaultStartup(preview, this);
2318+
String sourceLevel = detectSourceLevel(options.compilerOptions());
2319+
startup = Startup.defaultStartup(sourceLevel, preview, this);
23152320
} else if (noneOption) {
23162321
startup = Startup.noStartup();
23172322
}
@@ -2329,7 +2334,8 @@ void showSetStart() {
23292334
String retained = prefs.get(STARTUP_KEY);
23302335
if (retained != null) {
23312336
boolean preview = options.hasOption(OptionKind.ENABLE_PREVIEW);
2332-
Startup retainedStart = Startup.unpack(retained, preview, this);
2337+
String sourceLevel = detectSourceLevel(options.compilerOptions());
2338+
Startup retainedStart = Startup.unpack(retained, sourceLevel, preview, this);
23332339
boolean currentDifferent = !startup.equals(retainedStart);
23342340
sb.append(retainedStart.show(true));
23352341
if (currentDifferent) {
@@ -2346,6 +2352,19 @@ void showSetStart() {
23462352
hard(escape(sb));
23472353
}
23482354

2355+
private String detectSourceLevel(String[] compilerOptions) {
2356+
for (int i = 0; i < compilerOptions.length; i++) {
2357+
switch (compilerOptions[i]) {
2358+
case "-source", "--source", "--release":
2359+
if (i + 1 < compilerOptions.length) {
2360+
return compilerOptions[i + 1];
2361+
}
2362+
}
2363+
}
2364+
2365+
return Integer.toString(SourceVersion.latest().runtimeVersion().feature());
2366+
}
2367+
23492368
private void showIndent() {
23502369
hard("/set indent %s", indent());
23512370
}

src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Startup.java

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,20 @@
2525

2626
package jdk.internal.jshell.tool;
2727

28+
import com.sun.tools.javac.code.Source;
29+
import com.sun.tools.javac.code.Source.Feature;
2830
import java.nio.file.AccessDeniedException;
2931
import java.nio.file.Files;
3032
import java.nio.file.NoSuchFileException;
3133
import java.time.LocalDateTime;
3234
import java.time.format.DateTimeFormatter;
3335
import java.time.format.FormatStyle;
3436
import java.util.ArrayList;
37+
import java.util.Arrays;
3538
import java.util.Collections;
39+
import java.util.EnumMap;
3640
import java.util.List;
41+
import java.util.Map;
3742
import java.util.Objects;
3843
import static java.util.stream.Collectors.joining;
3944
import static jdk.internal.jshell.tool.JShellTool.RECORD_SEPARATOR;
@@ -118,13 +123,10 @@ public boolean equals(Object o) {
118123
}
119124

120125
private static final String DEFAULT_STARTUP_NAME = "DEFAULT";
121-
private static final String PREVIEW_DEFAULT_STARTUP_NAME = "PREVIEW_DEFAULT";
122126

123127
// cached DEFAULT start-up
124-
private static Startup[] defaultStartup = new Startup[] {
125-
null, //standard startup
126-
null //preview startup
127-
};
128+
private static Map<DefaultStartupType, Startup> defaultStartup =
129+
new EnumMap<>(DefaultStartupType.class);
128130

129131
// the list of entries
130132
private List<StartupEntry> entries;
@@ -170,8 +172,10 @@ boolean isEmpty() {
170172
boolean isDefault() {
171173
if (entries.size() == 1) {
172174
StartupEntry sue = entries.get(0);
173-
if (sue.isBuiltIn && (sue.name.equals(DEFAULT_STARTUP_NAME) ||
174-
sue.name.equals(PREVIEW_DEFAULT_STARTUP_NAME))) {
175+
if (sue.isBuiltIn &&
176+
Arrays.stream(DefaultStartupType.values())
177+
.map(DefaultStartupType::getResourceName)
178+
.anyMatch(sue.name::equals)) {
175179
return true;
176180
}
177181
}
@@ -222,7 +226,7 @@ String showDetail() {
222226
* @param mh handler for error messages
223227
* @return Startup, or default startup when error (message has been printed)
224228
*/
225-
static Startup unpack(String storedForm, boolean preview, MessageHandler mh) {
229+
static Startup unpack(String storedForm, String sourceLevel, boolean preview, MessageHandler mh) {
226230
if (storedForm != null) {
227231
if (storedForm.isEmpty()) {
228232
return noStartup();
@@ -243,14 +247,18 @@ static Startup unpack(String storedForm, boolean preview, MessageHandler mh) {
243247
String name = all[i + 1];
244248
String timeStamp = all[i + 2];
245249
String content = all[i + 3];
246-
if (isBuiltIn) {
247-
// update to current definition, use stored if removed/error
248-
String resource = getResource(name);
249-
if (resource != null) {
250-
content = resource;
250+
if (isBuiltIn && DEFAULT_STARTUP_NAME.equals(name)) {
251+
e.addAll(defaultStartup(sourceLevel, preview, mh).entries);
252+
} else {
253+
if (isBuiltIn) {
254+
// update to current definition, use stored if removed/error
255+
String resource = getResource(name);
256+
if (resource != null) {
257+
content = resource;
258+
}
251259
}
260+
e.add(new StartupEntry(isBuiltIn, name, content, timeStamp));
252261
}
253-
e.add(new StartupEntry(isBuiltIn, name, content, timeStamp));
254262
}
255263
return new Startup(e);
256264
} else {
@@ -260,7 +268,7 @@ static Startup unpack(String storedForm, boolean preview, MessageHandler mh) {
260268
mh.errormsg("jshell.err.corrupted.stored.startup", ex.getMessage());
261269
}
262270
}
263-
return defaultStartup(preview, mh);
271+
return defaultStartup(sourceLevel, preview, mh);
264272
}
265273

266274
/**
@@ -329,26 +337,49 @@ static Startup noStartup() {
329337
* @param mh handler for error messages
330338
* @return The default Startup, or empty startup when error (message has been printed)
331339
*/
332-
static Startup defaultStartup(boolean preview, MessageHandler mh) {
333-
int idx = preview ? 1 : 0;
340+
static Startup defaultStartup(String sourceLevel, boolean preview, MessageHandler mh) {
341+
Source source = Source.lookup(sourceLevel);
342+
DefaultStartupType type;
343+
if (preview) {
344+
type = DefaultStartupType.PREVIEW_DEFAULT_STARTUP;
345+
} else if (source == null ||
346+
Feature.MODULE_IMPORTS.allowedInSource(source)) {
347+
type = DefaultStartupType.DEFAULT_STARTUP;
348+
} else {
349+
type = DefaultStartupType.DEFAULT_STARTUP_NO_MODULE_IMPORTS;
350+
}
351+
352+
return defaultStartup.computeIfAbsent(type, t -> {
353+
String resourceName = t.getResourceName();
354+
355+
try {
356+
String content = readResource(resourceName);
357+
return new Startup(
358+
new StartupEntry(true, DEFAULT_STARTUP_NAME, content));
359+
} catch (AccessDeniedException e) {
360+
mh.errormsg("jshell.err.file.not.accessible", "jshell", resourceName, e.getMessage());
361+
} catch (NoSuchFileException e) {
362+
mh.errormsg("jshell.err.file.not.found", "jshell", resourceName);
363+
} catch (Exception e) {
364+
mh.errormsg("jshell.err.file.exception", "jshell", resourceName, e);
365+
}
366+
return noStartup();
367+
});
368+
}
369+
370+
private enum DefaultStartupType {
371+
DEFAULT_STARTUP("DEFAULT"),
372+
DEFAULT_STARTUP_NO_MODULE_IMPORTS("DEFAULT_NO_MODULE_IMPORTS"),
373+
PREVIEW_DEFAULT_STARTUP("PREVIEW_DEFAULT");
334374

335-
if (defaultStartup[idx] != null) {
336-
return defaultStartup[idx];
375+
private final String resourceName;
376+
377+
private DefaultStartupType(String resourceName) {
378+
this.resourceName = resourceName;
337379
}
338-
String resourceName = preview ? PREVIEW_DEFAULT_STARTUP_NAME
339-
: DEFAULT_STARTUP_NAME;
340-
try {
341-
String content = readResource(resourceName);
342-
return defaultStartup[idx] = new Startup(
343-
new StartupEntry(true, resourceName, content));
344-
} catch (AccessDeniedException e) {
345-
mh.errormsg("jshell.err.file.not.accessible", "jshell", resourceName, e.getMessage());
346-
} catch (NoSuchFileException e) {
347-
mh.errormsg("jshell.err.file.not.found", "jshell", resourceName);
348-
} catch (Exception e) {
349-
mh.errormsg("jshell.err.file.exception", "jshell", resourceName, e);
380+
381+
public String getResourceName() {
382+
return resourceName;
350383
}
351-
return defaultStartup[idx] = noStartup();
352384
}
353-
354385
}

src/jdk.jshell/share/classes/jdk/jshell/Snippet.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import java.util.Collection;
2929
import java.util.Collections;
3030
import java.util.List;
31-
import jdk.internal.javac.PreviewFeature;
3231

3332
/**
3433
* A Snippet represents a snippet of Java source code as passed to
@@ -219,9 +218,8 @@ public enum SubKind {
219218
* Import Module Declaration.
220219
* An import declaration of a module.
221220
* @jls 7.5.5 Import Module Declarations
222-
* @since 23
221+
* @since 25
223222
*/
224-
@PreviewFeature(feature=PreviewFeature.Feature.MODULE_IMPORTS, reflective=true)
225223
MODULE_IMPORT_SUBKIND(Kind.IMPORT),
226224

227225
/**

0 commit comments

Comments
 (0)