Skip to content

Commit

Permalink
8328481: Implement JEP 476: Module Import Declarations (Preview)
Browse files Browse the repository at this point in the history
Co-authored-by: Jim Laskey <jlaskey@openjdk.org>
Reviewed-by: mcimadamore, vromero
  • Loading branch information
lahodaj and Jim Laskey committed May 6, 2024
1 parent 9347bb7 commit f2c4a41
Show file tree
Hide file tree
Showing 31 changed files with 1,349 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ public enum Feature {
CLASSFILE_API,
@JEP(number=473, title="Stream Gatherers", status="Second Preview")
STREAM_GATHERERS,
@JEP(number=476, title="Module Import Declarations", status="Preview")
MODULE_IMPORTS,
LANGUAGE_MODEL,
/**
* A key for testing.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -25,6 +25,8 @@

package com.sun.source.tree;

import jdk.internal.javac.PreviewFeature;

/**
* A tree node for an import declaration.
*
Expand All @@ -47,6 +49,12 @@ public interface ImportTree extends Tree {
* @return true if this is a static import
*/
boolean isStatic();
/**
* {@return true if this is an module import declaration.}
* @since 23
*/
@PreviewFeature(feature=PreviewFeature.Feature.MODULE_IMPORTS, reflective=true)
boolean isModule();

/**
* Returns the qualified identifier for the declaration(s)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -210,6 +210,7 @@ public boolean isPreview(Feature feature) {
case IMPLICIT_CLASSES -> true;
case SUPER_INIT -> true;
case PRIMITIVE_PATTERNS -> true;
case MODULE_IMPORTS -> true;
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
//When real preview features will be added, this method can be implemented to return 'true'
//for those selected features, and 'false' for all the others.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ public enum Feature {
UNNAMED_VARIABLES(JDK22, Fragments.FeatureUnnamedVariables, DiagKind.PLURAL),
PRIMITIVE_PATTERNS(JDK23, Fragments.FeaturePrimitivePatterns, DiagKind.PLURAL),
SUPER_INIT(JDK22, Fragments.FeatureSuperInit, DiagKind.NORMAL),
MODULE_IMPORTS(JDK23, Fragments.FeatureModuleImports, DiagKind.PLURAL),
;

enum DiagKind {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4396,7 +4396,9 @@ public void checkFunctionalInterface(JCClassDecl tree, ClassSymbol cs) {
}

public void checkImportsResolvable(final JCCompilationUnit toplevel) {
for (final JCImport imp : toplevel.getImports()) {
for (final JCImportBase impBase : toplevel.getImports()) {
if (!(impBase instanceof JCImport imp))
continue;
if (!imp.staticImport || !imp.qualid.hasTag(SELECT))
continue;
final JCFieldAccess select = imp.qualid;
Expand All @@ -4420,8 +4422,9 @@ public void checkImportsResolvable(final JCCompilationUnit toplevel) {

// Check that packages imported are in scope (JLS 7.4.3, 6.3, 6.5.3.1, 6.5.3.2)
public void checkImportedPackagesObservable(final JCCompilationUnit toplevel) {
OUTER: for (JCImport imp : toplevel.getImports()) {
if (!imp.staticImport && TreeInfo.name(imp.qualid) == names.asterisk) {
OUTER: for (JCImportBase impBase : toplevel.getImports()) {
if (impBase instanceof JCImport imp && !imp.staticImport &&
TreeInfo.name(imp.qualid) == names.asterisk) {
TypeSymbol tsym = imp.qualid.selected.type.tsym;
if (tsym.kind == PCK && tsym.members().isEmpty() &&
!(Feature.IMPORT_ON_DEMAND_OBSERVABLE_PACKAGES.allowedInSource(source) && tsym.exists())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018, Google LLC. All rights reserved.
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -67,6 +67,7 @@
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
import com.sun.tools.javac.tree.JCTree.JCModuleImport;
import com.sun.tools.javac.tree.JCTree.JCNewArray;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCOpens;
Expand Down Expand Up @@ -410,6 +411,12 @@ public void visitImport(JCImport tree) {
result = tree.staticImport == that.staticImport && scan(tree.qualid, that.qualid);
}

@Override
public void visitModuleImport(JCModuleImport tree) {
JCModuleImport that = (JCModuleImport) parameter;
result = scan(tree.module, that.module);
}

@Override
public void visitIndexed(JCArrayAccess tree) {
JCArrayAccess that = (JCArrayAccess) parameter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,15 @@
import javax.tools.JavaFileObject;

import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Directive.ExportsDirective;
import com.sun.tools.javac.code.Directive.RequiresDirective;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Scope.ImportFilter;
import com.sun.tools.javac.code.Scope.ImportScope;
import com.sun.tools.javac.code.Scope.NamedImportScope;
import com.sun.tools.javac.code.Scope.StarImportScope;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Source.Feature;
import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
import com.sun.tools.javac.parser.Parser;
import com.sun.tools.javac.parser.ParserFactory;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.DefinedBy.Api;
Expand All @@ -57,7 +56,6 @@
import static com.sun.tools.javac.code.Kinds.Kind.*;
import static com.sun.tools.javac.code.TypeTag.CLASS;
import static com.sun.tools.javac.code.TypeTag.ERROR;
import com.sun.tools.javac.resources.CompilerProperties.Fragments;

import static com.sun.tools.javac.code.TypeTag.*;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
Expand Down Expand Up @@ -114,8 +112,6 @@ public class TypeEnter implements Completer {
private final Lint lint;
private final TypeEnvs typeEnvs;
private final Dependencies dependencies;
private final ParserFactory parserFactory;
private final Preview preview;

public static TypeEnter instance(Context context) {
TypeEnter instance = context.get(typeEnterKey);
Expand Down Expand Up @@ -143,8 +139,6 @@ protected TypeEnter(Context context) {
lint = Lint.instance(context);
typeEnvs = TypeEnvs.instance(context);
dependencies = Dependencies.instance(context);
parserFactory = ParserFactory.instance(context);
preview = Preview.instance(context);
Source source = Source.instance(context);
allowDeprecationOnImport = Feature.DEPRECATION_ON_IMPORT.allowedInSource(source);
}
Expand Down Expand Up @@ -370,9 +364,7 @@ private void resolveImports(JCCompilationUnit tree, Env<AttrContext> env) {
if (tree.getPackage() != null && decl == null)
checkClassPackageClash(tree.getPackage());

for (JCImport imp : tree.getImports()) {
doImport(imp);
}
handleImports(tree.getImports());

if (decl != null) {
DiagnosticPosition prevCheckDeprecatedLintPos = deferredLintHandler.setPos(decl.pos());
Expand All @@ -394,6 +386,16 @@ private void resolveImports(JCCompilationUnit tree, Env<AttrContext> env) {
}
}

private void handleImports(List<JCImportBase> imports) {
for (JCImportBase imp : imports) {
if (imp instanceof JCModuleImport mimp) {
doModuleImport(mimp);
} else {
doImport((JCImport) imp);
}
}
}

private void checkClassPackageClash(JCPackageDecl tree) {
// check that no class exists with same fully qualified name as
// toplevel package
Expand Down Expand Up @@ -445,6 +447,57 @@ private void doImport(JCImport tree) {
}
}

private void doModuleImport(JCModuleImport tree) {
Name moduleName = TreeInfo.fullName(tree.module);
ModuleSymbol module = syms.getModule(moduleName);

if (module != null) {
if (!env.toplevel.modle.readModules.contains(module)) {
if (env.toplevel.modle.isUnnamed()) {
log.error(tree.pos, Errors.ImportModuleDoesNotReadUnnamed(module));
} else {
log.error(tree.pos, Errors.ImportModuleDoesNotRead(env.toplevel.modle,
module));
}
//error recovery, make sure the module is completed:
module.getDirectives();
}

List<ModuleSymbol> todo = List.of(module);
Set<ModuleSymbol> seenModules = new HashSet<>();

while (!todo.isEmpty()) {
ModuleSymbol currentModule = todo.head;

todo = todo.tail;

if (!seenModules.add(currentModule)) {
continue;
}

for (ExportsDirective export : currentModule.exports) {
if (export.modules != null && !export.modules.contains(env.toplevel.packge.modle)) {
continue;
}

PackageSymbol pkg = export.getPackage();
JCImport nestedImport = make.at(tree.pos)
.Import(make.Select(make.QualIdent(pkg), names.asterisk), false);

doImport(nestedImport);
}

for (RequiresDirective requires : currentModule.requires) {
if (requires.isTransitive()) {
todo = todo.prepend(requires.module);
}
}
}
} else {
log.error(tree.pos, Errors.ImportModuleNotFound(moduleName));
}
}

Type attribImportType(JCTree tree, Env<AttrContext> env) {
Assert.check(completionEnabled);
Lint prevLint = chk.setLint(allowDeprecationOnImport ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4252,6 +4252,13 @@ protected JCTree importDeclaration() {
if (token.kind == STATIC) {
importStatic = true;
nextToken();
} else if (token.kind == IDENTIFIER && token.name() == names.module &&
peekToken(TokenKind.IDENTIFIER)) {
checkSourceLevel(Feature.MODULE_IMPORTS);
nextToken();
JCExpression moduleName = qualident(false);
accept(SEMI);
return toP(F.at(pos).ModuleImport(moduleName));
}
JCExpression pid = toP(F.at(token.pos).Ident(ident()));
do {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3218,6 +3218,9 @@ compiler.misc.feature.implicit.classes=\
compiler.misc.feature.super.init=\
statements before super()

compiler.misc.feature.module.imports=\
module imports

compiler.warn.underscore.as.identifier=\
as of release 9, ''_'' is a keyword, and may not be used as an identifier

Expand Down Expand Up @@ -3528,6 +3531,18 @@ compiler.err.module.not.found=\
compiler.warn.module.not.found=\
module not found: {0}

# 0: name
compiler.err.import.module.not.found=\
imported module not found: {0}

# 0: symbol
compiler.err.import.module.does.not.read.unnamed=\
unnamed module does not read: {0}

# 0: symbol, 1: symbol
compiler.err.import.module.does.not.read=\
module {0} does not read: {1}

compiler.err.too.many.modules=\
too many module declarations found

Expand Down
Loading

1 comment on commit f2c4a41

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.