This commit is contained in:
Jesper Wilhelmsson 2017-10-04 20:01:19 +00:00
commit eed5d34c26
235 changed files with 7673 additions and 2642 deletions

View file

@ -449,3 +449,4 @@ a85884d55ce32799f5c7382b7ea4839052b362a2 jdk-10+21
e5357aa85dadacc6562175ff74714fecfb4470cf jdk-10+22 e5357aa85dadacc6562175ff74714fecfb4470cf jdk-10+22
22850b3a55240253841b9a425ad60a7fcdb22d47 jdk-10+23 22850b3a55240253841b9a425ad60a7fcdb22d47 jdk-10+23
3b201865d5c1f244f555cad58da599c9261286d8 jdk-10+24 3b201865d5c1f244f555cad58da599c9261286d8 jdk-10+24
8eb5e3ccee560c28ac9b1df2670adac2b3d36fad jdk-10+25

View file

@ -28,8 +28,8 @@
mydir="$(dirname "${BASH_SOURCE[0]}")" mydir="$(dirname "${BASH_SOURCE[0]}")"
myname="$(basename "${BASH_SOURCE[0]}")" myname="$(basename "${BASH_SOURCE[0]}")"
installed_jib_script=${mydir}/../../.jib/jib installed_jib_script=${mydir}/../.jib/jib
install_data=${mydir}/../../.jib/.data install_data=${mydir}/../.jib/.data
setup_url() { setup_url() {
if [ -f ~/.config/jib/jib.conf ]; then if [ -f ~/.config/jib/jib.conf ]; then
@ -42,7 +42,7 @@ setup_url() {
jib_revision="2.0-SNAPSHOT" jib_revision="2.0-SNAPSHOT"
jib_ext="jib.sh.gz" jib_ext="jib.sh.gz"
closed_script="${mydir}/../../../closed/conf/jib-install.conf" closed_script="${mydir}/../../closed/make/conf/jib-install.conf"
if [ -f "${closed_script}" ]; then if [ -f "${closed_script}" ]; then
source "${closed_script}" source "${closed_script}"
fi fi

View file

@ -127,7 +127,7 @@ scripting language.</span></p>
<hr> <hr>
<span><a name="package" id="package"></a></span> <span><a name="package" id="package"></a></span>
<h2><span>Scripting Package</span></h2> <h2><span>Scripting Package</span></h2>
<p><span>The Java Scripting functionality is in the <code><a href="http://docs.oracle.com/javase/6/docs/api/javax/script/package-summary.html">javax.script</a></code> <p><span>The Java Scripting functionality is in the <code><a href="http://docs.oracle.com/javase/9/docs/api/javax/script/package-summary.html">javax.script</a></code>
package. This is a relatively small, simple API. The starting point package. This is a relatively small, simple API. The starting point
of the scripting API is the <code>ScriptEngineManager</code> class. of the scripting API is the <code>ScriptEngineManager</code> class.
A ScriptEngineManager object can discover script engines through A ScriptEngineManager object can discover script engines through

View file

@ -41,7 +41,7 @@ JDK_CLASSES := $(call PathList, $(strip $(addprefix $(JDK_OUTPUTDIR)/modules/, \
$(eval $(call SetupJavaCompiler, GENERATE_NEWBYTECODE_DEBUG, \ $(eval $(call SetupJavaCompiler, GENERATE_NEWBYTECODE_DEBUG, \
JVM := $(JAVA_JAVAC), \ JVM := $(JAVA_JAVAC), \
JAVAC := $(NEW_JAVAC), \ JAVAC := $(NEW_JAVAC), \
FLAGS := -g -source 9 -target 9 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \ FLAGS := -g -source 10 -target 10 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \
--system none --module-source-path $(call GetModuleSrcPath), \ --system none --module-source-path $(call GetModuleSrcPath), \
SERVER_DIR := $(SJAVAC_SERVER_DIR), \ SERVER_DIR := $(SJAVAC_SERVER_DIR), \
SERVER_JVM := $(SJAVAC_SERVER_JAVA))) SERVER_JVM := $(SJAVAC_SERVER_JAVA)))

View file

@ -36,7 +36,7 @@ ifeq ($(HAS_SPEC),)
# Include the corresponding closed file, if present. # Include the corresponding closed file, if present.
# Normal hook mechanism cannot be used since we have no SPEC. # Normal hook mechanism cannot be used since we have no SPEC.
-include $(topdir)/closed/make/InitSupport.gmk -include $(topdir)/../closed/make/InitSupport.gmk
############################################################################## ##############################################################################
# Helper functions for the initial part of Init.gmk, before the spec file is # Helper functions for the initial part of Init.gmk, before the spec file is

View file

@ -1311,6 +1311,7 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER],
$2LDFLAGS_JDKLIB="${$2LDFLAGS_JDK}" $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDK}"
$2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}" $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
$2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
$2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} \ $2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} \
-libpath:${OUTPUTDIR}/support/modules_libs/java.base" -libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@ -1388,6 +1389,7 @@ $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${$2JAVA_BASE_LDFLAGS}"
AC_SUBST($2JDKEXE_LIBS) AC_SUBST($2JDKEXE_LIBS)
AC_SUBST($2LDFLAGS_CXX_JDK) AC_SUBST($2LDFLAGS_CXX_JDK)
AC_SUBST($2LDFLAGS_HASH_STYLE) AC_SUBST($2LDFLAGS_HASH_STYLE)
AC_SUBST($2LDFLAGS_NO_EXEC_STACK)
AC_SUBST($2JVM_CFLAGS) AC_SUBST($2JVM_CFLAGS)
AC_SUBST($2JVM_LDFLAGS) AC_SUBST($2JVM_LDFLAGS)

View file

@ -723,6 +723,7 @@ OPENJDK_BUILD_JVM_LIBS
OPENJDK_BUILD_JVM_ASFLAGS OPENJDK_BUILD_JVM_ASFLAGS
OPENJDK_BUILD_JVM_LDFLAGS OPENJDK_BUILD_JVM_LDFLAGS
OPENJDK_BUILD_JVM_CFLAGS OPENJDK_BUILD_JVM_CFLAGS
OPENJDK_BUILD_LDFLAGS_NO_EXEC_STACK
OPENJDK_BUILD_LDFLAGS_HASH_STYLE OPENJDK_BUILD_LDFLAGS_HASH_STYLE
OPENJDK_BUILD_LDFLAGS_CXX_JDK OPENJDK_BUILD_LDFLAGS_CXX_JDK
OPENJDK_BUILD_JDKEXE_LIBS OPENJDK_BUILD_JDKEXE_LIBS
@ -738,6 +739,7 @@ JVM_LIBS
JVM_ASFLAGS JVM_ASFLAGS
JVM_LDFLAGS JVM_LDFLAGS
JVM_CFLAGS JVM_CFLAGS
LDFLAGS_NO_EXEC_STACK
LDFLAGS_HASH_STYLE LDFLAGS_HASH_STYLE
LDFLAGS_CXX_JDK LDFLAGS_CXX_JDK
JDKEXE_LIBS JDKEXE_LIBS
@ -5115,7 +5117,7 @@ VS_SDK_PLATFORM_NAME_2013=
#CUSTOM_AUTOCONF_INCLUDE #CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks: # Do not change or remove the following line, it is needed for consistency checks:
DATE_WHEN_GENERATED=1506333008 DATE_WHEN_GENERATED=1506397140
############################################################################### ###############################################################################
# #
@ -52024,6 +52026,7 @@ fi
LDFLAGS_JDKLIB="${LDFLAGS_JDK}" LDFLAGS_JDKLIB="${LDFLAGS_JDK}"
LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}" LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} \ JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} \
-libpath:${OUTPUTDIR}/support/modules_libs/java.base" -libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@ -52109,6 +52112,7 @@ LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${JAVA_BASE_LDFLAGS}"
# Special extras... # Special extras...
if test "x$TOOLCHAIN_TYPE" = xsolstudio; then if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
if test "x$OPENJDK_BUILD_CPU_ARCH" = "xsparc"; then if test "x$OPENJDK_BUILD_CPU_ARCH" = "xsparc"; then
@ -52903,6 +52907,7 @@ fi
OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDK}" OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDK}"
OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}" OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} \ OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} \
-libpath:${OUTPUTDIR}/support/modules_libs/java.base" -libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@ -52988,6 +52993,7 @@ OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${OPENJDK_BUILD_JA
# Tests are only ever compiled for TARGET # Tests are only ever compiled for TARGET
# Flags for compiling test libraries # Flags for compiling test libraries
CFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA" CFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA"

View file

@ -387,6 +387,7 @@ CFLAGS_JDKEXE:=@CFLAGS_JDKEXE@
CXXFLAGS_JDKEXE:=@CXXFLAGS_JDKEXE@ CXXFLAGS_JDKEXE:=@CXXFLAGS_JDKEXE@
LDFLAGS_HASH_STYLE := @LDFLAGS_HASH_STYLE@ LDFLAGS_HASH_STYLE := @LDFLAGS_HASH_STYLE@
LDFLAGS_NO_EXEC_STACK := @LDFLAGS_NO_EXEC_STACK@
JVM_CFLAGS := @JVM_CFLAGS@ JVM_CFLAGS := @JVM_CFLAGS@
JVM_CFLAGS_SYMBOLS := @JVM_CFLAGS_SYMBOLS@ JVM_CFLAGS_SYMBOLS := @JVM_CFLAGS_SYMBOLS@

View file

@ -58,7 +58,6 @@ BOOT_MODULES += \
java.rmi \ java.rmi \
java.security.sasl \ java.security.sasl \
java.xml \ java.xml \
jdk.httpserver \
jdk.internal.vm.ci \ jdk.internal.vm.ci \
jdk.management \ jdk.management \
jdk.management.agent \ jdk.management.agent \
@ -112,6 +111,7 @@ PLATFORM_MODULES += \
jdk.crypto.cryptoki \ jdk.crypto.cryptoki \
jdk.crypto.ec \ jdk.crypto.ec \
jdk.dynalink \ jdk.dynalink \
jdk.httpserver \
jdk.incubator.httpclient \ jdk.incubator.httpclient \
jdk.internal.vm.compiler.management \ jdk.internal.vm.compiler.management \
jdk.jsobject \ jdk.jsobject \

View file

@ -900,6 +900,45 @@ var getJibProfilesProfiles = function (input, common, data) {
} }
}, },
"windows-x64-open": {
artifacts: {
jdk: {
local: "bundles/\\(jdk.*bin.tar.gz\\)",
remote: [
"bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+ "_windows-x64_bin.tar.gz",
"bundles/openjdk/GPL/windows-x64/\\1"
],
subdir: "jdk-" + data.version
},
jre: {
local: "bundles/\\(jre.*bin.tar.gz\\)",
remote: "bundles/openjdk/GPL/windows-x64/\\1"
},
test: {
local: "bundles/\\(jdk.*bin-tests.tar.gz\\)",
remote: [
"bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+ "_windows-x64_bin-tests.tar.gz",
"bundles/openjdk/GPL/windows-x64/\\1"
]
},
jdk_symbols: {
local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)",
remote: [
"bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+ "_windows-x64_bin-symbols.tar.gz",
"bundles/openjdk/GPL/windows-x64/\\1"
],
subdir: "jdk-" + data.version
},
jre_symbols: {
local: "bundles/\\(jre.*bin-symbols.tar.gz\\)",
remote: "bundles/openjdk/GPL/windows-x64/\\1",
}
}
},
"linux-x86-open-debug": { "linux-x86-open-debug": {
artifacts: { artifacts: {
jdk: { jdk: {
@ -929,9 +968,10 @@ var getJibProfilesProfiles = function (input, common, data) {
profiles["linux-x86-ri-debug"] = clone(profiles["linux-x86-open-debug"]); profiles["linux-x86-ri-debug"] = clone(profiles["linux-x86-open-debug"]);
profiles["macosx-x64-ri"] = clone(profiles["macosx-x64-open"]); profiles["macosx-x64-ri"] = clone(profiles["macosx-x64-open"]);
profiles["windows-x86-ri"] = clone(profiles["windows-x86-open"]); profiles["windows-x86-ri"] = clone(profiles["windows-x86-open"]);
profiles["windows-x64-ri"] = clone(profiles["windows-x64-open"]);
// Generate artifacts for ri profiles // Generate artifacts for ri profiles
[ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x86-ri" ] [ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x86-ri", "windows-x64-ri" ]
.forEach(function (name) { .forEach(function (name) {
// Rewrite all remote dirs to "bundles/openjdk/BCL/..." // Rewrite all remote dirs to "bundles/openjdk/BCL/..."
for (artifactName in profiles[name].artifacts) { for (artifactName in profiles[name].artifacts) {
@ -947,6 +987,11 @@ var getJibProfilesProfiles = function (input, common, data) {
configure_args: "--with-freetype-license=" configure_args: "--with-freetype-license="
+ input.get("freetype", "install_path") + input.get("freetype", "install_path")
+ "/freetype-2.7.1-v120-x86/freetype.md" + "/freetype-2.7.1-v120-x86/freetype.md"
},
"windows-x64-ri": {
configure_args: "--with-freetype-license="
+ input.get("freetype", "install_path")
+ "/freetype-2.7.1-v120-x64/freetype.md"
} }
}; };
profiles = concatObjects(profiles, profilesRiFreetype); profiles = concatObjects(profiles, profilesRiFreetype);

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -36,7 +36,7 @@ ifneq ($(OPENJDK_TARGET_OS), windows)
ifeq ($(STATIC_BUILD), false) ifeq ($(STATIC_BUILD), false)
ifeq ($(OPENJDK_TARGET_OS), linux) ifeq ($(OPENJDK_TARGET_OS), linux)
LIBJSIG_CFLAGS := -fPIC -D_GNU_SOURCE -D_REENTRANT $(EXTRA_CFLAGS) LIBJSIG_CFLAGS := -fPIC -D_GNU_SOURCE -D_REENTRANT $(EXTRA_CFLAGS)
LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) $(EXTRA_CFLAGS) LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) ${LDFLAGS_NO_EXEC_STACK} $(EXTRA_CFLAGS)
LIBJSIG_LIBS := $(LIBDL) LIBJSIG_LIBS := $(LIBDL)
# NOTE: The old build compiled this library without -soname. # NOTE: The old build compiled this library without -soname.

View file

@ -57,8 +57,8 @@ public class TransitiveDependencies {
} }
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
List<String> options = Arrays.asList("-source", "9", List<String> options = Arrays.asList("-source", "10",
"-target", "9", "-target", "10",
"-proc:only", "-proc:only",
"--system", "none", "--system", "none",
"--module-source-path", args[0], "--module-source-path", args[0],

View file

@ -174,8 +174,6 @@
<target name="compile" depends="prepare" description="Compiles nashorn"> <target name="compile" depends="prepare" description="Compiles nashorn">
<javac srcdir="${dynalink.module.src.dir}" <javac srcdir="${dynalink.module.src.dir}"
destdir="${dynalink.module.classes.dir}" destdir="${dynalink.module.classes.dir}"
source="${javac.source}"
target="${javac.target}"
debug="${javac.debug}" debug="${javac.debug}"
encoding="${javac.encoding}" encoding="${javac.encoding}"
includeantruntime="false" fork="true"> includeantruntime="false" fork="true">
@ -190,8 +188,6 @@
</delete> </delete>
<javac srcdir="${nashorn.module.src.dir}" <javac srcdir="${nashorn.module.src.dir}"
destdir="${nashorn.module.classes.dir}" destdir="${nashorn.module.classes.dir}"
source="${javac.source}"
target="${javac.target}"
debug="${javac.debug}" debug="${javac.debug}"
encoding="${javac.encoding}" encoding="${javac.encoding}"
includeantruntime="false" fork="true"> includeantruntime="false" fork="true">
@ -207,8 +203,6 @@
</delete> </delete>
<javac srcdir="${nashorn.shell.module.src.dir}" <javac srcdir="${nashorn.shell.module.src.dir}"
destdir="${nashorn.shell.module.classes.dir}" destdir="${nashorn.shell.module.classes.dir}"
source="${javac.source}"
target="${javac.target}"
debug="${javac.debug}" debug="${javac.debug}"
encoding="${javac.encoding}" encoding="${javac.encoding}"
includeantruntime="false" fork="true"> includeantruntime="false" fork="true">
@ -342,8 +336,6 @@
<javac srcdir="${test.src.dir}" <javac srcdir="${test.src.dir}"
destdir="${build.test.classes.dir}" destdir="${build.test.classes.dir}"
classpath="${javac.test.classpath}" classpath="${javac.test.classpath}"
source="${javac.source}"
target="${javac.target}"
debug="${javac.debug}" debug="${javac.debug}"
encoding="${javac.encoding}" encoding="${javac.encoding}"
includeantruntime="false" fork="true"> includeantruntime="false" fork="true">
@ -351,7 +343,7 @@
<compilerarg value="-Xlint:unchecked"/> <compilerarg value="-Xlint:unchecked"/>
<compilerarg value="-Xlint:deprecation"/> <compilerarg value="-Xlint:deprecation"/>
<compilerarg value="-Xdiags:verbose"/> <compilerarg value="-Xdiags:verbose"/>
<compilerarg line="${test.module.imports}"/> <compilerarg line="${test.module.imports.compile.time}"/>
</javac> </javac>
<copy todir="${build.test.classes.dir}/META-INF/services"> <copy todir="${build.test.classes.dir}/META-INF/services">

View file

@ -24,8 +24,6 @@ application.title=nasgen
# source and target levels # source and target levels
build.compiler=modern build.compiler=modern
javac.source=1.7
javac.target=1.7
# This directory is removed when the project is cleaned: # This directory is removed when the project is cleaned:
nasgen.build.dir=../../../../build/nashorn/nasgen nasgen.build.dir=../../../../build/nashorn/nasgen

View file

@ -24,8 +24,6 @@ application.title=nashorntask
# source and target levels # source and target levels
build.compiler=modern build.compiler=modern
javac.source=1.8
javac.target=1.8
# This directory is removed when the project is cleaned: # This directory is removed when the project is cleaned:
nashorntask.build.dir=../../../../build/nashorn/nashorntask nashorntask.build.dir=../../../../build/nashorn/nashorntask

View file

@ -32,8 +32,6 @@ jdk.jline.src.dir=src/jdk.internal.le/share/classes
# source and target levels # source and target levels
build.compiler=modern build.compiler=modern
javac.source=1.9
javac.target=1.9
javadoc.option=\ javadoc.option=\
-tag "implSpec:a:Implementation Requirements:" \ -tag "implSpec:a:Implementation Requirements:" \
@ -146,7 +144,7 @@ javac.test.classpath=\
${file.reference.bsh.jar}${path.separator}\ ${file.reference.bsh.jar}${path.separator}\
${file.reference.snakeyaml.jar} ${file.reference.snakeyaml.jar}
test.module.imports=\ test.module.imports.compile.time=\
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.ir=ALL-UNNAMED \ --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.ir=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.codegen=ALL-UNNAMED \ --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.codegen=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.parser=ALL-UNNAMED \ --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.parser=ALL-UNNAMED \
@ -159,7 +157,10 @@ test.module.imports=\
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp=ALL-UNNAMED \ --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp.joni=ALL-UNNAMED \ --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp.joni=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.tools=ALL-UNNAMED \ --add-exports jdk.scripting.nashorn/jdk.nashorn.tools=ALL-UNNAMED \
--add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \ --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED
test.module.imports.runtime=\
${test.module.imports.compile.time} \
--add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime=ALL-UNNAMED \ --add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime=ALL-UNNAMED \
--add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime.doubleconv=ALL-UNNAMED --add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime.doubleconv=ALL-UNNAMED
@ -359,7 +360,7 @@ run.test.user.country=TR
run.test.jvmargs.common=\ run.test.jvmargs.common=\
-server \ -server \
${test.module.imports} \ ${test.module.imports.runtime} \
${run.test.jvmargs.external} \ ${run.test.jvmargs.external} \
--add-modules jdk.scripting.nashorn.shell \ --add-modules jdk.scripting.nashorn.shell \
${nashorn.override.option} \ ${nashorn.override.option} \

View file

@ -73,6 +73,9 @@
#include "utilities/nativeCallStack.hpp" #include "utilities/nativeCallStack.hpp"
#endif // INCLUDE_NMT #endif // INCLUDE_NMT
#ifdef LINUX
#include "utilities/elfFile.hpp"
#endif
#define SIZE_T_MAX_VALUE ((size_t) -1) #define SIZE_T_MAX_VALUE ((size_t) -1)
@ -1823,6 +1826,20 @@ WB_ENTRY(void, WB_RemoveCompilerDirective(JNIEnv* env, jobject o, jint count))
DirectivesStack::pop(count); DirectivesStack::pop(count);
WB_END WB_END
// Checks that the library libfile has the noexecstack bit set.
WB_ENTRY(jboolean, WB_CheckLibSpecifiesNoexecstack(JNIEnv* env, jobject o, jstring libfile))
jboolean ret = false;
#ifdef LINUX
// Can't be in VM when we call JNI.
ThreadToNativeFromVM ttnfv(thread);
const char* lf = env->GetStringUTFChars(libfile, NULL);
CHECK_JNI_EXCEPTION_(env, 0);
ret = (jboolean) ElfFile::specifies_noexecstack(lf);
env->ReleaseStringUTFChars(libfile, lf);
#endif
return ret;
WB_END
#define CC (char*) #define CC (char*)
static JNINativeMethod methods[] = { static JNINativeMethod methods[] = {
@ -2027,6 +2044,8 @@ static JNINativeMethod methods[] = {
(void*)&WB_GetConcurrentGCPhases}, (void*)&WB_GetConcurrentGCPhases},
{CC"requestConcurrentGCPhase0", CC"(Ljava/lang/String;)Z", {CC"requestConcurrentGCPhase0", CC"(Ljava/lang/String;)Z",
(void*)&WB_RequestConcurrentGCPhase}, (void*)&WB_RequestConcurrentGCPhase},
{CC"checkLibSpecifiesNoexecstack", CC"(Ljava/lang/String;)Z",
(void*)&WB_CheckLibSpecifiesNoexecstack},
}; };
#undef CC #undef CC

View file

@ -2160,10 +2160,12 @@ public abstract class ClassLoader {
* if a package of the given {@code name} is already * if a package of the given {@code name} is already
* defined by this class loader * defined by this class loader
* *
*
* @since 1.2 * @since 1.2
* @revised 9 * @revised 9
* @spec JPMS * @spec JPMS
* *
* @jvms 5.3 Run-time package
* @see <a href="{@docRoot}/../specs/jar/jar.html#sealing"> * @see <a href="{@docRoot}/../specs/jar/jar.html#sealing">
* The JAR File Specification: Package Sealing</a> * The JAR File Specification: Package Sealing</a>
*/ */
@ -2186,17 +2188,19 @@ public abstract class ClassLoader {
} }
/** /**
* Returns a {@code Package} of the given <a href="#name">name</a> that has been * Returns a {@code Package} of the given <a href="#name">name</a> that
* defined by this class loader. * has been defined by this class loader.
* *
* @param name The <a href="#name">package name</a> * @param name The <a href="#name">package name</a>
* *
* @return The {@code Package} of the given name defined by this class loader, * @return The {@code Package} of the given name that has been defined
* or {@code null} if not found * by this class loader, or {@code null} if not found
* *
* @throws NullPointerException * @throws NullPointerException
* if {@code name} is {@code null}. * if {@code name} is {@code null}.
* *
* @jvms 5.3 Run-time package
*
* @since 9 * @since 9
* @spec JPMS * @spec JPMS
*/ */
@ -2211,14 +2215,18 @@ public abstract class ClassLoader {
} }
/** /**
* Returns all of the {@code Package}s defined by this class loader. * Returns all of the {@code Package}s that have been defined by
* The returned array has no duplicated {@code Package}s of the same name. * this class loader. The returned array has no duplicated {@code Package}s
* of the same name.
* *
* @apiNote This method returns an array rather than a {@code Set} or {@code Stream} * @apiNote This method returns an array rather than a {@code Set} or {@code Stream}
* for consistency with the existing {@link #getPackages} method. * for consistency with the existing {@link #getPackages} method.
* *
* @return The array of {@code Package} objects defined by this class loader; * @return The array of {@code Package} objects that have been defined by
* or an zero length array if no package has been defined by this class loader. * this class loader; or an zero length array if no package has been
* defined by this class loader.
*
* @jvms 5.3 Run-time package
* *
* @since 9 * @since 9
* @spec JPMS * @spec JPMS
@ -2244,7 +2252,7 @@ public abstract class ClassLoader {
* @param name * @param name
* The <a href="#name">package name</a> * The <a href="#name">package name</a>
* *
* @return The {@code Package} corresponding to the given name defined by * @return The {@code Package} of the given name that has been defined by
* this class loader or its ancestors, or {@code null} if not found. * this class loader or its ancestors, or {@code null} if not found.
* *
* @throws NullPointerException * @throws NullPointerException
@ -2263,6 +2271,8 @@ public abstract class ClassLoader {
* {@link ClassLoader#getDefinedPackage} method which returns * {@link ClassLoader#getDefinedPackage} method which returns
* a {@code Package} for the specified class loader. * a {@code Package} for the specified class loader.
* *
* @see ClassLoader#getDefinedPackage(String)
*
* @since 1.2 * @since 1.2
* @revised 9 * @revised 9
* @spec JPMS * @spec JPMS
@ -2281,10 +2291,10 @@ public abstract class ClassLoader {
} }
/** /**
* Returns all of the {@code Package}s defined by this class loader * Returns all of the {@code Package}s that have been defined by
* and its ancestors. The returned array may contain more than one * this class loader and its ancestors. The returned array may contain
* {@code Package} object of the same package name, each defined by * more than one {@code Package} object of the same package name, each
* a different class loader in the class loader hierarchy. * defined by a different class loader in the class loader hierarchy.
* *
* @apiNote The {@link #getPlatformClassLoader() platform class loader} * @apiNote The {@link #getPlatformClassLoader() platform class loader}
* may delegate to the application class loader. In other words, * may delegate to the application class loader. In other words,
@ -2294,8 +2304,10 @@ public abstract class ClassLoader {
* when invoked on the platform class loader, this method will not * when invoked on the platform class loader, this method will not
* return any packages defined to the application class loader. * return any packages defined to the application class loader.
* *
* @return The array of {@code Package} objects defined by this * @return The array of {@code Package} objects that have been defined by
* class loader and its ancestors * this class loader and its ancestors
*
* @see ClassLoader#getDefinedPackages()
* *
* @since 1.2 * @since 1.2
* @revised 9 * @revised 9

View file

@ -29,6 +29,7 @@ import jdk.internal.misc.SharedSecrets;
import static java.lang.StackWalker.Option.*; import static java.lang.StackWalker.Option.*;
import java.lang.StackWalker.StackFrame; import java.lang.StackWalker.StackFrame;
import java.lang.invoke.MethodType;
class StackFrameInfo implements StackFrame { class StackFrameInfo implements StackFrame {
private final static JavaLangInvokeAccess JLIA = private final static JavaLangInvokeAccess JLIA =
@ -78,6 +79,17 @@ class StackFrameInfo implements StackFrame {
return JLIA.getName(memberName); return JLIA.getName(memberName);
} }
@Override
public MethodType getMethodType() {
walker.ensureAccessEnabled(RETAIN_CLASS_REFERENCE);
return JLIA.getMethodType(memberName);
}
@Override
public String getDescriptor() {
return JLIA.getMethodDescriptor(memberName);
}
@Override @Override
public int getByteCodeIndex() { public int getByteCodeIndex() {
// bci not available for native methods // bci not available for native methods

View file

@ -26,10 +26,12 @@ package java.lang;
import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.CallerSensitive;
import java.util.*; import java.lang.invoke.MethodType;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
@ -96,7 +98,7 @@ public final class StackWalker {
* @since 9 * @since 9
* @jvms 2.6 * @jvms 2.6
*/ */
public static interface StackFrame { public interface StackFrame {
/** /**
* Gets the <a href="ClassLoader.html#name">binary name</a> * Gets the <a href="ClassLoader.html#name">binary name</a>
* of the declaring class of the method represented by this stack frame. * of the declaring class of the method represented by this stack frame.
@ -127,6 +129,47 @@ public final class StackWalker {
*/ */
public Class<?> getDeclaringClass(); public Class<?> getDeclaringClass();
/**
* Returns the {@link MethodType} representing the parameter types and
* the return type for the method represented by this stack frame.
*
* @implSpec
* The default implementation throws {@code UnsupportedOperationException}.
*
* @return the {@code MethodType} for this stack frame
*
* @throws UnsupportedOperationException if this {@code StackWalker}
* is not configured with {@link Option#RETAIN_CLASS_REFERENCE
* Option.RETAIN_CLASS_REFERENCE}.
*
* @since 10
*/
public default MethodType getMethodType() {
throw new UnsupportedOperationException();
}
/**
* Returns the <i>descriptor</i> of the method represented by
* this stack frame as defined by
* <cite>The Java Virtual Machine Specification</cite>.
*
* @implSpec
* The default implementation throws {@code UnsupportedOperationException}.
*
* @return the descriptor of the method represented by
* this stack frame
*
* @see MethodType#fromMethodDescriptorString(String, ClassLoader)
* @see MethodType#toMethodDescriptorString()
* @jvms 4.3.3 Method Descriptor
*
* @since 10
*/
public default String getDescriptor() {
throw new UnsupportedOperationException();
}
/** /**
* Returns the index to the code array of the {@code Code} attribute * Returns the index to the code array of the {@code Code} attribute
* containing the execution point represented by this stack frame. * containing the execution point represented by this stack frame.

View file

@ -28,6 +28,7 @@ package java.lang.invoke;
import java.util.Arrays; import java.util.Arrays;
import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.LambdaForm.Kind.*; import static java.lang.invoke.LambdaForm.Kind.*;
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
/** /**
@ -158,8 +159,11 @@ abstract class DelegatingMethodHandle extends MethodHandle {
static final NamedFunction NF_getTarget; static final NamedFunction NF_getTarget;
static { static {
try { try {
NF_getTarget = new NamedFunction(DelegatingMethodHandle.class MemberName member = new MemberName(DelegatingMethodHandle.class, "getTarget",
.getDeclaredMethod("getTarget")); MethodType.methodType(MethodHandle.class), REF_invokeVirtual);
NF_getTarget = new NamedFunction(
MemberName.getFactory()
.resolveOrFail(REF_invokeVirtual, member, DelegatingMethodHandle.class, NoSuchMethodException.class));
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
throw newInternalError(ex); throw newInternalError(ex);
} }

View file

@ -753,42 +753,38 @@ class DirectMethodHandle extends MethodHandle {
return nf; return nf;
} }
private static final MethodType OBJ_OBJ_TYPE = MethodType.methodType(Object.class, Object.class);
private static final MethodType LONG_OBJ_TYPE = MethodType.methodType(long.class, Object.class);
private static NamedFunction createFunction(byte func) { private static NamedFunction createFunction(byte func) {
try { try {
switch (func) { switch (func) {
case NF_internalMemberName: case NF_internalMemberName:
return new NamedFunction(DirectMethodHandle.class return getNamedFunction("internalMemberName", OBJ_OBJ_TYPE);
.getDeclaredMethod("internalMemberName", Object.class));
case NF_internalMemberNameEnsureInit: case NF_internalMemberNameEnsureInit:
return new NamedFunction(DirectMethodHandle.class return getNamedFunction("internalMemberNameEnsureInit", OBJ_OBJ_TYPE);
.getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
case NF_ensureInitialized: case NF_ensureInitialized:
return new NamedFunction(DirectMethodHandle.class return getNamedFunction("ensureInitialized", MethodType.methodType(void.class, Object.class));
.getDeclaredMethod("ensureInitialized", Object.class));
case NF_fieldOffset: case NF_fieldOffset:
return new NamedFunction(DirectMethodHandle.class return getNamedFunction("fieldOffset", LONG_OBJ_TYPE);
.getDeclaredMethod("fieldOffset", Object.class));
case NF_checkBase: case NF_checkBase:
return new NamedFunction(DirectMethodHandle.class return getNamedFunction("checkBase", OBJ_OBJ_TYPE);
.getDeclaredMethod("checkBase", Object.class));
case NF_staticBase: case NF_staticBase:
return new NamedFunction(DirectMethodHandle.class return getNamedFunction("staticBase", OBJ_OBJ_TYPE);
.getDeclaredMethod("staticBase", Object.class));
case NF_staticOffset: case NF_staticOffset:
return new NamedFunction(DirectMethodHandle.class return getNamedFunction("staticOffset", LONG_OBJ_TYPE);
.getDeclaredMethod("staticOffset", Object.class));
case NF_checkCast: case NF_checkCast:
return new NamedFunction(DirectMethodHandle.class return getNamedFunction("checkCast", MethodType.methodType(Object.class, Object.class, Object.class));
.getDeclaredMethod("checkCast", Object.class, Object.class));
case NF_allocateInstance: case NF_allocateInstance:
return new NamedFunction(DirectMethodHandle.class return getNamedFunction("allocateInstance", OBJ_OBJ_TYPE);
.getDeclaredMethod("allocateInstance", Object.class));
case NF_constructorMethod: case NF_constructorMethod:
return new NamedFunction(DirectMethodHandle.class return getNamedFunction("constructorMethod", OBJ_OBJ_TYPE);
.getDeclaredMethod("constructorMethod", Object.class));
case NF_UNSAFE: case NF_UNSAFE:
return new NamedFunction(new MemberName(MethodHandleStatics.class MemberName member = new MemberName(MethodHandleStatics.class, "UNSAFE", Unsafe.class, REF_getField);
.getDeclaredField("UNSAFE"))); return new NamedFunction(
MemberName.getFactory()
.resolveOrFail(REF_getField, member, DirectMethodHandle.class, NoSuchMethodException.class));
default: default:
throw newInternalError("Unknown function: " + func); throw newInternalError("Unknown function: " + func);
} }
@ -797,6 +793,15 @@ class DirectMethodHandle extends MethodHandle {
} }
} }
private static NamedFunction getNamedFunction(String name, MethodType type)
throws ReflectiveOperationException
{
MemberName member = new MemberName(DirectMethodHandle.class, name, type, REF_invokeStatic);
return new NamedFunction(
MemberName.getFactory()
.resolveOrFail(REF_invokeStatic, member, DirectMethodHandle.class, NoSuchMethodException.class));
}
static { static {
// The Holder class will contain pre-generated DirectMethodHandles resolved // The Holder class will contain pre-generated DirectMethodHandles resolved
// speculatively using MemberName.getFactory().resolveOrNull. However, that // speculatively using MemberName.getFactory().resolveOrNull. However, that

View file

@ -611,23 +611,17 @@ class Invokers {
try { try {
switch (func) { switch (func) {
case NF_checkExactType: case NF_checkExactType:
return new NamedFunction(Invokers.class return getNamedFunction("checkExactType", MethodType.methodType(void.class, MethodHandle.class, MethodType.class));
.getDeclaredMethod("checkExactType", MethodHandle.class, MethodType.class));
case NF_checkGenericType: case NF_checkGenericType:
return new NamedFunction(Invokers.class return getNamedFunction("checkGenericType", MethodType.methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
.getDeclaredMethod("checkGenericType", MethodHandle.class, MethodType.class));
case NF_getCallSiteTarget: case NF_getCallSiteTarget:
return new NamedFunction(Invokers.class return getNamedFunction("getCallSiteTarget", MethodType.methodType(MethodHandle.class, CallSite.class));
.getDeclaredMethod("getCallSiteTarget", CallSite.class));
case NF_checkCustomized: case NF_checkCustomized:
return new NamedFunction(Invokers.class return getNamedFunction("checkCustomized", MethodType.methodType(void.class, MethodHandle.class));
.getDeclaredMethod("checkCustomized", MethodHandle.class));
case NF_checkVarHandleGenericType: case NF_checkVarHandleGenericType:
return new NamedFunction(Invokers.class return getNamedFunction("checkVarHandleGenericType", MethodType.methodType(MethodHandle.class, VarHandle.class, VarHandle.AccessDescriptor.class));
.getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class));
case NF_checkVarHandleExactType: case NF_checkVarHandleExactType:
return new NamedFunction(Invokers.class return getNamedFunction("checkVarHandleExactType", MethodType.methodType(MethodHandle.class, VarHandle.class, VarHandle.AccessDescriptor.class));
.getDeclaredMethod("checkVarHandleExactType", VarHandle.class, VarHandle.AccessDescriptor.class));
default: default:
throw newInternalError("Unknown function: " + func); throw newInternalError("Unknown function: " + func);
} }
@ -636,6 +630,15 @@ class Invokers {
} }
} }
private static NamedFunction getNamedFunction(String name, MethodType type)
throws ReflectiveOperationException
{
MemberName member = new MemberName(Invokers.class, name, type, REF_invokeStatic);
return new NamedFunction(
MemberName.getFactory()
.resolveOrFail(REF_invokeStatic, member, Invokers.class, NoSuchMethodException.class));
}
private static class Lazy { private static class Lazy {
private static final MethodHandle MH_asSpreader; private static final MethodHandle MH_asSpreader;

View file

@ -162,6 +162,29 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
return (MethodType) type; return (MethodType) type;
} }
/** Return the descriptor of this member, which
* must be a method or constructor.
*/
String getMethodDescriptor() {
if (type == null) {
expandFromVM();
if (type == null) {
return null;
}
}
if (!isInvocable()) {
throw newIllegalArgumentException("not invocable, no method type");
}
// Get a snapshot of type which doesn't get changed by racing threads.
final Object type = this.type;
if (type instanceof String) {
return (String) type;
} else {
return getMethodType().toMethodDescriptorString();
}
}
/** Return the actual type under which this method or constructor must be invoked. /** Return the actual type under which this method or constructor must be invoked.
* For non-static methods or constructors, this is the type with a leading parameter, * For non-static methods or constructors, this is the type with a leading parameter,
* a reference to declaring class. For static methods, it is the same as the declared type. * a reference to declaring class. For static methods, it is the same as the declared type.

View file

@ -1785,6 +1785,18 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
return memberName.getName(); return memberName.getName();
} }
@Override
public MethodType getMethodType(Object mname) {
MemberName memberName = (MemberName)mname;
return memberName.getMethodType();
}
@Override
public String getMethodDescriptor(Object mname) {
MemberName memberName = (MemberName)mname;
return memberName.getMethodDescriptor();
}
@Override @Override
public boolean isNative(Object mname) { public boolean isNative(Object mname) {
MemberName memberName = (MemberName)mname; MemberName memberName = (MemberName)mname;

View file

@ -211,7 +211,7 @@ public class ArrayDeque<E> extends AbstractCollection<E>
} }
/** /**
* Increments i, mod modulus. * Circularly increments i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus. * Precondition and postcondition: 0 <= i < modulus.
*/ */
static final int inc(int i, int modulus) { static final int inc(int i, int modulus) {
@ -220,7 +220,7 @@ public class ArrayDeque<E> extends AbstractCollection<E>
} }
/** /**
* Decrements i, mod modulus. * Circularly decrements i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus. * Precondition and postcondition: 0 <= i < modulus.
*/ */
static final int dec(int i, int modulus) { static final int dec(int i, int modulus) {
@ -233,7 +233,7 @@ public class ArrayDeque<E> extends AbstractCollection<E>
* Precondition: 0 <= i < modulus, 0 <= distance <= modulus. * Precondition: 0 <= i < modulus, 0 <= distance <= modulus.
* @return index 0 <= i < modulus * @return index 0 <= i < modulus
*/ */
static final int add(int i, int distance, int modulus) { static final int inc(int i, int distance, int modulus) {
if ((i += distance) - modulus >= 0) i -= modulus; if ((i += distance) - modulus >= 0) i -= modulus;
return i; return i;
} }
@ -825,7 +825,7 @@ public class ArrayDeque<E> extends AbstractCollection<E>
final int i, n; final int i, n;
return ((n = sub(getFence(), i = cursor, es.length) >> 1) <= 0) return ((n = sub(getFence(), i = cursor, es.length) >> 1) <= 0)
? null ? null
: new DeqSpliterator(i, cursor = add(i, n, es.length)); : new DeqSpliterator(i, cursor = inc(i, n, es.length));
} }
public void forEachRemaining(Consumer<? super E> action) { public void forEachRemaining(Consumer<? super E> action) {

View file

@ -490,7 +490,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
} }
/** /**
* Implements Map.putAll and Map constructor * Implements Map.putAll and Map constructor.
* *
* @param m the map * @param m the map
* @param evict false when initially constructing this map, else * @param evict false when initially constructing this map, else
@ -557,7 +557,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
} }
/** /**
* Implements Map.get and related methods * Implements Map.get and related methods.
* *
* @param hash hash for key * @param hash hash for key
* @param key the key * @param key the key
@ -612,7 +612,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
} }
/** /**
* Implements Map.put and related methods * Implements Map.put and related methods.
* *
* @param hash hash for key * @param hash hash for key
* @param key the key * @param key the key
@ -700,7 +700,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
} }
threshold = newThr; threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"}) @SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab; table = newTab;
if (oldTab != null) { if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) { for (int j = 0; j < oldCap; ++j) {
@ -800,7 +800,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
} }
/** /**
* Implements Map.remove and related methods * Implements Map.remove and related methods.
* *
* @param hash hash for key * @param hash hash for key
* @param key the key * @param key the key
@ -875,7 +875,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
public boolean containsValue(Object value) { public boolean containsValue(Object value) {
Node<K,V>[] tab; V v; Node<K,V>[] tab; V v;
if ((tab = table) != null && size > 0) { if ((tab = table) != null && size > 0) {
for (Node<K, V> e : tab) { for (Node<K,V> e : tab) {
for (; e != null; e = e.next) { for (; e != null; e = e.next) {
if ((v = e.value) == value || if ((v = e.value) == value ||
(value != null && value.equals(v))) (value != null && value.equals(v)))
@ -927,7 +927,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
throw new NullPointerException(); throw new NullPointerException();
if (size > 0 && (tab = table) != null) { if (size > 0 && (tab = table) != null) {
int mc = modCount; int mc = modCount;
for (Node<K, V> e : tab) { for (Node<K,V> e : tab) {
for (; e != null; e = e.next) for (; e != null; e = e.next)
action.accept(e.key); action.accept(e.key);
} }
@ -975,7 +975,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
throw new NullPointerException(); throw new NullPointerException();
if (size > 0 && (tab = table) != null) { if (size > 0 && (tab = table) != null) {
int mc = modCount; int mc = modCount;
for (Node<K, V> e : tab) { for (Node<K,V> e : tab) {
for (; e != null; e = e.next) for (; e != null; e = e.next)
action.accept(e.value); action.accept(e.value);
} }
@ -1038,7 +1038,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
throw new NullPointerException(); throw new NullPointerException();
if (size > 0 && (tab = table) != null) { if (size > 0 && (tab = table) != null) {
int mc = modCount; int mc = modCount;
for (Node<K, V> e : tab) { for (Node<K,V> e : tab) {
for (; e != null; e = e.next) for (; e != null; e = e.next)
action.accept(e); action.accept(e);
} }
@ -1335,7 +1335,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
throw new NullPointerException(); throw new NullPointerException();
if (size > 0 && (tab = table) != null) { if (size > 0 && (tab = table) != null) {
int mc = modCount; int mc = modCount;
for (Node<K, V> e : tab) { for (Node<K,V> e : tab) {
for (; e != null; e = e.next) for (; e != null; e = e.next)
action.accept(e.key, e.value); action.accept(e.key, e.value);
} }
@ -1351,7 +1351,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
throw new NullPointerException(); throw new NullPointerException();
if (size > 0 && (tab = table) != null) { if (size > 0 && (tab = table) != null) {
int mc = modCount; int mc = modCount;
for (Node<K, V> e : tab) { for (Node<K,V> e : tab) {
for (; e != null; e = e.next) { for (; e != null; e = e.next) {
e.value = function.apply(e.key, e.value); e.value = function.apply(e.key, e.value);
} }
@ -1394,9 +1394,10 @@ public class HashMap<K,V> extends AbstractMap<K,V>
} }
/** /**
* Save the state of the {@code HashMap} instance to a stream (i.e., * Saves this map to a stream (that is, serializes it).
* serialize it).
* *
* @param s the stream
* @throws IOException if an I/O error occurs
* @serialData The <i>capacity</i> of the HashMap (the length of the * @serialData The <i>capacity</i> of the HashMap (the length of the
* bucket array) is emitted (int), followed by the * bucket array) is emitted (int), followed by the
* <i>size</i> (an int, the number of key-value * <i>size</i> (an int, the number of key-value
@ -1415,8 +1416,11 @@ public class HashMap<K,V> extends AbstractMap<K,V>
} }
/** /**
* Reconstitute the {@code HashMap} instance from a stream (i.e., * Reconstitutes this map from a stream (that is, deserializes it).
* deserialize it). * @param s the stream
* @throws ClassNotFoundException if the class of a serialized object
* could not be found
* @throws IOException if an I/O error occurs
*/ */
private void readObject(java.io.ObjectInputStream s) private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException { throws IOException, ClassNotFoundException {
@ -1445,7 +1449,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ? threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
(int)ft : Integer.MAX_VALUE); (int)ft : Integer.MAX_VALUE);
@SuppressWarnings({"rawtypes","unchecked"}) @SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] tab = (Node<K,V>[])new Node[cap]; Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
table = tab; table = tab;
// Read the keys and values, and put the mappings in the HashMap // Read the keys and values, and put the mappings in the HashMap
@ -1830,7 +1834,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException { void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
Node<K,V>[] tab; Node<K,V>[] tab;
if (size > 0 && (tab = table) != null) { if (size > 0 && (tab = table) != null) {
for (Node<K, V> e : tab) { for (Node<K,V> e : tab) {
for (; e != null; e = e.next) { for (; e != null; e = e.next) {
s.writeObject(e.key); s.writeObject(e.key);
s.writeObject(e.value); s.writeObject(e.value);
@ -1951,7 +1955,6 @@ public class HashMap<K,V> extends AbstractMap<K,V>
/** /**
* Forms tree of the nodes linked from this node. * Forms tree of the nodes linked from this node.
* @return root of tree
*/ */
final void treeify(Node<K,V>[] tab) { final void treeify(Node<K,V>[] tab) {
TreeNode<K,V> root = null; TreeNode<K,V> root = null;
@ -2089,8 +2092,11 @@ public class HashMap<K,V> extends AbstractMap<K,V>
return; return;
if (root.parent != null) if (root.parent != null)
root = root.root(); root = root.root();
if (root == null || root.right == null || if (root == null
(rl = root.left) == null || rl.left == null) { || (movable
&& (root.right == null
|| (rl = root.left) == null
|| rl.left == null))) {
tab[index] = first.untreeify(map); // too small tab[index] = first.untreeify(map); // too small
return; return;
} }
@ -2319,7 +2325,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root, static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
TreeNode<K,V> x) { TreeNode<K,V> x) {
for (TreeNode<K,V> xp, xpl, xpr;;) { for (TreeNode<K,V> xp, xpl, xpr;;) {
if (x == null || x == root) if (x == null || x == root)
return root; return root;
else if ((xp = x.parent) == null) { else if ((xp = x.parent) == null) {

View file

@ -2490,13 +2490,13 @@ public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
for (Completion p = stack; p != null; p = p.next) for (Completion p = stack; p != null; p = p.next)
++count; ++count;
return super.toString() + return super.toString() +
((r == null) ? ((r == null)
((count == 0) ? ? ((count == 0)
"[Not completed]" : ? "[Not completed]"
"[Not completed, " + count + " dependents]") : : "[Not completed, " + count + " dependents]")
(((r instanceof AltResult) && ((AltResult)r).ex != null) ? : (((r instanceof AltResult) && ((AltResult)r).ex != null)
"[Completed exceptionally]" : ? "[Completed exceptionally: " + ((AltResult)r).ex + "]"
"[Completed normally]")); : "[Completed normally]"));
} }
// jdk9 additions // jdk9 additions

View file

@ -1394,8 +1394,8 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
} }
/** /**
* Saves the state of the {@code ConcurrentHashMap} instance to a * Saves this map to a stream (that is, serializes it).
* stream (i.e., serializes it). *
* @param s the stream * @param s the stream
* @throws java.io.IOException if an I/O error occurs * @throws java.io.IOException if an I/O error occurs
* @serialData * @serialData
@ -1439,7 +1439,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
} }
/** /**
* Reconstitutes the instance from a stream (that is, deserializes it). * Reconstitutes this map from a stream (that is, deserializes it).
* @param s the stream * @param s the stream
* @throws ClassNotFoundException if the class of a serialized object * @throws ClassNotFoundException if the class of a serialized object
* could not be found * could not be found

View file

@ -174,6 +174,10 @@ public class ExecutorCompletionService<V> implements CompletionService<V> {
this.completionQueue = completionQueue; this.completionQueue = completionQueue;
} }
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public Future<V> submit(Callable<V> task) { public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException(); if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task); RunnableFuture<V> f = newTaskFor(task);
@ -181,6 +185,10 @@ public class ExecutorCompletionService<V> implements CompletionService<V> {
return f; return f;
} }
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public Future<V> submit(Runnable task, V result) { public Future<V> submit(Runnable task, V result) {
if (task == null) throw new NullPointerException(); if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task, result); RunnableFuture<V> f = newTaskFor(task, result);

View file

@ -514,6 +514,9 @@ public class Executors {
task.run(); task.run();
return result; return result;
} }
public String toString() {
return super.toString() + "[Wrapped task = " + task + "]";
}
} }
/** /**
@ -540,6 +543,10 @@ public class Executors {
throw e.getException(); throw e.getException();
} }
} }
public String toString() {
return super.toString() + "[Wrapped task = " + task + "]";
}
} }
/** /**
@ -592,6 +599,10 @@ public class Executors {
throw e.getException(); throw e.getException();
} }
} }
public String toString() {
return super.toString() + "[Wrapped task = " + task + "]";
}
} }
/** /**

View file

@ -1375,6 +1375,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
public final void setRawResult(T v) { result = v; } public final void setRawResult(T v) { result = v; }
public final boolean exec() { runnable.run(); return true; } public final boolean exec() { runnable.run(); return true; }
public final void run() { invoke(); } public final void run() { invoke(); }
public String toString() {
return super.toString() + "[Wrapped task = " + runnable + "]";
}
private static final long serialVersionUID = 5232453952276885070L; private static final long serialVersionUID = 5232453952276885070L;
} }
@ -1392,6 +1395,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
public final void setRawResult(Void v) { } public final void setRawResult(Void v) { }
public final boolean exec() { runnable.run(); return true; } public final boolean exec() { runnable.run(); return true; }
public final void run() { invoke(); } public final void run() { invoke(); }
public String toString() {
return super.toString() + "[Wrapped task = " + runnable + "]";
}
private static final long serialVersionUID = 5232453952276885070L; private static final long serialVersionUID = 5232453952276885070L;
} }
@ -1437,6 +1443,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
} }
} }
public final void run() { invoke(); } public final void run() { invoke(); }
public String toString() {
return super.toString() + "[Wrapped task = " + callable + "]";
}
private static final long serialVersionUID = 2838392045355241008L; private static final long serialVersionUID = 2838392045355241008L;
} }

View file

@ -480,6 +480,41 @@ public class FutureTask<V> implements RunnableFuture<V> {
} }
} }
/**
* Returns a string representation of this FutureTask.
*
* @implSpec
* The default implementation returns a string identifying this
* FutureTask, as well as its completion state. The state, in
* brackets, contains one of the strings {@code "Completed Normally"},
* {@code "Completed Exceptionally"}, {@code "Cancelled"}, or {@code
* "Not completed"}.
*
* @return a string representation of this FutureTask
*/
public String toString() {
final String status;
switch (state) {
case NORMAL:
status = "[Completed normally]";
break;
case EXCEPTIONAL:
status = "[Completed exceptionally: " + outcome + "]";
break;
case CANCELLED:
case INTERRUPTING:
case INTERRUPTED:
status = "[Cancelled]";
break;
default:
final Callable<?> callable = this.callable;
status = (callable == null)
? "[Not completed]"
: "[Not completed, task = " + callable + "]";
}
return super.toString() + status;
}
// VarHandle mechanics // VarHandle mechanics
private static final VarHandle STATE; private static final VarHandle STATE;
private static final VarHandle RUNNER; private static final VarHandle RUNNER;

View file

@ -383,7 +383,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
*/ */
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3; private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1; private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits // runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS; private static final int RUNNING = -1 << COUNT_BITS;
@ -393,8 +393,8 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
private static final int TERMINATED = 3 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl // Packing and unpacking ctl
private static int runStateOf(int c) { return c & ~CAPACITY; } private static int runStateOf(int c) { return c & ~COUNT_MASK; }
private static int workerCountOf(int c) { return c & CAPACITY; } private static int workerCountOf(int c) { return c & COUNT_MASK; }
private static int ctlOf(int rs, int wc) { return rs | wc; } private static int ctlOf(int rs, int wc) { return rs | wc; }
/* /*
@ -434,7 +434,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* decrements are performed within getTask. * decrements are performed within getTask.
*/ */
private void decrementWorkerCount() { private void decrementWorkerCount() {
do {} while (! compareAndDecrementWorkerCount(ctl.get())); ctl.addAndGet(-1);
} }
/** /**
@ -538,12 +538,17 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* Core pool size is the minimum number of workers to keep alive * Core pool size is the minimum number of workers to keep alive
* (and not allow to time out etc) unless allowCoreThreadTimeOut * (and not allow to time out etc) unless allowCoreThreadTimeOut
* is set, in which case the minimum is zero. * is set, in which case the minimum is zero.
*
* Since the worker count is actually stored in COUNT_BITS bits,
* the effective limit is {@code corePoolSize & COUNT_MASK}.
*/ */
private volatile int corePoolSize; private volatile int corePoolSize;
/** /**
* Maximum pool size. Note that the actual maximum is internally * Maximum pool size.
* bounded by CAPACITY. *
* Since the worker count is actually stored in COUNT_BITS bits,
* the effective limit is {@code maximumPoolSize & COUNT_MASK}.
*/ */
private volatile int maximumPoolSize; private volatile int maximumPoolSize;
@ -705,7 +710,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
int c = ctl.get(); int c = ctl.get();
if (isRunning(c) || if (isRunning(c) ||
runStateAtLeast(c, TIDYING) || runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) (runStateLessThan(c, STOP) && ! workQueue.isEmpty()))
return; return;
if (workerCountOf(c) != 0) { // Eligible to terminate if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE); interruptIdleWorkers(ONLY_ONE);
@ -744,17 +749,12 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* specially. * specially.
*/ */
private void checkShutdownAccess() { private void checkShutdownAccess() {
// assert mainLock.isHeldByCurrentThread();
SecurityManager security = System.getSecurityManager(); SecurityManager security = System.getSecurityManager();
if (security != null) { if (security != null) {
security.checkPermission(shutdownPerm); security.checkPermission(shutdownPerm);
final ReentrantLock mainLock = this.mainLock; for (Worker w : workers)
mainLock.lock(); security.checkAccess(w.thread);
try {
for (Worker w : workers)
security.checkAccess(w.thread);
} finally {
mainLock.unlock();
}
} }
} }
@ -763,14 +763,9 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* (in which case some threads may remain uninterrupted). * (in which case some threads may remain uninterrupted).
*/ */
private void interruptWorkers() { private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock; // assert mainLock.isHeldByCurrentThread();
mainLock.lock(); for (Worker w : workers)
try { w.interruptIfStarted();
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
} }
/** /**
@ -896,26 +891,22 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
*/ */
private boolean addWorker(Runnable firstTask, boolean core) { private boolean addWorker(Runnable firstTask, boolean core) {
retry: retry:
for (;;) { for (int c = ctl.get();;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary. // Check if queue empty only if necessary.
if (rs >= SHUTDOWN && if (runStateAtLeast(c, SHUTDOWN)
! (rs == SHUTDOWN && && (runStateAtLeast(c, STOP)
firstTask == null && || firstTask != null
! workQueue.isEmpty())) || workQueue.isEmpty()))
return false; return false;
for (;;) { for (;;) {
int wc = workerCountOf(c); if (workerCountOf(c)
if (wc >= CAPACITY || >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
wc >= (core ? corePoolSize : maximumPoolSize))
return false; return false;
if (compareAndIncrementWorkerCount(c)) if (compareAndIncrementWorkerCount(c))
break retry; break retry;
c = ctl.get(); // Re-read ctl c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs) if (runStateAtLeast(c, SHUTDOWN))
continue retry; continue retry;
// else CAS failed due to workerCount change; retry inner loop // else CAS failed due to workerCount change; retry inner loop
} }
@ -934,10 +925,10 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
// Recheck while holding lock. // Recheck while holding lock.
// Back out on ThreadFactory failure or if // Back out on ThreadFactory failure or if
// shut down before lock acquired. // shut down before lock acquired.
int rs = runStateOf(ctl.get()); int c = ctl.get();
if (rs < SHUTDOWN || if (isRunning(c) ||
(rs == SHUTDOWN && firstTask == null)) { (runStateLessThan(c, STOP) && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException(); throw new IllegalThreadStateException();
workers.add(w); workers.add(w);
@ -1044,10 +1035,10 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
for (;;) { for (;;) {
int c = ctl.get(); int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary. // Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP) || workQueue.isEmpty())) {
decrementWorkerCount(); decrementWorkerCount();
return null; return null;
} }
@ -1140,17 +1131,12 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
wt.interrupt(); wt.interrupt();
try { try {
beforeExecute(wt, task); beforeExecute(wt, task);
Throwable thrown = null;
try { try {
task.run(); task.run();
} catch (RuntimeException x) { afterExecute(task, null);
thrown = x; throw x; } catch (Throwable ex) {
} catch (Error x) { afterExecute(task, ex);
thrown = x; throw x; throw ex;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
} }
} finally { } finally {
task = null; task = null;
@ -1331,7 +1317,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* *
* If the task cannot be submitted for execution, either because this * If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached, * executor has been shutdown or because its capacity has been reached,
* the task is handled by the current {@code RejectedExecutionHandler}. * the task is handled by the current {@link RejectedExecutionHandler}.
* *
* @param command the task to execute * @param command the task to execute
* @throws RejectedExecutionException at discretion of * @throws RejectedExecutionException at discretion of
@ -1438,7 +1424,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
} }
public boolean isShutdown() { public boolean isShutdown() {
return ! isRunning(ctl.get()); return runStateAtLeast(ctl.get(), SHUTDOWN);
} }
/** Used by ScheduledThreadPoolExecutor. */ /** Used by ScheduledThreadPoolExecutor. */
@ -1459,7 +1445,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
*/ */
public boolean isTerminating() { public boolean isTerminating() {
int c = ctl.get(); int c = ctl.get();
return ! isRunning(c) && runStateLessThan(c, TERMINATED); return runStateAtLeast(c, SHUTDOWN) && runStateLessThan(c, TERMINATED);
} }
public boolean isTerminated() { public boolean isTerminated() {
@ -1472,7 +1458,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
final ReentrantLock mainLock = this.mainLock; final ReentrantLock mainLock = this.mainLock;
mainLock.lock(); mainLock.lock();
try { try {
while (!runStateAtLeast(ctl.get(), TERMINATED)) { while (runStateLessThan(ctl.get(), TERMINATED)) {
if (nanos <= 0L) if (nanos <= 0L)
return false; return false;
nanos = termination.awaitNanos(nanos); nanos = termination.awaitNanos(nanos);
@ -1951,7 +1937,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
} }
int c = ctl.get(); int c = ctl.get();
String runState = String runState =
runStateLessThan(c, SHUTDOWN) ? "Running" : isRunning(c) ? "Running" :
runStateAtLeast(c, TERMINATED) ? "Terminated" : runStateAtLeast(c, TERMINATED) ? "Terminated" :
"Shutting down"; "Shutting down";
return super.toString() + return super.toString() +

View file

@ -342,11 +342,13 @@ public enum TimeUnit {
* using: * using:
* *
* <pre> {@code * <pre> {@code
* public synchronized Object poll(long timeout, TimeUnit unit) * public E poll(long timeout, TimeUnit unit)
* throws InterruptedException { * throws InterruptedException {
* while (empty) { * synchronized (lock) {
* unit.timedWait(this, timeout); * while (isEmpty()) {
* ... * unit.timedWait(lock, timeout);
* ...
* }
* } * }
* }}</pre> * }}</pre>
* *

View file

@ -67,11 +67,11 @@ public abstract class AbstractQueuedLongSynchronizer
private static final long serialVersionUID = 7373984972572414692L; private static final long serialVersionUID = 7373984972572414692L;
/* /*
To keep sources in sync, the remainder of this source file is * To keep sources in sync, the remainder of this source file is
exactly cloned from AbstractQueuedSynchronizer, replacing class * exactly cloned from AbstractQueuedSynchronizer, replacing class
name and changing ints related with sync state to longs. Please * name and changing ints related with sync state to longs. Please
keep it that way. * keep it that way.
*/ */
/** /**
* Creates a new {@code AbstractQueuedLongSynchronizer} instance * Creates a new {@code AbstractQueuedLongSynchronizer} instance
@ -725,8 +725,7 @@ public abstract class AbstractQueuedLongSynchronizer
/** /**
* Returns {@code true} if synchronization is held exclusively with * Returns {@code true} if synchronization is held exclusively with
* respect to the current (calling) thread. This method is invoked * respect to the current (calling) thread. This method is invoked
* upon each call to a non-waiting {@link ConditionObject} method. * upon each call to a {@link ConditionObject} method.
* (Waiting methods instead invoke {@link #release}.)
* *
* <p>The default implementation throws {@link * <p>The default implementation throws {@link
* UnsupportedOperationException}. This method is invoked * UnsupportedOperationException}. This method is invoked
@ -1366,9 +1365,8 @@ public abstract class AbstractQueuedLongSynchronizer
} }
/** /**
* Condition implementation for a {@link * Condition implementation for a {@link AbstractQueuedLongSynchronizer}
* AbstractQueuedLongSynchronizer} serving as the basis of a {@link * serving as the basis of a {@link Lock} implementation.
* Lock} implementation.
* *
* <p>Method documentation for this class describes mechanics, * <p>Method documentation for this class describes mechanics,
* not behavioral specifications from the point of view of Lock * not behavioral specifications from the point of view of Lock
@ -1401,6 +1399,8 @@ public abstract class AbstractQueuedLongSynchronizer
* @return its new wait node * @return its new wait node
*/ */
private Node addConditionWaiter() { private Node addConditionWaiter() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node t = lastWaiter; Node t = lastWaiter;
// If lastWaiter is cancelled, clean out. // If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) { if (t != null && t.waitStatus != Node.CONDITION) {

View file

@ -194,19 +194,13 @@ import java.util.concurrent.TimeUnit;
* represent the locked state. While a non-reentrant lock * represent the locked state. While a non-reentrant lock
* does not strictly require recording of the current owner * does not strictly require recording of the current owner
* thread, this class does so anyway to make usage easier to monitor. * thread, this class does so anyway to make usage easier to monitor.
* It also supports conditions and exposes * It also supports conditions and exposes some instrumentation methods:
* one of the instrumentation methods:
* *
* <pre> {@code * <pre> {@code
* class Mutex implements Lock, java.io.Serializable { * class Mutex implements Lock, java.io.Serializable {
* *
* // Our internal helper class * // Our internal helper class
* private static class Sync extends AbstractQueuedSynchronizer { * private static class Sync extends AbstractQueuedSynchronizer {
* // Reports whether in locked state
* protected boolean isHeldExclusively() {
* return getState() == 1;
* }
*
* // Acquires the lock if state is zero * // Acquires the lock if state is zero
* public boolean tryAcquire(int acquires) { * public boolean tryAcquire(int acquires) {
* assert acquires == 1; // Otherwise unused * assert acquires == 1; // Otherwise unused
@ -220,14 +214,27 @@ import java.util.concurrent.TimeUnit;
* // Releases the lock by setting state to zero * // Releases the lock by setting state to zero
* protected boolean tryRelease(int releases) { * protected boolean tryRelease(int releases) {
* assert releases == 1; // Otherwise unused * assert releases == 1; // Otherwise unused
* if (getState() == 0) throw new IllegalMonitorStateException(); * if (!isHeldExclusively())
* throw new IllegalMonitorStateException();
* setExclusiveOwnerThread(null); * setExclusiveOwnerThread(null);
* setState(0); * setState(0);
* return true; * return true;
* } * }
* *
* // Reports whether in locked state
* public boolean isLocked() {
* return getState() != 0;
* }
*
* public boolean isHeldExclusively() {
* // a data race, but safe due to out-of-thin-air guarantees
* return getExclusiveOwnerThread() == Thread.currentThread();
* }
*
* // Provides a Condition * // Provides a Condition
* Condition newCondition() { return new ConditionObject(); } * public Condition newCondition() {
* return new ConditionObject();
* }
* *
* // Deserializes properly * // Deserializes properly
* private void readObject(ObjectInputStream s) * private void readObject(ObjectInputStream s)
@ -240,12 +247,17 @@ import java.util.concurrent.TimeUnit;
* // The sync object does all the hard work. We just forward to it. * // The sync object does all the hard work. We just forward to it.
* private final Sync sync = new Sync(); * private final Sync sync = new Sync();
* *
* public void lock() { sync.acquire(1); } * public void lock() { sync.acquire(1); }
* public boolean tryLock() { return sync.tryAcquire(1); } * public boolean tryLock() { return sync.tryAcquire(1); }
* public void unlock() { sync.release(1); } * public void unlock() { sync.release(1); }
* public Condition newCondition() { return sync.newCondition(); } * public Condition newCondition() { return sync.newCondition(); }
* public boolean isLocked() { return sync.isHeldExclusively(); } * public boolean isLocked() { return sync.isLocked(); }
* public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } * public boolean isHeldByCurrentThread() {
* return sync.isHeldExclusively();
* }
* public boolean hasQueuedThreads() {
* return sync.hasQueuedThreads();
* }
* public void lockInterruptibly() throws InterruptedException { * public void lockInterruptibly() throws InterruptedException {
* sync.acquireInterruptibly(1); * sync.acquireInterruptibly(1);
* } * }
@ -1193,8 +1205,7 @@ public abstract class AbstractQueuedSynchronizer
/** /**
* Returns {@code true} if synchronization is held exclusively with * Returns {@code true} if synchronization is held exclusively with
* respect to the current (calling) thread. This method is invoked * respect to the current (calling) thread. This method is invoked
* upon each call to a non-waiting {@link ConditionObject} method. * upon each call to a {@link ConditionObject} method.
* (Waiting methods instead invoke {@link #release}.)
* *
* <p>The default implementation throws {@link * <p>The default implementation throws {@link
* UnsupportedOperationException}. This method is invoked * UnsupportedOperationException}. This method is invoked
@ -1834,9 +1845,8 @@ public abstract class AbstractQueuedSynchronizer
} }
/** /**
* Condition implementation for a {@link * Condition implementation for a {@link AbstractQueuedSynchronizer}
* AbstractQueuedSynchronizer} serving as the basis of a {@link * serving as the basis of a {@link Lock} implementation.
* Lock} implementation.
* *
* <p>Method documentation for this class describes mechanics, * <p>Method documentation for this class describes mechanics,
* not behavioral specifications from the point of view of Lock * not behavioral specifications from the point of view of Lock
@ -1867,6 +1877,8 @@ public abstract class AbstractQueuedSynchronizer
* @return its new wait node * @return its new wait node
*/ */
private Node addConditionWaiter() { private Node addConditionWaiter() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node t = lastWaiter; Node t = lastWaiter;
// If lastWaiter is cancelled, clean out. // If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) { if (t != null && t.waitStatus != Node.CONDITION) {

View file

@ -73,7 +73,7 @@ import java.util.concurrent.TimeUnit;
* available in the buffer. This can be achieved using two * available in the buffer. This can be achieved using two
* {@link Condition} instances. * {@link Condition} instances.
* <pre> * <pre>
* class BoundedBuffer { * class BoundedBuffer&lt;E&gt; {
* <b>final Lock lock = new ReentrantLock();</b> * <b>final Lock lock = new ReentrantLock();</b>
* final Condition notFull = <b>lock.newCondition(); </b> * final Condition notFull = <b>lock.newCondition(); </b>
* final Condition notEmpty = <b>lock.newCondition(); </b> * final Condition notEmpty = <b>lock.newCondition(); </b>
@ -81,7 +81,7 @@ import java.util.concurrent.TimeUnit;
* final Object[] items = new Object[100]; * final Object[] items = new Object[100];
* int putptr, takeptr, count; * int putptr, takeptr, count;
* *
* public void put(Object x) throws InterruptedException { * public void put(E x) throws InterruptedException {
* <b>lock.lock(); * <b>lock.lock();
* try {</b> * try {</b>
* while (count == items.length) * while (count == items.length)
@ -95,12 +95,12 @@ import java.util.concurrent.TimeUnit;
* }</b> * }</b>
* } * }
* *
* public Object take() throws InterruptedException { * public E take() throws InterruptedException {
* <b>lock.lock(); * <b>lock.lock();
* try {</b> * try {</b>
* while (count == 0) * while (count == 0)
* <b>notEmpty.await();</b> * <b>notEmpty.await();</b>
* Object x = items[takeptr]; * E x = (E) items[takeptr];
* if (++takeptr == items.length) takeptr = 0; * if (++takeptr == items.length) takeptr = 0;
* --count; * --count;
* <b>notFull.signal();</b> * <b>notFull.signal();</b>
@ -310,7 +310,8 @@ public interface Condition {
* the following form: * the following form:
* *
* <pre> {@code * <pre> {@code
* boolean aMethod(long timeout, TimeUnit unit) { * boolean aMethod(long timeout, TimeUnit unit)
* throws InterruptedException {
* long nanos = unit.toNanos(timeout); * long nanos = unit.toNanos(timeout);
* lock.lock(); * lock.lock();
* try { * try {
@ -320,6 +321,7 @@ public interface Condition {
* nanos = theCondition.awaitNanos(nanos); * nanos = theCondition.awaitNanos(nanos);
* } * }
* // ... * // ...
* return true;
* } finally { * } finally {
* lock.unlock(); * lock.unlock();
* } * }
@ -410,7 +412,8 @@ public interface Condition {
* <p>The return value indicates whether the deadline has elapsed, * <p>The return value indicates whether the deadline has elapsed,
* which can be used as follows: * which can be used as follows:
* <pre> {@code * <pre> {@code
* boolean aMethod(Date deadline) { * boolean aMethod(Date deadline)
* throws InterruptedException {
* boolean stillWaiting = true; * boolean stillWaiting = true;
* lock.lock(); * lock.lock();
* try { * try {
@ -420,6 +423,7 @@ public interface Condition {
* stillWaiting = theCondition.awaitUntil(deadline); * stillWaiting = theCondition.awaitUntil(deadline);
* } * }
* // ... * // ...
* return true;
* } finally { * } finally {
* lock.unlock(); * lock.unlock();
* } * }

View file

@ -151,18 +151,20 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
* } * }
* *
* double distanceFromOrigin() { // A read-only method * double distanceFromOrigin() { // A read-only method
* double currentX, currentY;
* long stamp = sl.tryOptimisticRead(); * long stamp = sl.tryOptimisticRead();
* double currentX = x, currentY = y; * do {
* if (!sl.validate(stamp)) { * if (stamp == 0L)
* stamp = sl.readLock(); * stamp = sl.readLock();
* try { * try {
* // possibly racy reads
* currentX = x; * currentX = x;
* currentY = y; * currentY = y;
* } finally { * } finally {
* sl.unlockRead(stamp); * stamp = sl.tryConvertToOptimisticRead(stamp);
* } * }
* } * } while (stamp == 0);
* return Math.sqrt(currentX * currentX + currentY * currentY); * return Math.hypot(currentX, currentY);
* } * }
* *
* void moveIfAtOrigin(double newX, double newY) { // upgrade * void moveIfAtOrigin(double newX, double newY) { // upgrade

View file

@ -39,6 +39,18 @@ public interface JavaLangInvokeAccess {
*/ */
String getName(Object mname); String getName(Object mname);
/**
* Returns the {@code MethodType} for the given MemberName.
* Used by {@see StackFrameInfo}.
*/
MethodType getMethodType(Object mname);
/**
* Returns the descriptor for the given MemberName.
* Used by {@see StackFrameInfo}.
*/
String getMethodDescriptor(Object mname);
/** /**
* Returns {@code true} if the given MemberName is a native method. Used by * Returns {@code true} if the given MemberName is a native method. Used by
* {@see StackFrameInfo}. * {@see StackFrameInfo}.

View file

@ -1802,7 +1802,12 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl {
try { try {
readRecord(true); readRecord(true);
} catch (SocketTimeoutException e) { } catch (SocketTimeoutException e) {
// if time out, ignore the exception and continue if ((debug != null) && Debug.isOn("ssl")) {
System.out.println(
Thread.currentThread().getName() +
", received Exception: " + e);
}
fatal((byte)(-1), "Did not receive close_notify from peer", e);
} }
} }
} catch (IOException e) { } catch (IOException e) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@ package sun.security.util;
import java.security.*; import java.security.*;
import java.util.HashMap; import java.util.HashMap;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import static java.nio.charset.StandardCharsets.UTF_8;
/** /**
* This class is used to compute digests on sections of the Manifest. * This class is used to compute digests on sections of the Manifest.
@ -112,8 +113,6 @@ public class ManifestDigester {
rawBytes = bytes; rawBytes = bytes;
entries = new HashMap<>(); entries = new HashMap<>();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Position pos = new Position(); Position pos = new Position();
if (!findSection(0, pos)) if (!findSection(0, pos))
@ -131,50 +130,41 @@ public class ManifestDigester {
if (len > 6) { if (len > 6) {
if (isNameAttr(bytes, start)) { if (isNameAttr(bytes, start)) {
StringBuilder nameBuf = new StringBuilder(sectionLen); ByteArrayOutputStream nameBuf = new ByteArrayOutputStream();
nameBuf.write(bytes, start+6, len-6);
try { int i = start + len;
nameBuf.append( if ((i-start) < sectionLen) {
new String(bytes, start+6, len-6, "UTF8")); if (bytes[i] == '\r') {
i += 2;
int i = start + len; } else {
if ((i-start) < sectionLen) { i += 1;
if (bytes[i] == '\r') {
i += 2;
} else {
i += 1;
}
} }
while ((i-start) < sectionLen) {
if (bytes[i++] == ' ') {
// name is wrapped
int wrapStart = i;
while (((i-start) < sectionLen)
&& (bytes[i++] != '\n'));
if (bytes[i-1] != '\n')
return; // XXX: exception?
int wrapLen;
if (bytes[i-2] == '\r')
wrapLen = i-wrapStart-2;
else
wrapLen = i-wrapStart-1;
nameBuf.append(new String(bytes, wrapStart,
wrapLen, "UTF8"));
} else {
break;
}
}
entries.put(nameBuf.toString(),
new Entry(start, sectionLen, sectionLenWithBlank,
rawBytes));
} catch (java.io.UnsupportedEncodingException uee) {
throw new IllegalStateException(
"UTF8 not available on platform");
} }
while ((i-start) < sectionLen) {
if (bytes[i++] == ' ') {
// name is wrapped
int wrapStart = i;
while (((i-start) < sectionLen)
&& (bytes[i++] != '\n'));
if (bytes[i-1] != '\n')
return; // XXX: exception?
int wrapLen;
if (bytes[i-2] == '\r')
wrapLen = i-wrapStart-2;
else
wrapLen = i-wrapStart-1;
nameBuf.write(bytes, wrapStart, wrapLen);
} else {
break;
}
}
entries.put(new String(nameBuf.toByteArray(), UTF_8),
new Entry(start, sectionLen, sectionLenWithBlank,
rawBytes));
} }
} }
start = pos.startOfNext; start = pos.startOfNext;

View file

@ -142,6 +142,10 @@ grant codeBase "jrt:/jdk.dynalink" {
permission java.security.AllPermission; permission java.security.AllPermission;
}; };
grant codeBase "jrt:/jdk.httpserver" {
permission java.security.AllPermission;
};
grant codeBase "jrt:/jdk.internal.le" { grant codeBase "jrt:/jdk.internal.le" {
permission java.security.AllPermission; permission java.security.AllPermission;
}; };

View file

@ -679,14 +679,16 @@ Java_java_net_PlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
} }
/* ECONNABORTED or EWOULDBLOCK error so adjust timeout if there is one. */ /* ECONNABORTED or EWOULDBLOCK error so adjust timeout if there is one. */
currNanoTime = JVM_NanoTime(env, 0); if (nanoTimeout >= NET_NSEC_PER_MSEC) {
nanoTimeout -= (currNanoTime - prevNanoTime); currNanoTime = JVM_NanoTime(env, 0);
if (nanoTimeout < NET_NSEC_PER_MSEC) { nanoTimeout -= (currNanoTime - prevNanoTime);
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", if (nanoTimeout < NET_NSEC_PER_MSEC) {
"Accept timed out"); JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
return; "Accept timed out");
return;
}
prevNanoTime = currNanoTime;
} }
prevNanoTime = currNanoTime;
} }
if (newfd < 0) { if (newfd < 0) {

View file

@ -550,10 +550,10 @@ void
fileDescriptorClose(JNIEnv *env, jobject this) fileDescriptorClose(JNIEnv *env, jobject this)
{ {
FD fd = (*env)->GetLongField(env, this, IO_handle_fdID); FD fd = (*env)->GetLongField(env, this, IO_handle_fdID);
HANDLE h = (HANDLE)fd;
if ((*env)->ExceptionOccurred(env)) { if ((*env)->ExceptionOccurred(env)) {
return; return;
} }
HANDLE h = (HANDLE)fd;
if (h == INVALID_HANDLE_VALUE) { if (h == INVALID_HANDLE_VALUE) {
return; return;

View file

@ -216,8 +216,9 @@ public enum SourceVersion {
* Character#isJavaIdentifierStart(int)} returns {@code true}, * Character#isJavaIdentifierStart(int)} returns {@code true},
* followed only by characters for which {@link * followed only by characters for which {@link
* Character#isJavaIdentifierPart(int)} returns {@code true}. * Character#isJavaIdentifierPart(int)} returns {@code true}.
* This pattern matches regular identifiers, keywords, and the * This pattern matches regular identifiers, keywords, restricted
* literals {@code "true"}, {@code "false"}, and {@code "null"}. * keywords, and the literals {@code "true"}, {@code "false"}, and
* {@code "null"}.
* The method returns {@code false} for all other strings. * The method returns {@code false} for all other strings.
* *
* @param name the string to check * @param name the string to check
@ -251,10 +252,13 @@ public enum SourceVersion {
* qualified name in the latest source version. Unlike {@link * qualified name in the latest source version. Unlike {@link
* #isIdentifier isIdentifier}, this method returns {@code false} * #isIdentifier isIdentifier}, this method returns {@code false}
* for keywords, boolean literals, and the null literal. * for keywords, boolean literals, and the null literal.
* This method returns {@code true} for <i>restricted
* keywords</i>.
* *
* @param name the string to check * @param name the string to check
* @return {@code true} if this string is a * @return {@code true} if this string is a
* syntactically valid name, {@code false} otherwise. * syntactically valid name, {@code false} otherwise.
* @jls 3.9 Keywords
* @jls 6.2 Names and Identifiers * @jls 6.2 Names and Identifiers
*/ */
public static boolean isName(CharSequence name) { public static boolean isName(CharSequence name) {
@ -266,11 +270,14 @@ public enum SourceVersion {
* qualified name in the given source version. Unlike {@link * qualified name in the given source version. Unlike {@link
* #isIdentifier isIdentifier}, this method returns {@code false} * #isIdentifier isIdentifier}, this method returns {@code false}
* for keywords, boolean literals, and the null literal. * for keywords, boolean literals, and the null literal.
* This method returns {@code true} for <i>restricted
* keywords</i>.
* *
* @param name the string to check * @param name the string to check
* @param version the version to use * @param version the version to use
* @return {@code true} if this string is a * @return {@code true} if this string is a
* syntactically valid name, {@code false} otherwise. * syntactically valid name, {@code false} otherwise.
* @jls 3.9 Keywords
* @jls 6.2 Names and Identifiers * @jls 6.2 Names and Identifiers
* @since 9 * @since 9
*/ */
@ -287,6 +294,8 @@ public enum SourceVersion {
/** /**
* Returns whether or not {@code s} is a keyword, boolean literal, * Returns whether or not {@code s} is a keyword, boolean literal,
* or null literal in the latest source version. * or null literal in the latest source version.
* This method returns {@code false} for <i>restricted
* keywords</i>.
* *
* @param s the string to check * @param s the string to check
* @return {@code true} if {@code s} is a keyword, or boolean * @return {@code true} if {@code s} is a keyword, or boolean
@ -302,6 +311,8 @@ public enum SourceVersion {
/** /**
* Returns whether or not {@code s} is a keyword, boolean literal, * Returns whether or not {@code s} is a keyword, boolean literal,
* or null literal in the given source version. * or null literal in the given source version.
* This method returns {@code false} for <i>restricted
* keywords</i>.
* *
* @param s the string to check * @param s the string to check
* @param version the version to use * @param version the version to use

View file

@ -87,7 +87,7 @@ public interface ModuleElement extends Element, QualifiedNameable {
* *
* @return {@code true} if this is an open module and {@code * @return {@code true} if this is an open module and {@code
* false} otherwise * false} otherwise
*/ // TODO: add @jls to unnamed module section */
boolean isOpen(); boolean isOpen();
/** /**
@ -96,7 +96,9 @@ public interface ModuleElement extends Element, QualifiedNameable {
* *
* @return {@code true} if this is an unnamed module and {@code * @return {@code true} if this is an unnamed module and {@code
* false} otherwise * false} otherwise
*/ // TODO: add @jls to unnamed module section *
* @jls 7.7.5 Unnamed Modules
*/
boolean isUnnamed(); boolean isUnnamed();
/** /**

View file

@ -71,6 +71,7 @@ public class Kinds {
HIDDEN(Category.RESOLUTION_TARGET), // not overloaded non-target HIDDEN(Category.RESOLUTION_TARGET), // not overloaded non-target
STATICERR(Category.RESOLUTION_TARGET), // overloaded? target STATICERR(Category.RESOLUTION_TARGET), // overloaded? target
MISSING_ENCL(Category.RESOLUTION), // not overloaded non-target MISSING_ENCL(Category.RESOLUTION), // not overloaded non-target
BAD_VAR(Category.RESOLUTION), // not overloaded non-target
ABSENT_VAR(Category.RESOLUTION_TARGET, KindName.VAR), // not overloaded non-target ABSENT_VAR(Category.RESOLUTION_TARGET, KindName.VAR), // not overloaded non-target
WRONG_MTHS(Category.RESOLUTION_TARGET, KindName.METHOD), // overloaded target WRONG_MTHS(Category.RESOLUTION_TARGET, KindName.METHOD), // overloaded target
WRONG_MTH(Category.RESOLUTION_TARGET, KindName.METHOD), // not overloaded target WRONG_MTH(Category.RESOLUTION_TARGET, KindName.METHOD), // not overloaded target

View file

@ -227,6 +227,7 @@ public enum Source {
return compareTo(JDK1_8) <= 0; return compareTo(JDK1_8) <= 0;
} }
public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; } public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; }
public boolean allowLocalVariableTypeInference() { return compareTo(JDK1_10) >= 0; }
public static SourceVersion toSourceVersion(Source source) { public static SourceVersion toSourceVersion(Source source) {
switch(source) { switch(source) {
case JDK1_2: case JDK1_2:

View file

@ -1616,6 +1616,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
public TypeVar(Name name, Symbol owner, Type lower) { public TypeVar(Name name, Symbol owner, Type lower) {
super(null, TypeMetadata.EMPTY); super(null, TypeMetadata.EMPTY);
Assert.checkNonNull(lower);
tsym = new TypeVariableSymbol(0, name, this, owner); tsym = new TypeVariableSymbol(0, name, this, owner);
this.bound = null; this.bound = null;
this.lower = lower; this.lower = lower;
@ -1628,6 +1629,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
public TypeVar(TypeSymbol tsym, Type bound, Type lower, public TypeVar(TypeSymbol tsym, Type bound, Type lower,
TypeMetadata metadata) { TypeMetadata metadata) {
super(tsym, metadata); super(tsym, metadata);
Assert.checkNonNull(lower);
this.bound = bound; this.bound = bound;
this.lower = lower; this.lower = lower;
} }

View file

@ -1247,7 +1247,9 @@ public class TypeAnnotations {
final TypeAnnotationPosition pos = final TypeAnnotationPosition pos =
TypeAnnotationPosition.localVariable(currentLambda, TypeAnnotationPosition.localVariable(currentLambda,
tree.pos); tree.pos);
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); if (!tree.isImplicitlyTyped()) {
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
}
} else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { } else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
final TypeAnnotationPosition pos = final TypeAnnotationPosition pos =
TypeAnnotationPosition.exceptionParameter(currentLambda, TypeAnnotationPosition.exceptionParameter(currentLambda,

View file

@ -190,6 +190,245 @@ public class Types {
} }
// </editor-fold> // </editor-fold>
// <editor-fold defaultstate="collapsed" desc="projections">
/**
* A projection kind. See {@link TypeProjection}
*/
enum ProjectionKind {
UPWARDS() {
@Override
ProjectionKind complement() {
return DOWNWARDS;
}
},
DOWNWARDS() {
@Override
ProjectionKind complement() {
return UPWARDS;
}
};
abstract ProjectionKind complement();
}
/**
* This visitor performs upwards and downwards projections on types.
*
* A projection is defined as a function that takes a type T, a set of type variables V and that
* produces another type S.
*
* An upwards projection maps a type T into a type S such that (i) T has no variables in V,
* and (ii) S is an upper bound of T.
*
* A downwards projection maps a type T into a type S such that (i) T has no variables in V,
* and (ii) S is a lower bound of T.
*
* Note that projections are only allowed to touch variables in V. Theferore it is possible for
* a projection to leave its input type unchanged if it does not contain any variables in V.
*
* Moreover, note that while an upwards projection is always defined (every type as an upper bound),
* a downwards projection is not always defined.
*
* Examples:
*
* {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
* {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
* {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
* {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
*/
class TypeProjection extends StructuralTypeMapping<ProjectionKind> {
List<Type> vars;
Set<Type> seen = new HashSet<>();
public TypeProjection(List<Type> vars) {
this.vars = vars;
}
@Override
public Type visitClassType(ClassType t, ProjectionKind pkind) {
if (t.isCompound()) {
List<Type> components = directSupertypes(t);
List<Type> components1 = components.map(c -> c.map(this, pkind));
if (components == components1) return t;
else return makeIntersectionType(components1);
} else {
Type outer = t.getEnclosingType();
Type outer1 = visit(outer, pkind);
List<Type> typarams = t.getTypeArguments();
List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, pkind));
if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
//not defined
return syms.botType;
}
if (outer1 == outer && typarams1 == typarams) return t;
else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
@Override
protected boolean needsStripping() {
return true;
}
};
}
}
protected Type makeWildcard(Type upper, Type lower) {
BoundKind bk;
Type bound;
if (upper.hasTag(BOT)) {
upper = syms.objectType;
}
boolean isUpperObject = isSameType(upper, syms.objectType);
if (!lower.hasTag(BOT) && isUpperObject) {
bound = lower;
bk = SUPER;
} else {
bound = upper;
bk = isUpperObject ? UNBOUND : EXTENDS;
}
return new WildcardType(bound, bk, syms.boundClass);
}
@Override
public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
if (vars.contains(t)) {
try {
if (seen.add(t)) {
final Type bound;
switch (pkind) {
case UPWARDS:
bound = t.getUpperBound();
break;
case DOWNWARDS:
bound = (t.getLowerBound() == null) ?
syms.botType :
t.getLowerBound();
break;
default:
Assert.error();
return null;
}
return bound.map(this, pkind);
} else {
//cycle
return syms.objectType;
}
} finally {
seen.remove(t);
}
} else {
return t;
}
}
@Override
public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
switch (pkind) {
case UPWARDS:
return wt.isExtendsBound() ?
wt.type.map(this, pkind) :
syms.objectType;
case DOWNWARDS:
return wt.isSuperBound() ?
wt.type.map(this, pkind) :
syms.botType;
default:
Assert.error();
return null;
}
}
private Type mapTypeArgument(Type t, ProjectionKind pkind) {
if (!t.containsAny(vars)) {
return t;
} else if (!t.hasTag(WILDCARD) && pkind == ProjectionKind.DOWNWARDS) {
//not defined
return syms.botType;
} else {
Type upper = t.map(this, pkind);
Type lower = t.map(this, pkind.complement());
return makeWildcard(upper, lower);
}
}
}
/**
* Computes an upward projection of given type, and vars. See {@link TypeProjection}.
*
* @param t the type to be projected
* @param vars the set of type variables to be mapped
* @return the type obtained as result of the projection
*/
public Type upward(Type t, List<Type> vars) {
return t.map(new TypeProjection(vars), ProjectionKind.UPWARDS);
}
/**
* Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
* This routine is typically used to computed the input set of variables to be used during
* an upwards projection (see {@link Types#upward(Type, List)}).
*
* @param t the type where occurrences of captured variables have to be found
* @return the set of captured variables found in t
*/
public List<Type> captures(Type t) {
CaptureScanner cs = new CaptureScanner();
Set<Type> captures = new HashSet<>();
cs.visit(t, captures);
return List.from(captures);
}
/**
* This visitor scans a type recursively looking for occurrences of captured type variables.
*/
class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
@Override
public Void visitType(Type t, Set<Type> types) {
return null;
}
@Override
public Void visitClassType(ClassType t, Set<Type> seen) {
if (t.isCompound()) {
directSupertypes(t).forEach(s -> visit(s, seen));
} else {
t.allparams().forEach(ta -> visit(ta, seen));
}
return null;
}
@Override
public Void visitArrayType(ArrayType t, Set<Type> seen) {
return visit(t.elemtype, seen);
}
@Override
public Void visitWildcardType(WildcardType t, Set<Type> seen) {
visit(t.type, seen);
return null;
}
@Override
public Void visitTypeVar(TypeVar t, Set<Type> seen) {
if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
visit(t.getUpperBound(), seen);
}
return null;
}
@Override
public Void visitCapturedType(CapturedType t, Set<Type> seen) {
if (seen.add(t)) {
visit(t.getUpperBound(), seen);
visit(t.getLowerBound(), seen);
}
return null;
}
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="isUnbounded"> // <editor-fold defaultstate="collapsed" desc="isUnbounded">
/** /**
* Checks that all the arguments to a class are unbounded * Checks that all the arguments to a class are unbounded

View file

@ -83,6 +83,7 @@ import com.sun.tools.javac.util.DiagnosticSource;
import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR; import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
import static com.sun.tools.javac.code.TypeTag.CLASS; import static com.sun.tools.javac.code.TypeTag.CLASS;
import static com.sun.tools.javac.tree.JCTree.Tag.APPLY; import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
import static com.sun.tools.javac.tree.JCTree.Tag.FOREACHLOOP;
import static com.sun.tools.javac.tree.JCTree.Tag.LABELLED; import static com.sun.tools.javac.tree.JCTree.Tag.LABELLED;
import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF; import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS; import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
@ -139,7 +140,8 @@ public class Analyzer {
enum AnalyzerMode { enum AnalyzerMode {
DIAMOND("diamond", Source::allowDiamond), DIAMOND("diamond", Source::allowDiamond),
LAMBDA("lambda", Source::allowLambda), LAMBDA("lambda", Source::allowLambda),
METHOD("method", Source::allowGraphInference); METHOD("method", Source::allowGraphInference),
LOCAL("local", Source::allowLocalVariableTypeInference);
final String opt; final String opt;
final Predicate<Source> sourceFilter; final Predicate<Source> sourceFilter;
@ -341,11 +343,91 @@ public class Analyzer {
} }
} }
/**
* Base class for local variable inference analyzers.
*/
abstract class RedundantLocalVarTypeAnalyzerBase<X extends JCStatement> extends StatementAnalyzer<X, X> {
RedundantLocalVarTypeAnalyzerBase(JCTree.Tag tag) {
super(AnalyzerMode.LOCAL, tag);
}
/**
* Map a variable tree into a new declaration using implicit type.
*/
JCVariableDecl mapVar(JCVariableDecl oldTree, JCVariableDecl newTree){
newTree.vartype = null;
return newTree;
}
/**
* Analyze results of local variable inference.
*/
void processVar(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
if (!hasErrors) {
if (types.isSameType(oldTree.type, newTree.type)) {
log.warning(oldTree, Warnings.LocalRedundantType);
}
}
}
}
/**
* This analyzer checks if a local variable declaration has redundant type.
*/
class RedundantLocalVarTypeAnalyzer extends RedundantLocalVarTypeAnalyzerBase<JCVariableDecl> {
RedundantLocalVarTypeAnalyzer() {
super(VARDEF);
}
boolean match(JCVariableDecl tree){
return tree.sym.owner.kind == Kind.MTH &&
tree.init != null && !tree.isImplicitlyTyped() &&
attr.canInferLocalVarType(tree) == null;
}
@Override
JCVariableDecl map(JCVariableDecl oldTree, JCVariableDecl newTree){
return mapVar(oldTree, newTree);
}
@Override
void process(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
processVar(oldTree, newTree, hasErrors);
}
}
/**
* This analyzer checks if a for each variable declaration has redundant type.
*/
class RedundantLocalVarTypeAnalyzerForEach extends RedundantLocalVarTypeAnalyzerBase<JCEnhancedForLoop> {
RedundantLocalVarTypeAnalyzerForEach() {
super(FOREACHLOOP);
}
@Override
boolean match(JCEnhancedForLoop tree){
return !tree.var.isImplicitlyTyped();
}
@Override
JCEnhancedForLoop map(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree){
newTree.var = mapVar(oldTree.var, newTree.var);
newTree.body = make.Block(0, List.nil()); //ignore body for analysis purpose
return newTree;
}
@Override
void process(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree, boolean hasErrors){
processVar(oldTree.var, newTree.var, hasErrors);
}
}
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] { StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
new DiamondInitializer(), new DiamondInitializer(),
new LambdaAnalyzer(), new LambdaAnalyzer(),
new RedundantTypeArgAnalyzer() new RedundantTypeArgAnalyzer(),
new RedundantLocalVarTypeAnalyzer(),
new RedundantLocalVarTypeAnalyzerForEach()
}; };
/** /**

View file

@ -28,9 +28,11 @@ package com.sun.tools.javac.comp;
import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Attribute.Compound; import com.sun.tools.javac.code.Attribute.Compound;
import com.sun.tools.javac.code.Attribute.TypeCompound; import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.Kinds.KindSelector;
import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.TypeMetadata.Entry.Kind; import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.resources.CompilerProperties.Errors; import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.tree.JCTree.*;
@ -602,7 +604,7 @@ public class Annotate {
} }
private Attribute getAnnotationEnumValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) { private Attribute getAnnotationEnumValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
Type result = attr.attribExpr(tree, env, expectedElementType); Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
Symbol sym = TreeInfo.symbol(tree); Symbol sym = TreeInfo.symbol(tree);
if (sym == null || if (sym == null ||
TreeInfo.nonstaticSelect(tree) || TreeInfo.nonstaticSelect(tree) ||
@ -616,7 +618,7 @@ public class Annotate {
} }
private Attribute getAnnotationClassValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) { private Attribute getAnnotationClassValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
Type result = attr.attribExpr(tree, env, expectedElementType); Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
if (result.isErroneous()) { if (result.isErroneous()) {
// Does it look like an unresolved class literal? // Does it look like an unresolved class literal?
if (TreeInfo.name(tree) == names._class && if (TreeInfo.name(tree) == names._class &&
@ -642,7 +644,7 @@ public class Annotate {
} }
private Attribute getAnnotationPrimitiveValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) { private Attribute getAnnotationPrimitiveValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
Type result = attr.attribExpr(tree, env, expectedElementType); Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
if (result.isErroneous()) if (result.isErroneous())
return new Attribute.Error(result.getOriginalType()); return new Attribute.Error(result.getOriginalType());
if (result.constValue() == null) { if (result.constValue() == null) {
@ -653,6 +655,22 @@ public class Annotate {
return new Attribute.Constant(expectedElementType, result.constValue()); return new Attribute.Constant(expectedElementType, result.constValue());
} }
private Attr.ResultInfo annotationValueInfo(Type pt) {
return attr.unknownExprInfo.dup(pt, new AnnotationValueContext(attr.unknownExprInfo.checkContext));
}
class AnnotationValueContext extends Check.NestedCheckContext {
AnnotationValueContext(CheckContext enclosingContext) {
super(enclosingContext);
}
@Override
public boolean compatible(Type found, Type req, Warner warn) {
//handle non-final implicitly-typed vars (will be rejected later on)
return found.hasTag(TypeTag.NONE) || super.compatible(found, req, warn);
}
}
private Attribute getAnnotationArrayValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) { private Attribute getAnnotationArrayValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
// Special case, implicit array // Special case, implicit array
if (!tree.hasTag(NEWARRAY)) { if (!tree.hasTag(NEWARRAY)) {

View file

@ -36,7 +36,6 @@ import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.TreeVisitor; import com.sun.source.tree.TreeVisitor;
import com.sun.source.util.SimpleTreeVisitor; import com.sun.source.util.SimpleTreeVisitor;
import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Directive.RequiresFlag;
import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
@ -46,7 +45,6 @@ import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext; import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
import com.sun.tools.javac.comp.Check.CheckContext; import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.comp.DeferredAttr.AttrMode; import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
import com.sun.tools.javac.comp.Infer.FreeTypeListener;
import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.jvm.*;
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond; import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg; import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
@ -830,6 +828,10 @@ public class Attr extends JCTree.Visitor {
final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile); final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
try { try {
Type itype = attribExpr(variable.init, env, type); Type itype = attribExpr(variable.init, env, type);
if (variable.isImplicitlyTyped()) {
//fixup local variable type
type = variable.type = variable.sym.type = chk.checkLocalVarType(variable, itype.baseType(), variable.name);
}
if (itype.constValue() != null) { if (itype.constValue() != null) {
return coerce(itype, type).constValue(); return coerce(itype, type).constValue();
} else { } else {
@ -1108,6 +1110,21 @@ public class Attr extends JCTree.Visitor {
// parameters have already been entered // parameters have already been entered
env.info.scope.enter(tree.sym); env.info.scope.enter(tree.sym);
} else { } else {
if (tree.isImplicitlyTyped() && (tree.getModifiers().flags & PARAMETER) == 0) {
if (tree.init == null) {
//cannot use 'var' without initializer
log.error(tree, Errors.CantInferLocalVarType(tree.name, Fragments.LocalMissingInit));
tree.vartype = make.Erroneous();
} else {
Fragment msg = canInferLocalVarType(tree);
if (msg != null) {
//cannot use 'var' with initializer which require an explicit target
//(e.g. lambda, method reference, array initializer).
log.error(tree, Errors.CantInferLocalVarType(tree.name, msg));
tree.vartype = make.Erroneous();
}
}
}
try { try {
annotate.blockAnnotations(); annotate.blockAnnotations();
memberEnter.memberEnter(tree, env); memberEnter.memberEnter(tree, env);
@ -1131,7 +1148,7 @@ public class Attr extends JCTree.Visitor {
boolean isImplicitLambdaParameter = env.tree.hasTag(LAMBDA) && boolean isImplicitLambdaParameter = env.tree.hasTag(LAMBDA) &&
((JCLambda)env.tree).paramKind == JCLambda.ParameterKind.IMPLICIT && ((JCLambda)env.tree).paramKind == JCLambda.ParameterKind.IMPLICIT &&
(tree.sym.flags() & PARAMETER) != 0; (tree.sym.flags() & PARAMETER) != 0;
chk.validate(tree.vartype, env, !isImplicitLambdaParameter); chk.validate(tree.vartype, env, !isImplicitLambdaParameter && !tree.isImplicitlyTyped());
try { try {
v.getConstValue(); // ensure compile-time constant initializer is evaluated v.getConstValue(); // ensure compile-time constant initializer is evaluated
@ -1152,6 +1169,10 @@ public class Attr extends JCTree.Visitor {
// marking the variable as undefined. // marking the variable as undefined.
initEnv.info.enclVar = v; initEnv.info.enclVar = v;
attribExpr(tree.init, initEnv, v.type); attribExpr(tree.init, initEnv, v.type);
if (tree.isImplicitlyTyped()) {
//fixup local variable type
v.type = chk.checkLocalVarType(tree, tree.init.type.baseType(), tree.name);
}
} }
} }
result = tree.type = v.type; result = tree.type = v.type;
@ -1161,6 +1182,71 @@ public class Attr extends JCTree.Visitor {
} }
} }
Fragment canInferLocalVarType(JCVariableDecl tree) {
LocalInitScanner lis = new LocalInitScanner();
lis.scan(tree.init);
return lis.badInferenceMsg;
}
static class LocalInitScanner extends TreeScanner {
Fragment badInferenceMsg = null;
boolean needsTarget = true;
@Override
public void visitNewArray(JCNewArray tree) {
if (tree.elemtype == null && needsTarget) {
badInferenceMsg = Fragments.LocalArrayMissingTarget;
}
}
@Override
public void visitLambda(JCLambda tree) {
if (needsTarget) {
badInferenceMsg = Fragments.LocalLambdaMissingTarget;
}
}
@Override
public void visitTypeCast(JCTypeCast tree) {
boolean prevNeedsTarget = needsTarget;
try {
needsTarget = false;
super.visitTypeCast(tree);
} finally {
needsTarget = prevNeedsTarget;
}
}
@Override
public void visitReference(JCMemberReference tree) {
if (needsTarget) {
badInferenceMsg = Fragments.LocalMrefMissingTarget;
}
}
@Override
public void visitNewClass(JCNewClass tree) {
boolean prevNeedsTarget = needsTarget;
try {
needsTarget = false;
super.visitNewClass(tree);
} finally {
needsTarget = prevNeedsTarget;
}
}
@Override
public void visitApply(JCMethodInvocation tree) {
boolean prevNeedsTarget = needsTarget;
try {
needsTarget = false;
super.visitApply(tree);
} finally {
needsTarget = prevNeedsTarget;
}
}
}
public void visitSkip(JCSkip tree) { public void visitSkip(JCSkip tree) {
result = null; result = null;
} }
@ -1243,7 +1329,6 @@ public class Attr extends JCTree.Visitor {
//attributing the for-each expression; we mimick this by attributing //attributing the for-each expression; we mimick this by attributing
//the for-each expression first (against original scope). //the for-each expression first (against original scope).
Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv)); Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
attribStat(tree.var, loopEnv);
chk.checkNonVoid(tree.pos(), exprType); chk.checkNonVoid(tree.pos(), exprType);
Type elemtype = types.elemtype(exprType); // perhaps expr is an array? Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
if (elemtype == null) { if (elemtype == null) {
@ -1261,6 +1346,15 @@ public class Attr extends JCTree.Visitor {
: types.wildUpperBound(iterableParams.head); : types.wildUpperBound(iterableParams.head);
} }
} }
if (tree.var.isImplicitlyTyped()) {
Type inferredType = chk.checkLocalVarType(tree.var, elemtype, tree.var.name);
if (inferredType.isErroneous()) {
tree.var.vartype = make.at(tree.var.vartype).Erroneous();
} else {
tree.var.vartype = make.at(tree.var.vartype).Type(inferredType);
}
}
attribStat(tree.var, loopEnv);
chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type); chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
loopEnv.tree = tree; // before, we were not in loop! loopEnv.tree = tree; // before, we were not in loop!
attribStat(tree.body, loopEnv); attribStat(tree.body, loopEnv);
@ -2379,7 +2473,8 @@ public class Attr extends JCTree.Visitor {
if (pt().hasTag(ARRAY)) { if (pt().hasTag(ARRAY)) {
elemtype = types.elemtype(pt()); elemtype = types.elemtype(pt());
} else { } else {
if (!pt().hasTag(ERROR)) { if (!pt().hasTag(ERROR) &&
(env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
log.error(tree.pos(), log.error(tree.pos(),
Errors.IllegalInitializerForType(pt())); Errors.IllegalInitializerForType(pt()));
} }
@ -2404,7 +2499,7 @@ public class Attr extends JCTree.Visitor {
@Override @Override
public void visitLambda(final JCLambda that) { public void visitLambda(final JCLambda that) {
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) { if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
if (pt().hasTag(NONE)) { if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
//lambda only allowed in assignment or method invocation/cast context //lambda only allowed in assignment or method invocation/cast context
log.error(that.pos(), Errors.UnexpectedLambda); log.error(that.pos(), Errors.UnexpectedLambda);
} }
@ -2837,7 +2932,7 @@ public class Attr extends JCTree.Visitor {
@Override @Override
public void visitReference(final JCMemberReference that) { public void visitReference(final JCMemberReference that) {
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) { if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
if (pt().hasTag(NONE)) { if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
//method reference only allowed in assignment or method invocation/cast context //method reference only allowed in assignment or method invocation/cast context
log.error(that.pos(), Errors.UnexpectedMref); log.error(that.pos(), Errors.UnexpectedMref);
} }
@ -3811,6 +3906,14 @@ public class Attr extends JCTree.Visitor {
break; break;
case VAR: case VAR:
VarSymbol v = (VarSymbol)sym; VarSymbol v = (VarSymbol)sym;
if (env.info.enclVar != null
&& v.type.hasTag(NONE)) {
//self reference to implicitly typed variable declaration
log.error(TreeInfo.positionFor(v, env.enclClass), Errors.CantInferLocalVarType(v.name, Fragments.LocalSelfRef));
return v.type = types.createErrorType(v.type);
}
// Test (4): if symbol is an instance field of a raw type, // Test (4): if symbol is an instance field of a raw type,
// which is being assigned to, issue an unchecked warning if // which is being assigned to, issue an unchecked warning if
// its type changes under erasure. // its type changes under erasure.
@ -4135,6 +4238,9 @@ public class Attr extends JCTree.Visitor {
public void visitTypeArray(JCArrayTypeTree tree) { public void visitTypeArray(JCArrayTypeTree tree) {
Type etype = attribType(tree.elemtype, env); Type etype = attribType(tree.elemtype, env);
Type type = new ArrayType(etype, syms.arrayClass); Type type = new ArrayType(etype, syms.arrayClass);
if (etype.isErroneous()) {
type = types.createErrorType(type);
}
result = check(tree, type, KindSelector.TYP, resultInfo); result = check(tree, type, KindSelector.TYP, resultInfo);
} }
@ -4776,7 +4882,7 @@ public class Attr extends JCTree.Visitor {
} }
public void visitVarDef(final JCVariableDecl tree) { public void visitVarDef(final JCVariableDecl tree) {
//System.err.println("validateTypeAnnotations.visitVarDef " + tree); //System.err.println("validateTypeAnnotations.visitVarDef " + tree);
if (tree.sym != null && tree.sym.type != null) if (tree.sym != null && tree.sym.type != null && !tree.isImplicitlyTyped())
validateAnnotatedType(tree.vartype, tree.sym.type); validateAnnotatedType(tree.vartype, tree.sym.type);
scan(tree.mods); scan(tree.mods);
scan(tree.vartype); scan(tree.vartype);
@ -4904,17 +5010,16 @@ public class Attr extends JCTree.Visitor {
repeat = false; repeat = false;
} else if (enclTr.hasTag(JCTree.Tag.WILDCARD)) { } else if (enclTr.hasTag(JCTree.Tag.WILDCARD)) {
JCWildcard wc = (JCWildcard) enclTr; JCWildcard wc = (JCWildcard) enclTr;
if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD) { if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD ||
validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getExtendsBound()); wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
} else if (wc.getKind() == JCTree.Kind.SUPER_WILDCARD) { validateAnnotatedType(wc.getBound(), wc.getBound().type);
validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getSuperBound());
} else { } else {
// Nothing to do for UNBOUND // Nothing to do for UNBOUND
} }
repeat = false; repeat = false;
} else if (enclTr.hasTag(TYPEARRAY)) { } else if (enclTr.hasTag(TYPEARRAY)) {
JCArrayTypeTree art = (JCArrayTypeTree) enclTr; JCArrayTypeTree art = (JCArrayTypeTree) enclTr;
validateAnnotatedType(art.getType(), ((ArrayType)enclTy).getComponentType()); validateAnnotatedType(art.getType(), art.elemtype.type);
repeat = false; repeat = false;
} else if (enclTr.hasTag(TYPEUNION)) { } else if (enclTr.hasTag(TYPEUNION)) {
JCTypeUnion ut = (JCTypeUnion) enclTr; JCTypeUnion ut = (JCTypeUnion) enclTr;

View file

@ -843,26 +843,30 @@ public class Check {
List<Type> checkDiamondDenotable(ClassType t) { List<Type> checkDiamondDenotable(ClassType t) {
ListBuffer<Type> buf = new ListBuffer<>(); ListBuffer<Type> buf = new ListBuffer<>();
for (Type arg : t.allparams()) { for (Type arg : t.allparams()) {
if (!diamondTypeChecker.visit(arg, null)) { if (!checkDenotable(arg)) {
buf.append(arg); buf.append(arg);
} }
} }
return buf.toList(); return buf.toList();
} }
boolean checkDenotable(Type t) {
return denotableChecker.visit(t, null);
}
// where // where
/** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable /** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable
* types. The visit methods return false as soon as a non-denotable type is encountered and true * types. The visit methods return false as soon as a non-denotable type is encountered and true
* otherwise. * otherwise.
*/ */
private static final Types.SimpleVisitor<Boolean, Void> diamondTypeChecker = new Types.SimpleVisitor<Boolean, Void>() { private static final Types.SimpleVisitor<Boolean, Void> denotableChecker = new Types.SimpleVisitor<Boolean, Void>() {
@Override @Override
public Boolean visitType(Type t, Void s) { public Boolean visitType(Type t, Void s) {
return true; return true;
} }
@Override @Override
public Boolean visitClassType(ClassType t, Void s) { public Boolean visitClassType(ClassType t, Void s) {
if (t.isCompound()) { if (t.isUnion() || t.isIntersection()) {
return false; return false;
} }
for (Type targ : t.allparams()) { for (Type targ : t.allparams()) {
@ -878,7 +882,7 @@ public class Check {
/* Any type variable mentioned in the inferred type must have been declared as a type parameter /* Any type variable mentioned in the inferred type must have been declared as a type parameter
(i.e cannot have been produced by inference (18.4)) (i.e cannot have been produced by inference (18.4))
*/ */
return t.tsym.owner.type.getTypeArguments().contains(t); return (t.tsym.flags() & SYNTHETIC) == 0;
} }
@Override @Override
@ -941,6 +945,17 @@ public class Check {
(allowPrivateSafeVarargs ? PRIVATE : 0) )) != 0); (allowPrivateSafeVarargs ? PRIVATE : 0) )) != 0);
} }
Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
//upward project the initializer type
t = types.upward(t, types.captures(t));
//check that resulting type is not the null type
if (t.hasTag(BOT)) {
log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferNull));
return types.createErrorType(t);
}
return t;
}
Type checkMethod(final Type mtype, Type checkMethod(final Type mtype,
final Symbol sym, final Symbol sym,
final Env<AttrContext> env, final Env<AttrContext> env,
@ -3159,7 +3174,10 @@ public class Check {
if (s.kind == PCK) if (s.kind == PCK)
return true; return true;
} else if (target == names.TYPE_USE) { } else if (target == names.TYPE_USE) {
if (s.kind == TYP || s.kind == VAR || if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) {
//cannot type annotate implictly typed locals
return false;
} else if (s.kind == TYP || s.kind == VAR ||
(s.kind == MTH && !s.isConstructor() && (s.kind == MTH && !s.isConstructor() &&
!s.type.getReturnType().hasTag(VOID)) || !s.type.getReturnType().hasTag(VOID)) ||
(s.kind == MTH && s.isConstructor())) { (s.kind == MTH && s.isConstructor())) {

View file

@ -529,7 +529,7 @@ public class Infer {
List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER); List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
if (Type.containsAny(upperBounds, vars)) { if (Type.containsAny(upperBounds, vars)) {
TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner); TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), null); fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), syms.botType);
todo.append(uv); todo.append(uv);
uv.setInst(fresh_tvar.type); uv.setInst(fresh_tvar.type);
} else if (upperBounds.nonEmpty()) { } else if (upperBounds.nonEmpty()) {

View file

@ -259,7 +259,7 @@ public class MemberEnter extends JCTree.Visitor {
try { try {
if (TreeInfo.isEnumInit(tree)) { if (TreeInfo.isEnumInit(tree)) {
attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype); attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
} else { } else if (!tree.isImplicitlyTyped()) {
attr.attribType(tree.vartype, localEnv); attr.attribType(tree.vartype, localEnv);
if (TreeInfo.isReceiverParam(tree)) if (TreeInfo.isReceiverParam(tree))
checkReceiver(tree, localEnv); checkReceiver(tree, localEnv);
@ -279,8 +279,8 @@ public class MemberEnter extends JCTree.Visitor {
tree.vartype.type = atype.makeVarargs(); tree.vartype.type = atype.makeVarargs();
} }
WriteableScope enclScope = enter.enterScope(env); WriteableScope enclScope = enter.enterScope(env);
VarSymbol v = Type vartype = tree.isImplicitlyTyped() ? Type.noType : tree.vartype.type;
new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner); VarSymbol v = new VarSymbol(0, tree.name, vartype, enclScope.owner);
v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree); v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
tree.sym = v; tree.sym = v;
if (tree.init != null) { if (tree.init != null) {
@ -298,7 +298,9 @@ public class MemberEnter extends JCTree.Visitor {
} }
annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos()); annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos()); if (!tree.isImplicitlyTyped()) {
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
}
v.pos = tree.pos; v.pos = tree.pos;
} }

View file

@ -59,6 +59,7 @@ import java.util.EnumSet;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.BiFunction; import java.util.function.BiFunction;
@ -105,6 +106,7 @@ public class Resolve {
public final boolean allowModules; public final boolean allowModules;
public final boolean checkVarargsAccessAfterResolution; public final boolean checkVarargsAccessAfterResolution;
private final boolean compactMethodDiags; private final boolean compactMethodDiags;
private final boolean allowLocalVariableTypeInference;
final EnumSet<VerboseResolutionMode> verboseResolutionMode; final EnumSet<VerboseResolutionMode> verboseResolutionMode;
WriteableScope polymorphicSignatureScope; WriteableScope polymorphicSignatureScope;
@ -116,7 +118,7 @@ public class Resolve {
varNotFound = new SymbolNotFoundError(ABSENT_VAR); varNotFound = new SymbolNotFoundError(ABSENT_VAR);
methodNotFound = new SymbolNotFoundError(ABSENT_MTH); methodNotFound = new SymbolNotFoundError(ABSENT_MTH);
typeNotFound = new SymbolNotFoundError(ABSENT_TYP); typeNotFound = new SymbolNotFoundError(ABSENT_TYP);
referenceNotFound = new ReferenceLookupResult(methodNotFound, null); referenceNotFound = ReferenceLookupResult.error(methodNotFound);
names = Names.instance(context); names = Names.instance(context);
log = Log.instance(context); log = Log.instance(context);
@ -136,6 +138,7 @@ public class Resolve {
Target target = Target.instance(context); Target target = Target.instance(context);
allowMethodHandles = target.hasMethodHandles(); allowMethodHandles = target.hasMethodHandles();
allowFunctionalInterfaceMostSpecific = source.allowFunctionalInterfaceMostSpecific(); allowFunctionalInterfaceMostSpecific = source.allowFunctionalInterfaceMostSpecific();
allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
checkVarargsAccessAfterResolution = checkVarargsAccessAfterResolution =
source.allowPostApplicabilityVarargsAccessCheck(); source.allowPostApplicabilityVarargsAccessCheck();
polymorphicSignatureScope = WriteableScope.create(syms.noSymbol); polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
@ -2325,6 +2328,10 @@ public class Resolve {
* (a subset of VAL, TYP, PCK). * (a subset of VAL, TYP, PCK).
*/ */
Symbol findIdent(Env<AttrContext> env, Name name, KindSelector kind) { Symbol findIdent(Env<AttrContext> env, Name name, KindSelector kind) {
return checkVarType(findIdentInternal(env, name, kind), name);
}
Symbol findIdentInternal(Env<AttrContext> env, Name name, KindSelector kind) {
Symbol bestSoFar = typeNotFound; Symbol bestSoFar = typeNotFound;
Symbol sym; Symbol sym;
@ -2354,6 +2361,11 @@ public class Resolve {
*/ */
Symbol findIdentInPackage(Env<AttrContext> env, TypeSymbol pck, Symbol findIdentInPackage(Env<AttrContext> env, TypeSymbol pck,
Name name, KindSelector kind) { Name name, KindSelector kind) {
return checkVarType(findIdentInPackageInternal(env, pck, name, kind), name);
}
Symbol findIdentInPackageInternal(Env<AttrContext> env, TypeSymbol pck,
Name name, KindSelector kind) {
Name fullname = TypeSymbol.formFullName(name, pck); Name fullname = TypeSymbol.formFullName(name, pck);
Symbol bestSoFar = typeNotFound; Symbol bestSoFar = typeNotFound;
if (kind.contains(KindSelector.TYP)) { if (kind.contains(KindSelector.TYP)) {
@ -2383,6 +2395,11 @@ public class Resolve {
*/ */
Symbol findIdentInType(Env<AttrContext> env, Type site, Symbol findIdentInType(Env<AttrContext> env, Type site,
Name name, KindSelector kind) { Name name, KindSelector kind) {
return checkVarType(findIdentInTypeInternal(env, site, name, kind), name);
}
Symbol findIdentInTypeInternal(Env<AttrContext> env, Type site,
Name name, KindSelector kind) {
Symbol bestSoFar = typeNotFound; Symbol bestSoFar = typeNotFound;
Symbol sym; Symbol sym;
if (kind.contains(KindSelector.VAL)) { if (kind.contains(KindSelector.VAL)) {
@ -2399,6 +2416,14 @@ public class Resolve {
return bestSoFar; return bestSoFar;
} }
private Symbol checkVarType(Symbol bestSoFar, Name name) {
if (allowLocalVariableTypeInference && name.equals(names.var) &&
(bestSoFar.kind == TYP || bestSoFar.kind == ABSENT_TYP)) {
bestSoFar = new BadVarTypeError();
}
return bestSoFar;
}
/* *************************************************************************** /* ***************************************************************************
* Access checking * Access checking
* The following methods convert ResolveErrors to ErrorSymbols, issuing * The following methods convert ResolveErrors to ErrorSymbols, issuing
@ -2944,10 +2969,10 @@ public class Resolve {
//merge results //merge results
Pair<Symbol, ReferenceLookupHelper> res; Pair<Symbol, ReferenceLookupHelper> res;
Symbol bestSym = referenceChooser.result(boundRes, unboundRes); ReferenceLookupResult bestRes = referenceChooser.result(boundRes, unboundRes);
res = new Pair<>(bestSym, res = new Pair<>(bestRes.sym,
bestSym == unboundSym ? unboundLookupHelper : boundLookupHelper); bestRes == unboundRes ? unboundLookupHelper : boundLookupHelper);
env.info.pendingResolutionPhase = bestSym == unboundSym ? env.info.pendingResolutionPhase = bestRes == unboundRes ?
unboundEnv.info.pendingResolutionPhase : unboundEnv.info.pendingResolutionPhase :
boundEnv.info.pendingResolutionPhase; boundEnv.info.pendingResolutionPhase;
@ -3003,11 +3028,15 @@ public class Resolve {
Symbol sym; Symbol sym;
ReferenceLookupResult(Symbol sym, MethodResolutionContext resolutionContext) { ReferenceLookupResult(Symbol sym, MethodResolutionContext resolutionContext) {
this.staticKind = staticKind(sym, resolutionContext); this(sym, staticKind(sym, resolutionContext));
}
private ReferenceLookupResult(Symbol sym, StaticKind staticKind) {
this.staticKind = staticKind;
this.sym = sym; this.sym = sym;
} }
private StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) { private static StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) {
switch (sym.kind) { switch (sym.kind) {
case MTH: case MTH:
case AMBIGUOUS: case AMBIGUOUS:
@ -3056,6 +3085,10 @@ public class Resolve {
return false; return false;
} }
} }
static ReferenceLookupResult error(Symbol sym) {
return new ReferenceLookupResult(sym, StaticKind.UNDEFINED);
}
} }
/** /**
@ -3068,7 +3101,7 @@ public class Resolve {
* Generate a result from a pair of lookup result objects. This method delegates to the * Generate a result from a pair of lookup result objects. This method delegates to the
* appropriate result generation routine. * appropriate result generation routine.
*/ */
Symbol result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) { ReferenceLookupResult result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
return unboundRes != referenceNotFound ? return unboundRes != referenceNotFound ?
unboundResult(boundRes, unboundRes) : unboundResult(boundRes, unboundRes) :
boundResult(boundRes); boundResult(boundRes);
@ -3077,12 +3110,12 @@ public class Resolve {
/** /**
* Generate a symbol from a given bound lookup result. * Generate a symbol from a given bound lookup result.
*/ */
abstract Symbol boundResult(ReferenceLookupResult boundRes); abstract ReferenceLookupResult boundResult(ReferenceLookupResult boundRes);
/** /**
* Generate a symbol from a pair of bound/unbound lookup results. * Generate a symbol from a pair of bound/unbound lookup results.
*/ */
abstract Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes); abstract ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes);
} }
/** /**
@ -3092,37 +3125,38 @@ public class Resolve {
ReferenceChooser basicReferenceChooser = new ReferenceChooser() { ReferenceChooser basicReferenceChooser = new ReferenceChooser() {
@Override @Override
Symbol boundResult(ReferenceLookupResult boundRes) { ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
return !boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC) ? return !boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC) ?
boundRes.sym : //the search produces a non-static method boundRes : //the search produces a non-static method
new BadMethodReferenceError(boundRes.sym, false); ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
} }
@Override @Override
Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) { ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
if (boundRes.hasKind(StaticKind.STATIC) && if (boundRes.hasKind(StaticKind.STATIC) &&
(!unboundRes.isSuccess() || unboundRes.hasKind(StaticKind.STATIC))) { (!unboundRes.isSuccess() || unboundRes.hasKind(StaticKind.STATIC))) {
//the first search produces a static method and no non-static method is applicable //the first search produces a static method and no non-static method is applicable
//during the second search //during the second search
return boundRes.sym; return boundRes;
} else if (unboundRes.hasKind(StaticKind.NON_STATIC) && } else if (unboundRes.hasKind(StaticKind.NON_STATIC) &&
(!boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC))) { (!boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC))) {
//the second search produces a non-static method and no static method is applicable //the second search produces a non-static method and no static method is applicable
//during the first search //during the first search
return unboundRes.sym; return unboundRes;
} else if (boundRes.isSuccess() && unboundRes.isSuccess()) { } else if (boundRes.isSuccess() && unboundRes.isSuccess()) {
//both searches produce some result; ambiguity (error recovery) //both searches produce some result; ambiguity (error recovery)
return ambiguityError(boundRes.sym, unboundRes.sym); return ReferenceLookupResult.error(ambiguityError(boundRes.sym, unboundRes.sym));
} else if (boundRes.isSuccess() || unboundRes.isSuccess()) { } else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
//Both searches failed to produce a result with correct staticness (i.e. first search //Both searches failed to produce a result with correct staticness (i.e. first search
//produces an non-static method). Alternatively, a given search produced a result //produces an non-static method). Alternatively, a given search produced a result
//with the right staticness, but the other search has applicable methods with wrong //with the right staticness, but the other search has applicable methods with wrong
//staticness (error recovery) //staticness (error recovery)
return new BadMethodReferenceError(boundRes.isSuccess() ? boundRes.sym : unboundRes.sym, true); return ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.isSuccess() ?
boundRes.sym : unboundRes.sym, true));
} else { } else {
//both searches fail to produce a result - pick 'better' error using heuristics (error recovery) //both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
return (boundRes.canIgnore() && !unboundRes.canIgnore()) ? return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
unboundRes.sym : boundRes.sym; unboundRes : boundRes;
} }
} }
}; };
@ -3134,28 +3168,29 @@ public class Resolve {
ReferenceChooser structuralReferenceChooser = new ReferenceChooser() { ReferenceChooser structuralReferenceChooser = new ReferenceChooser() {
@Override @Override
Symbol boundResult(ReferenceLookupResult boundRes) { ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
return (!boundRes.isSuccess() || !boundRes.hasKind(StaticKind.STATIC)) ? return (!boundRes.isSuccess() || !boundRes.hasKind(StaticKind.STATIC)) ?
boundRes.sym : //the search has at least one applicable non-static method boundRes : //the search has at least one applicable non-static method
new BadMethodReferenceError(boundRes.sym, false); ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
} }
@Override @Override
Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) { ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
if (boundRes.isSuccess() && !boundRes.hasKind(StaticKind.NON_STATIC)) { if (boundRes.isSuccess() && !boundRes.hasKind(StaticKind.NON_STATIC)) {
//the first serach has at least one applicable static method //the first serach has at least one applicable static method
return boundRes.sym; return boundRes;
} else if (unboundRes.isSuccess() && !unboundRes.hasKind(StaticKind.STATIC)) { } else if (unboundRes.isSuccess() && !unboundRes.hasKind(StaticKind.STATIC)) {
//the second search has at least one applicable non-static method //the second search has at least one applicable non-static method
return unboundRes.sym; return unboundRes;
} else if (boundRes.isSuccess() || unboundRes.isSuccess()) { } else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
//either the first search produces a non-static method, or second search produces //either the first search produces a non-static method, or second search produces
//a non-static method (error recovery) //a non-static method (error recovery)
return new BadMethodReferenceError(boundRes.isSuccess() ? boundRes.sym : unboundRes.sym, true); return ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.isSuccess() ?
boundRes.sym : unboundRes.sym, true));
} else { } else {
//both searches fail to produce a result - pick 'better' error using heuristics (error recovery) //both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
return (boundRes.canIgnore() && !unboundRes.canIgnore()) ? return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
unboundRes.sym : boundRes.sym; unboundRes : boundRes;
} }
} }
}; };
@ -3774,6 +3809,17 @@ public class Resolve {
} }
} }
class BadVarTypeError extends ResolveError {
BadVarTypeError() {
super(Kind.BAD_VAR, "bad var use");
}
@Override
JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos, Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
return diags.create(dkind, log.currentSource(), pos, "illegal.ref.to.var.type", name);
}
}
/** /**
* InvalidSymbolError error class indicating that a symbol matching a * InvalidSymbolError error class indicating that a symbol matching a
* given name does not exists in a given site. * given name does not exists in a given site.
@ -3995,14 +4041,35 @@ public class Resolve {
} }
//where //where
private Map<Symbol, JCDiagnostic> mapCandidates() { private Map<Symbol, JCDiagnostic> mapCandidates() {
Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<>(); MostSpecificMap candidates = new MostSpecificMap();
for (Candidate c : resolveContext.candidates) { for (Candidate c : resolveContext.candidates) {
if (c.isApplicable()) continue; if (c.isApplicable()) continue;
candidates.put(c.sym, c.details); candidates.put(c);
} }
return candidates; return candidates;
} }
@SuppressWarnings("serial")
private class MostSpecificMap extends LinkedHashMap<Symbol, JCDiagnostic> {
private void put(Candidate c) {
ListBuffer<Symbol> overridden = new ListBuffer<>();
for (Symbol s : keySet()) {
if (s == c.sym) {
continue;
}
if (c.sym.overrides(s, (TypeSymbol)s.owner, types, false)) {
overridden.add(s);
} else if (s.overrides(c.sym, (TypeSymbol)c.sym.owner, types, false)) {
return;
}
}
for (Symbol s : overridden) {
remove(s);
}
put(c.sym, c.details);
}
}
Map<Symbol, JCDiagnostic> filterCandidates(Map<Symbol, JCDiagnostic> candidatesMap) { Map<Symbol, JCDiagnostic> filterCandidates(Map<Symbol, JCDiagnostic> candidatesMap) {
Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<>(); Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<>();
for (Map.Entry<Symbol, JCDiagnostic> _entry : candidatesMap.entrySet()) { for (Map.Entry<Symbol, JCDiagnostic> _entry : candidatesMap.entrySet()) {

View file

@ -179,6 +179,7 @@ public class JavacParser implements Parser {
this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams(); this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams();
this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier(); this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier();
this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods(); this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
this.allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
this.keepDocComments = keepDocComments; this.keepDocComments = keepDocComments;
this.parseModuleInfo = parseModuleInfo; this.parseModuleInfo = parseModuleInfo;
docComments = newDocCommentTable(keepDocComments, fac); docComments = newDocCommentTable(keepDocComments, fac);
@ -270,11 +271,14 @@ public class JavacParser implements Parser {
*/ */
boolean allowThisIdent; boolean allowThisIdent;
/** Switch: is local variable inference allowed?
*/
boolean allowLocalVariableTypeInference;
/** The type of the method receiver, as specified by a first "this" parameter. /** The type of the method receiver, as specified by a first "this" parameter.
*/ */
JCVariableDecl receiverParam; JCVariableDecl receiverParam;
/** When terms are parsed, the mode determines which is expected: /** When terms are parsed, the mode determines which is expected:
* mode = EXPR : an expression * mode = EXPR : an expression
* mode = TYPE : a type * mode = TYPE : a type
@ -808,12 +812,16 @@ public class JavacParser implements Parser {
* parsing annotations. * parsing annotations.
*/ */
public JCExpression parseType() { public JCExpression parseType() {
List<JCAnnotation> annotations = typeAnnotationsOpt(); return parseType(false);
return parseType(annotations);
} }
public JCExpression parseType(List<JCAnnotation> annotations) { public JCExpression parseType(boolean allowVar) {
JCExpression result = unannotatedType(); List<JCAnnotation> annotations = typeAnnotationsOpt();
return parseType(allowVar, annotations);
}
public JCExpression parseType(boolean allowVar, List<JCAnnotation> annotations) {
JCExpression result = unannotatedType(allowVar);
if (annotations.nonEmpty()) { if (annotations.nonEmpty()) {
result = insertAnnotationsToMostInner(result, annotations, false); result = insertAnnotationsToMostInner(result, annotations, false);
@ -822,10 +830,18 @@ public class JavacParser implements Parser {
return result; return result;
} }
public JCExpression unannotatedType() { public JCExpression unannotatedType(boolean allowVar) {
return term(TYPE); JCExpression result = term(TYPE);
if (!allowVar && isRestrictedLocalVarTypeName(result)) {
syntaxError(result.pos, "var.not.allowed.here");
}
return result;
} }
protected JCExpression term(int newmode) { protected JCExpression term(int newmode) {
int prevmode = mode; int prevmode = mode;
mode = newmode; mode = newmode;
@ -1152,11 +1168,11 @@ public class JavacParser implements Parser {
accept(LPAREN); accept(LPAREN);
mode = TYPE; mode = TYPE;
int pos1 = pos; int pos1 = pos;
List<JCExpression> targets = List.of(t = term3()); List<JCExpression> targets = List.of(t = parseType());
while (token.kind == AMP) { while (token.kind == AMP) {
checkIntersectionTypesInCast(); checkIntersectionTypesInCast();
accept(AMP); accept(AMP);
targets = targets.prepend(term3()); targets = targets.prepend(parseType());
} }
if (targets.length() > 1) { if (targets.length() > 1) {
t = toP(F.at(pos1).TypeIntersection(targets.reverse())); t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
@ -1912,7 +1928,7 @@ public class JavacParser implements Parser {
*/ */
JCExpression typeArgument() { JCExpression typeArgument() {
List<JCAnnotation> annotations = typeAnnotationsOpt(); List<JCAnnotation> annotations = typeAnnotationsOpt();
if (token.kind != QUES) return parseType(annotations); if (token.kind != QUES) return parseType(false, annotations);
int pos = token.pos; int pos = token.pos;
nextToken(); nextToken();
JCExpression result; JCExpression result;
@ -2425,13 +2441,8 @@ public class JavacParser implements Parser {
token.kind == ENUM) { token.kind == ENUM) {
return List.of(classOrInterfaceOrEnumDeclaration(mods, dc)); return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
} else { } else {
JCExpression t = parseType(); JCExpression t = parseType(true);
ListBuffer<JCStatement> stats = return localVariableDeclarations(mods, t);
variableDeclarators(mods, t, new ListBuffer<JCStatement>());
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
accept(SEMI);
storeEnd(stats.last(), S.prevToken().endPos);
return stats.toList();
} }
} }
case ABSTRACT: case STRICTFP: { case ABSTRACT: case STRICTFP: {
@ -2458,12 +2469,7 @@ public class JavacParser implements Parser {
pos = token.pos; pos = token.pos;
JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
F.at(pos); F.at(pos);
ListBuffer<JCStatement> stats = return localVariableDeclarations(mods, t);
variableDeclarators(mods, t, new ListBuffer<JCStatement>());
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
accept(SEMI);
storeEnd(stats.last(), S.prevToken().endPos);
return stats.toList();
} else { } else {
// This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
t = checkExprStat(t); t = checkExprStat(t);
@ -2473,6 +2479,15 @@ public class JavacParser implements Parser {
} }
} }
} }
//where
private List<JCStatement> localVariableDeclarations(JCModifiers mods, JCExpression type) {
ListBuffer<JCStatement> stats =
variableDeclarators(mods, type, new ListBuffer<>(), true);
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
accept(SEMI);
storeEnd(stats.last(), S.prevToken().endPos);
return stats.toList();
}
/** Statement = /** Statement =
* Block * Block
@ -2766,11 +2781,11 @@ public class JavacParser implements Parser {
ListBuffer<JCStatement> stats = new ListBuffer<>(); ListBuffer<JCStatement> stats = new ListBuffer<>();
int pos = token.pos; int pos = token.pos;
if (token.kind == FINAL || token.kind == MONKEYS_AT) { if (token.kind == FINAL || token.kind == MONKEYS_AT) {
return variableDeclarators(optFinal(0), parseType(), stats).toList(); return variableDeclarators(optFinal(0), parseType(true), stats, true).toList();
} else { } else {
JCExpression t = term(EXPR | TYPE); JCExpression t = term(EXPR | TYPE);
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) { if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
return variableDeclarators(modifiersOpt(), t, stats).toList(); return variableDeclarators(modifiersOpt(), t, stats, true).toList();
} else if ((lastmode & TYPE) != 0 && token.kind == COLON) { } else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
error(pos, "bad.initializer", "for-loop"); error(pos, "bad.initializer", "for-loop");
return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null)); return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
@ -2989,9 +3004,10 @@ public class JavacParser implements Parser {
*/ */
public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods, public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
JCExpression type, JCExpression type,
T vdefs) T vdefs,
boolean localDecl)
{ {
return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs); return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs, localDecl);
} }
/** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator } /** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
@ -3006,14 +3022,20 @@ public class JavacParser implements Parser {
Name name, Name name,
boolean reqInit, boolean reqInit,
Comment dc, Comment dc,
T vdefs) T vdefs,
boolean localDecl)
{ {
vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc)); JCVariableDecl head = variableDeclaratorRest(pos, mods, type, name, reqInit, dc, localDecl);
boolean implicit = allowLocalVariableTypeInference && head.vartype == null;
vdefs.append(head);
while (token.kind == COMMA) { while (token.kind == COMMA) {
if (implicit) {
reportSyntaxError(pos, "var.not.allowed.compound");
}
// All but last of multiple declarators subsume a comma // All but last of multiple declarators subsume a comma
storeEnd((JCTree)vdefs.last(), token.endPos); storeEnd((JCTree)vdefs.last(), token.endPos);
nextToken(); nextToken();
vdefs.append(variableDeclarator(mods, type, reqInit, dc)); vdefs.append(variableDeclarator(mods, type, reqInit, dc, localDecl));
} }
return vdefs; return vdefs;
} }
@ -3021,8 +3043,8 @@ public class JavacParser implements Parser {
/** VariableDeclarator = Ident VariableDeclaratorRest /** VariableDeclarator = Ident VariableDeclaratorRest
* ConstantDeclarator = Ident ConstantDeclaratorRest * ConstantDeclarator = Ident ConstantDeclaratorRest
*/ */
JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) { JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc, boolean localDecl) {
return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc); return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc, localDecl);
} }
/** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer] /** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
@ -3032,7 +3054,7 @@ public class JavacParser implements Parser {
* @param dc The documentation comment for the variable declarations, or null. * @param dc The documentation comment for the variable declarations, or null.
*/ */
JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name, JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
boolean reqInit, Comment dc) { boolean reqInit, Comment dc, boolean localDecl) {
type = bracketsOpt(type); type = bracketsOpt(type);
JCExpression init = null; JCExpression init = null;
if (token.kind == EQ) { if (token.kind == EQ) {
@ -3040,12 +3062,40 @@ public class JavacParser implements Parser {
init = variableInitializer(); init = variableInitializer();
} }
else if (reqInit) syntaxError(token.pos, "expected", EQ); else if (reqInit) syntaxError(token.pos, "expected", EQ);
JCTree elemType = TreeInfo.innermostType(type, true);
if (allowLocalVariableTypeInference && elemType.hasTag(IDENT)) {
Name typeName = ((JCIdent)elemType).name;
if (isRestrictedLocalVarTypeName(typeName)) {
if (type.hasTag(TYPEARRAY)) {
//error - 'var' and arrays
reportSyntaxError(pos, "var.not.allowed.array");
} else {
//implicit type
type = null;
}
}
}
JCVariableDecl result = JCVariableDecl result =
toP(F.at(pos).VarDef(mods, name, type, init)); toP(F.at(pos).VarDef(mods, name, type, init));
attach(result, dc); attach(result, dc);
return result; return result;
} }
boolean isRestrictedLocalVarTypeName(JCExpression e) {
switch (e.getTag()) {
case IDENT:
return isRestrictedLocalVarTypeName(((JCIdent)e).name);
case TYPEARRAY:
return isRestrictedLocalVarTypeName(((JCArrayTypeTree)e).elemtype);
default:
return false;
}
}
boolean isRestrictedLocalVarTypeName(Name name) {
return allowLocalVariableTypeInference && name == names.var;
}
/** VariableDeclaratorId = Ident BracketsOpt /** VariableDeclaratorId = Ident BracketsOpt
*/ */
JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) { JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
@ -3111,13 +3161,13 @@ public class JavacParser implements Parser {
int startPos = token.pos; int startPos = token.pos;
if (token.kind == FINAL || token.kind == MONKEYS_AT) { if (token.kind == FINAL || token.kind == MONKEYS_AT) {
JCModifiers mods = optFinal(Flags.FINAL); JCModifiers mods = optFinal(Flags.FINAL);
JCExpression t = parseType(); JCExpression t = parseType(true);
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null); return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
} }
JCExpression t = term(EXPR | TYPE); JCExpression t = term(EXPR | TYPE);
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) { if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
JCModifiers mods = toP(F.at(startPos).Modifiers(Flags.FINAL)); JCModifiers mods = toP(F.at(startPos).Modifiers(Flags.FINAL));
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null); return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
} else { } else {
checkVariableInTryWithResources(startPos); checkVariableInTryWithResources(startPos);
if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) { if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
@ -3397,7 +3447,7 @@ public class JavacParser implements Parser {
protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) { protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
int pos = token.pos; int pos = token.pos;
accept(CLASS); accept(CLASS);
Name name = ident(); Name name = typeName();
List<JCTypeParameter> typarams = typeParametersOpt(); List<JCTypeParameter> typarams = typeParametersOpt();
@ -3418,6 +3468,15 @@ public class JavacParser implements Parser {
return result; return result;
} }
Name typeName() {
int pos = token.pos;
Name name = ident();
if (isRestrictedLocalVarTypeName(name)) {
reportSyntaxError(pos, "var.not.allowed", name);
}
return name;
}
/** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
* [EXTENDS TypeList] InterfaceBody * [EXTENDS TypeList] InterfaceBody
* @param mods The modifiers starting the interface declaration * @param mods The modifiers starting the interface declaration
@ -3426,7 +3485,8 @@ public class JavacParser implements Parser {
protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) { protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
int pos = token.pos; int pos = token.pos;
accept(INTERFACE); accept(INTERFACE);
Name name = ident();
Name name = typeName();
List<JCTypeParameter> typarams = typeParametersOpt(); List<JCTypeParameter> typarams = typeParametersOpt();
@ -3449,7 +3509,8 @@ public class JavacParser implements Parser {
protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) { protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
int pos = token.pos; int pos = token.pos;
accept(ENUM); accept(ENUM);
Name name = ident();
Name name = typeName();
List<JCExpression> implementing = List.nil(); List<JCExpression> implementing = List.nil();
if (token.kind == IMPLEMENTS) { if (token.kind == IMPLEMENTS) {
@ -3647,7 +3708,7 @@ public class JavacParser implements Parser {
nextToken(); nextToken();
} else { } else {
// method returns types are un-annotated types // method returns types are un-annotated types
type = unannotatedType(); type = unannotatedType(false);
} }
if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) { if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
if (isInterface || tk.name() != className) if (isInterface || tk.name() != className)
@ -3667,7 +3728,7 @@ public class JavacParser implements Parser {
} else if (!isVoid && typarams.isEmpty()) { } else if (!isVoid && typarams.isEmpty()) {
List<JCTree> defs = List<JCTree> defs =
variableDeclaratorsRest(pos, mods, type, name, isInterface, dc, variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
new ListBuffer<JCTree>()).toList(); new ListBuffer<JCTree>(), false).toList();
accept(SEMI); accept(SEMI);
storeEnd(defs.last(), S.prevToken().endPos); storeEnd(defs.last(), S.prevToken().endPos);
return defs; return defs;
@ -3809,7 +3870,7 @@ public class JavacParser implements Parser {
JCTypeParameter typeParameter() { JCTypeParameter typeParameter() {
int pos = token.pos; int pos = token.pos;
List<JCAnnotation> annos = typeAnnotationsOpt(); List<JCAnnotation> annos = typeAnnotationsOpt();
Name name = ident(); Name name = typeName();
ListBuffer<JCExpression> bounds = new ListBuffer<>(); ListBuffer<JCExpression> bounds = new ListBuffer<>();
if (token.kind == EXTENDS) { if (token.kind == EXTENDS) {
nextToken(); nextToken();

View file

@ -1190,6 +1190,47 @@ compiler.err.io.exception=\
compiler.err.undef.label=\ compiler.err.undef.label=\
undefined label: {0} undefined label: {0}
# 0: name (type)
compiler.err.illegal.ref.to.var.type=\
illegal reference to restricted type ''{0}''
# 0: token
compiler.err.var.not.allowed=\
''{0}'' not allowed here\n\
as of release 10, ''{0}'' is a restricted local variable type and cannot be used for type declarations
# 0: name (variable), 1: message segment
compiler.err.cant.infer.local.var.type=\
cannot infer type for local variable {0}\n\
({1})
compiler.err.var.not.allowed.here=\
''var'' is not allowed here
compiler.err.var.not.allowed.array=\
''var'' is not allowed as an element type of an array
compiler.err.var.not.allowed.compound=\
''var'' is not allowed in a compound declaration
compiler.misc.local.cant.infer.null=\
variable initializer is ''null''
compiler.misc.local.missing.init=\
cannot use ''var'' on variable without initializer
compiler.misc.local.lambda.missing.target=\
lambda expression needs an explicit target-type
compiler.misc.local.mref.missing.target=\
method reference needs an explicit target-type
compiler.misc.local.array.missing.target=\
array initializer needs an explicit target-type
compiler.misc.local.self.ref=\
cannot use ''var'' on self-referencing variable
# 0: message segment, 1: unused # 0: message segment, 1: unused
compiler.err.cant.apply.diamond=\ compiler.err.cant.apply.diamond=\
cannot infer type arguments for {0} cannot infer type arguments for {0}
@ -1873,6 +1914,9 @@ compiler.warn.raw.class.use=\
compiler.warn.diamond.redundant.args=\ compiler.warn.diamond.redundant.args=\
Redundant type arguments in new expression (use diamond operator instead). Redundant type arguments in new expression (use diamond operator instead).
compiler.warn.local.redundant.type=\
Redundant type for local variable (replace explicit type with ''var'').
compiler.warn.potential.lambda.found=\ compiler.warn.potential.lambda.found=\
This anonymous inner class creation can be turned into a lambda expression. This anonymous inner class creation can be turned into a lambda expression.

View file

@ -946,6 +946,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
} }
} }
public boolean isImplicitlyTyped() {
return vartype == null;
}
@Override @Override
public void accept(Visitor v) { v.visitVarDef(this); } public void accept(Visitor v) { v.visitVarDef(this); }

View file

@ -1359,7 +1359,7 @@ public class Pretty extends JCTree.Visitor {
// Prints the inner element type of a nested array // Prints the inner element type of a nested array
private void printBaseElementType(JCTree tree) throws IOException { private void printBaseElementType(JCTree tree) throws IOException {
printExpr(TreeInfo.innermostType(tree)); printExpr(TreeInfo.innermostType(tree, false));
} }
// prints the brackets of a nested array in reverse order // prints the brackets of a nested array in reverse order

View file

@ -1136,7 +1136,7 @@ public class TreeInfo {
* For an array that contains an annotated type, return that annotated type. * For an array that contains an annotated type, return that annotated type.
* TODO: currently only used by Pretty. Describe behavior better. * TODO: currently only used by Pretty. Describe behavior better.
*/ */
public static JCTree innermostType(JCTree type) { public static JCTree innermostType(JCTree type, boolean skipAnnos) {
JCTree lastAnnotatedType = null; JCTree lastAnnotatedType = null;
JCTree cur = type; JCTree cur = type;
loop: while (true) { loop: while (true) {
@ -1157,7 +1157,7 @@ public class TreeInfo {
break loop; break loop;
} }
} }
if (lastAnnotatedType!=null) { if (!skipAnnos && lastAnnotatedType!=null) {
return lastAnnotatedType; return lastAnnotatedType;
} else { } else {
return cur; return cur;

View file

@ -63,6 +63,7 @@ public class Names {
public final Name _default; public final Name _default;
public final Name _super; public final Name _super;
public final Name _this; public final Name _this;
public final Name var;
public final Name exports; public final Name exports;
public final Name opens; public final Name opens;
public final Name module; public final Name module;
@ -224,6 +225,7 @@ public class Names {
_default = fromString("default"); _default = fromString("default");
_super = fromString("super"); _super = fromString("super");
_this = fromString("this"); _this = fromString("this");
var = fromString("var");
exports = fromString("exports"); exports = fromString("exports");
opens = fromString("opens"); opens = fromString("opens");
module = fromString("module"); module = fromString("module");

View file

@ -106,7 +106,8 @@ module jdk.compiler {
exports com.sun.tools.javac.jvm to exports com.sun.tools.javac.jvm to
jdk.javadoc; jdk.javadoc;
exports com.sun.tools.javac.main to exports com.sun.tools.javac.main to
jdk.javadoc; jdk.javadoc,
jdk.jshell;
exports com.sun.tools.javac.model to exports com.sun.tools.javac.model to
jdk.javadoc; jdk.javadoc;
exports com.sun.tools.javac.parser to exports com.sun.tools.javac.parser to

View file

@ -39,6 +39,7 @@ import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable; import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.SimpleTypeVisitor9; import javax.lang.model.util.SimpleTypeVisitor9;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.Content;
@ -98,15 +99,19 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite
*/ */
@Override @Override
protected Content getDeprecatedLink(Element member) { protected Content getDeprecatedLink(Element member) {
StringBuilder sb = new StringBuilder(); Content deprecatedLinkContent = new ContentBuilder();
sb.append(utils.getFullyQualifiedName(member)); deprecatedLinkContent.addContent(utils.getFullyQualifiedName(member));
if (!utils.isConstructor(member)) { if (!utils.isConstructor(member)) {
sb.append("."); deprecatedLinkContent.addContent(".");
sb.append(member.getSimpleName()); deprecatedLinkContent.addContent(member.getSimpleName());
} }
sb.append(utils.flatSignature((ExecutableElement) member)); String signature = utils.flatSignature((ExecutableElement) member);
if (signature.length() > 2) {
deprecatedLinkContent.addContent(Contents.ZERO_WIDTH_SPACE);
}
deprecatedLinkContent.addContent(signature);
return writer.getDocLink(MEMBER, member, sb); return writer.getDocLink(MEMBER, utils.getEnclosingTypeElement(member), member, deprecatedLinkContent);
} }
/** /**
@ -199,55 +204,61 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite
*/ */
protected void addParameters(ExecutableElement member, protected void addParameters(ExecutableElement member,
boolean includeAnnotations, Content htmltree, int indentSize) { boolean includeAnnotations, Content htmltree, int indentSize) {
htmltree.addContent(Contents.ZERO_WIDTH_SPACE); Content paramTree = new ContentBuilder();
htmltree.addContent("(");
String sep = ""; String sep = "";
List<? extends VariableElement> parameters = member.getParameters(); List<? extends VariableElement> parameters = member.getParameters();
CharSequence indent = makeSpace(indentSize + 1); CharSequence indent = makeSpace(indentSize + 1);
TypeMirror rcvrType = member.getReceiverType(); TypeMirror rcvrType = member.getReceiverType();
if (includeAnnotations && rcvrType != null && utils.isAnnotated(rcvrType)) { if (includeAnnotations && rcvrType != null && utils.isAnnotated(rcvrType)) {
List<? extends AnnotationMirror> annotationMirrors = rcvrType.getAnnotationMirrors(); List<? extends AnnotationMirror> annotationMirrors = rcvrType.getAnnotationMirrors();
addReceiverAnnotations(member, rcvrType, annotationMirrors, htmltree); addReceiverAnnotations(member, rcvrType, annotationMirrors, paramTree);
sep = "," + DocletConstants.NL + indent; sep = "," + DocletConstants.NL + indent;
} }
int paramstart; int paramstart;
for (paramstart = 0; paramstart < parameters.size(); paramstart++) { for (paramstart = 0; paramstart < parameters.size(); paramstart++) {
htmltree.addContent(sep); paramTree.addContent(sep);
VariableElement param = parameters.get(paramstart); VariableElement param = parameters.get(paramstart);
if (param.getKind() != ElementKind.INSTANCE_INIT) { if (param.getKind() != ElementKind.INSTANCE_INIT) {
if (includeAnnotations) { if (includeAnnotations) {
boolean foundAnnotations = boolean foundAnnotations =
writer.addAnnotationInfo(indent.length(), writer.addAnnotationInfo(indent.length(),
member, param, htmltree); member, param, paramTree);
if (foundAnnotations) { if (foundAnnotations) {
htmltree.addContent(DocletConstants.NL); paramTree.addContent(DocletConstants.NL);
htmltree.addContent(indent); paramTree.addContent(indent);
} }
} }
addParam(member, param, addParam(member, param,
(paramstart == parameters.size() - 1) && member.isVarArgs(), htmltree); (paramstart == parameters.size() - 1) && member.isVarArgs(), paramTree);
break; break;
} }
} }
for (int i = paramstart + 1; i < parameters.size(); i++) { for (int i = paramstart + 1; i < parameters.size(); i++) {
htmltree.addContent(","); paramTree.addContent(",");
htmltree.addContent(DocletConstants.NL); paramTree.addContent(DocletConstants.NL);
htmltree.addContent(indent); paramTree.addContent(indent);
if (includeAnnotations) { if (includeAnnotations) {
boolean foundAnnotations = boolean foundAnnotations =
writer.addAnnotationInfo(indent.length(), member, parameters.get(i), writer.addAnnotationInfo(indent.length(), member, parameters.get(i),
htmltree); paramTree);
if (foundAnnotations) { if (foundAnnotations) {
htmltree.addContent(DocletConstants.NL); paramTree.addContent(DocletConstants.NL);
htmltree.addContent(indent); paramTree.addContent(indent);
} }
} }
addParam(member, parameters.get(i), (i == parameters.size() - 1) && member.isVarArgs(), addParam(member, parameters.get(i), (i == parameters.size() - 1) && member.isVarArgs(),
htmltree); paramTree);
}
if (paramTree.isEmpty()) {
htmltree.addContent("()");
} else {
htmltree.addContent(Contents.ZERO_WIDTH_SPACE);
htmltree.addContent("(");
htmltree.addContent(paramTree);
paramTree.addContent(")");
} }
htmltree.addContent(")");
} }
/** /**

View file

@ -364,7 +364,7 @@ public class AbstractIndexWriter extends HtmlDocletWriter {
List<? extends DocTree> tags; List<? extends DocTree> tags;
Content span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(element)); Content span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(element));
HtmlTree div = new HtmlTree(HtmlTag.DIV); HtmlTree div = new HtmlTree(HtmlTag.DIV);
div.addStyle(HtmlStyle.block); div.addStyle(HtmlStyle.deprecationBlock);
if (utils.isDeprecated(element)) { if (utils.isDeprecated(element)) {
div.addContent(span); div.addContent(span);
tags = utils.getBlockTags(element, DocTree.Kind.DEPRECATED); tags = utils.getBlockTags(element, DocTree.Kind.DEPRECATED);

View file

@ -355,7 +355,7 @@ public abstract class AbstractMemberWriter {
writer.getTagletWriterInstance(false)); writer.getTagletWriterInstance(false));
if (!output.isEmpty()) { if (!output.isEmpty()) {
Content deprecatedContent = output; Content deprecatedContent = output;
Content div = HtmlTree.DIV(HtmlStyle.block, deprecatedContent); Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprecatedContent);
contentTree.addContent(div); contentTree.addContent(div);
} }
} }

View file

@ -278,7 +278,8 @@ public class AnnotationTypeWriterImpl extends SubWriterHolderWriter
*/ */
@Override @Override
public void addAnnotationTypeSignature(String modifiers, Content annotationInfoTree) { public void addAnnotationTypeSignature(String modifiers, Content annotationInfoTree) {
annotationInfoTree.addContent(new HtmlTree(HtmlTag.BR)); Content hr = new HtmlTree(HtmlTag.HR);
annotationInfoTree.addContent(hr);
Content pre = new HtmlTree(HtmlTag.PRE); Content pre = new HtmlTree(HtmlTag.PRE);
addAnnotationInfo(annotationType, pre); addAnnotationInfo(annotationType, pre);
pre.addContent(modifiers); pre.addContent(modifiers);
@ -324,18 +325,15 @@ public class AnnotationTypeWriterImpl extends SubWriterHolderWriter
*/ */
@Override @Override
public void addAnnotationTypeDeprecationInfo(Content annotationInfoTree) { public void addAnnotationTypeDeprecationInfo(Content annotationInfoTree) {
Content hr = new HtmlTree(HtmlTag.HR);
annotationInfoTree.addContent(hr);
List<? extends DocTree> deprs = utils.getBlockTags(annotationType, DocTree.Kind.DEPRECATED); List<? extends DocTree> deprs = utils.getBlockTags(annotationType, DocTree.Kind.DEPRECATED);
if (utils.isDeprecated(annotationType)) { if (utils.isDeprecated(annotationType)) {
CommentHelper ch = utils.getCommentHelper(annotationType); CommentHelper ch = utils.getCommentHelper(annotationType);
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(annotationType)); Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(annotationType));
Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel); Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel);
if (!deprs.isEmpty()) { if (!deprs.isEmpty()) {
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0)); List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
if (!commentTags.isEmpty()) { if (!commentTags.isEmpty()) {
div.addContent(Contents.SPACE);
addInlineDeprecatedComment(annotationType, deprs.get(0), div); addInlineDeprecatedComment(annotationType, deprs.get(0), div);
} }
} }

View file

@ -293,7 +293,8 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
*/ */
@Override @Override
public void addClassSignature(String modifiers, Content classInfoTree) { public void addClassSignature(String modifiers, Content classInfoTree) {
classInfoTree.addContent(new HtmlTree(HtmlTag.BR)); Content hr = new HtmlTree(HtmlTag.HR);
classInfoTree.addContent(hr);
Content pre = new HtmlTree(HtmlTag.PRE); Content pre = new HtmlTree(HtmlTag.PRE);
addAnnotationInfo(typeElement, pre); addAnnotationInfo(typeElement, pre);
pre.addContent(modifiers); pre.addContent(modifiers);
@ -606,18 +607,15 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
*/ */
@Override @Override
public void addClassDeprecationInfo(Content classInfoTree) { public void addClassDeprecationInfo(Content classInfoTree) {
Content hr = new HtmlTree(HtmlTag.HR);
classInfoTree.addContent(hr);
List<? extends DocTree> deprs = utils.getBlockTags(typeElement, DocTree.Kind.DEPRECATED); List<? extends DocTree> deprs = utils.getBlockTags(typeElement, DocTree.Kind.DEPRECATED);
if (utils.isDeprecated(typeElement)) { if (utils.isDeprecated(typeElement)) {
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(typeElement)); Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(typeElement));
Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel); Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel);
if (!deprs.isEmpty()) { if (!deprs.isEmpty()) {
CommentHelper ch = utils.getCommentHelper(typeElement); CommentHelper ch = utils.getCommentHelper(typeElement);
DocTree dt = deprs.get(0); DocTree dt = deprs.get(0);
List<? extends DocTree> commentTags = ch.getBody(configuration, dt); List<? extends DocTree> commentTags = ch.getBody(configuration, dt);
if (!commentTags.isEmpty()) { if (!commentTags.isEmpty()) {
div.addContent(Contents.SPACE);
addInlineDeprecatedComment(typeElement, deprs.get(0), div); addInlineDeprecatedComment(typeElement, deprs.get(0), div);
} }
} }

View file

@ -100,33 +100,33 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
private String getHeadingKey(DeprElementKind kind) { private String getHeadingKey(DeprElementKind kind) {
switch (kind) { switch (kind) {
case REMOVAL: case REMOVAL:
return "doclet.Deprecated_For_Removal"; return "doclet.For_Removal";
case MODULE: case MODULE:
return "doclet.Deprecated_Modules"; return "doclet.Modules";
case PACKAGE: case PACKAGE:
return "doclet.Deprecated_Packages"; return "doclet.Packages";
case INTERFACE: case INTERFACE:
return "doclet.Deprecated_Interfaces"; return "doclet.Interfaces";
case CLASS: case CLASS:
return "doclet.Deprecated_Classes"; return "doclet.Classes";
case ENUM: case ENUM:
return "doclet.Deprecated_Enums"; return "doclet.Enums";
case EXCEPTION: case EXCEPTION:
return "doclet.Deprecated_Exceptions"; return "doclet.Exceptions";
case ERROR: case ERROR:
return "doclet.Deprecated_Errors"; return "doclet.Errors";
case ANNOTATION_TYPE: case ANNOTATION_TYPE:
return "doclet.Deprecated_Annotation_Types"; return "doclet.Annotation_Types";
case FIELD: case FIELD:
return "doclet.Deprecated_Fields"; return "doclet.Fields";
case METHOD: case METHOD:
return "doclet.Deprecated_Methods"; return "doclet.Methods";
case CONSTRUCTOR: case CONSTRUCTOR:
return "doclet.Deprecated_Constructors"; return "doclet.Constructors";
case ENUM_CONSTANT: case ENUM_CONSTANT:
return "doclet.Deprecated_Enum_Constants"; return "doclet.Enum_Constants";
case ANNOTATION_TYPE_MEMBER: case ANNOTATION_TYPE_MEMBER:
return "doclet.Deprecated_Annotation_Type_Members"; return "doclet.Annotation_Type_Members";
default: default:
throw new AssertionError("unknown kind: " + kind); throw new AssertionError("unknown kind: " + kind);
} }
@ -135,33 +135,33 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
private String getSummaryKey(DeprElementKind kind) { private String getSummaryKey(DeprElementKind kind) {
switch (kind) { switch (kind) {
case REMOVAL: case REMOVAL:
return "doclet.deprecated_for_removal"; return "doclet.for_removal";
case MODULE: case MODULE:
return "doclet.deprecated_modules"; return "doclet.modules";
case PACKAGE: case PACKAGE:
return "doclet.deprecated_packages"; return "doclet.packages";
case INTERFACE: case INTERFACE:
return "doclet.deprecated_interfaces"; return "doclet.interfaces";
case CLASS: case CLASS:
return "doclet.deprecated_classes"; return "doclet.classes";
case ENUM: case ENUM:
return "doclet.deprecated_enums"; return "doclet.enums";
case EXCEPTION: case EXCEPTION:
return "doclet.deprecated_exceptions"; return "doclet.exceptions";
case ERROR: case ERROR:
return "doclet.deprecated_errors"; return "doclet.errors";
case ANNOTATION_TYPE: case ANNOTATION_TYPE:
return "doclet.deprecated_annotation_types"; return "doclet.annotation_types";
case FIELD: case FIELD:
return "doclet.deprecated_fields"; return "doclet.fields";
case METHOD: case METHOD:
return "doclet.deprecated_methods"; return "doclet.methods";
case CONSTRUCTOR: case CONSTRUCTOR:
return "doclet.deprecated_constructors"; return "doclet.constructors";
case ENUM_CONSTANT: case ENUM_CONSTANT:
return "doclet.deprecated_enum_constants"; return "doclet.enum_constants";
case ANNOTATION_TYPE_MEMBER: case ANNOTATION_TYPE_MEMBER:
return "doclet.deprecated_annotation_type_members"; return "doclet.annotation_type_members";
default: default:
throw new AssertionError("unknown kind: " + kind); throw new AssertionError("unknown kind: " + kind);
} }
@ -473,6 +473,6 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
default: default:
writer = new AnnotationTypeOptionalMemberWriterImpl(this, null); writer = new AnnotationTypeOptionalMemberWriterImpl(this, null);
} }
return HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, writer.getDeprecatedLink(e)); return HtmlTree.TH_ROW_SCOPE(HtmlStyle.colDeprecatedItemName, writer.getDeprecatedLink(e));
} }
} }

View file

@ -1715,8 +1715,7 @@ public class HtmlDocletWriter extends HtmlDocWriter {
Content div; Content div;
Content result = commentTagsToContent(null, element, tags, first); Content result = commentTagsToContent(null, element, tags, first);
if (depr) { if (depr) {
Content italic = HtmlTree.SPAN(HtmlStyle.deprecationComment, result); div = HtmlTree.DIV(HtmlStyle.deprecationComment, result);
div = HtmlTree.DIV(HtmlStyle.block, italic);
htmltree.addContent(div); htmltree.addContent(div);
} }
else { else {

View file

@ -929,7 +929,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
if (utils.isDeprecated(mdle)) { if (utils.isDeprecated(mdle)) {
CommentHelper ch = utils.getCommentHelper(mdle); CommentHelper ch = utils.getCommentHelper(mdle);
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV); HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
deprDiv.addStyle(HtmlStyle.deprecatedContent); deprDiv.addStyle(HtmlStyle.deprecationBlock);
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle)); Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle));
deprDiv.addContent(deprPhrase); deprDiv.addContent(deprPhrase);
if (!deprs.isEmpty()) { if (!deprs.isEmpty()) {
@ -1064,7 +1064,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
if (utils.isDeprecated(pkg)) { if (utils.isDeprecated(pkg)) {
deprs = utils.getDeprecatedTrees(pkg); deprs = utils.getDeprecatedTrees(pkg);
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV); HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
deprDiv.addStyle(HtmlStyle.deprecatedContent); deprDiv.addStyle(HtmlStyle.deprecationBlock);
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg)); Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg));
deprDiv.addContent(deprPhrase); deprDiv.addContent(deprPhrase);
if (!deprs.isEmpty()) { if (!deprs.isEmpty()) {

View file

@ -171,7 +171,7 @@ public class PackageWriterImpl extends HtmlDocletWriter
if (utils.isDeprecated(packageElement)) { if (utils.isDeprecated(packageElement)) {
CommentHelper ch = utils.getCommentHelper(packageElement); CommentHelper ch = utils.getCommentHelper(packageElement);
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV); HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
deprDiv.addStyle(HtmlStyle.deprecatedContent); deprDiv.addStyle(HtmlStyle.deprecationBlock);
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(packageElement)); Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(packageElement));
deprDiv.addContent(deprPhrase); deprDiv.addContent(deprPhrase);
if (!deprs.isEmpty()) { if (!deprs.isEmpty()) {

View file

@ -189,9 +189,8 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter {
if (utils.isDeprecated(member)) { if (utils.isDeprecated(member)) {
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(member)); Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(member));
div = HtmlTree.DIV(HtmlStyle.block, deprLabel); div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
div.addContent(Contents.SPACE);
if (!deprs.isEmpty()) { if (!deprs.isEmpty()) {
addInlineDeprecatedComment(member, deprs.get(0), div); addSummaryDeprecatedComment(member, deprs.get(0), div);
} }
tdSummary.addContent(div); tdSummary.addContent(div);
return; return;
@ -200,7 +199,6 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter {
if (te != null && utils.isTypeElement(te) && utils.isDeprecated(te)) { if (te != null && utils.isTypeElement(te) && utils.isDeprecated(te)) {
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(te)); Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(te));
div = HtmlTree.DIV(HtmlStyle.block, deprLabel); div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
div.addContent(Contents.SPACE);
tdSummary.addContent(div); tdSummary.addContent(div);
} }
} }

View file

@ -179,7 +179,6 @@ public class TagletWriterImpl extends TagletWriter {
if (utils.isDeprecated(element)) { if (utils.isDeprecated(element)) {
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel, result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
htmlWriter.getDeprecatedPhrase(element))); htmlWriter.getDeprecatedPhrase(element)));
result.addContent(RawHtml.nbsp);
if (!deprs.isEmpty()) { if (!deprs.isEmpty()) {
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0)); List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
if (!commentTags.isEmpty()) { if (!commentTags.isEmpty()) {
@ -191,19 +190,17 @@ public class TagletWriterImpl extends TagletWriter {
if (utils.isDeprecated(element)) { if (utils.isDeprecated(element)) {
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel, result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
htmlWriter.getDeprecatedPhrase(element))); htmlWriter.getDeprecatedPhrase(element)));
result.addContent(RawHtml.nbsp);
if (!deprs.isEmpty()) { if (!deprs.isEmpty()) {
List<? extends DocTree> bodyTags = ch.getBody(configuration, deprs.get(0)); List<? extends DocTree> bodyTags = ch.getBody(configuration, deprs.get(0));
Content body = commentTagsToOutput(null, element, bodyTags, false); Content body = commentTagsToOutput(null, element, bodyTags, false);
if (!body.isEmpty()) if (!body.isEmpty())
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecationComment, body)); result.addContent(HtmlTree.DIV(HtmlStyle.deprecationComment, body));
} }
} else { } else {
Element ee = utils.getEnclosingTypeElement(element); Element ee = utils.getEnclosingTypeElement(element);
if (utils.isDeprecated(ee)) { if (utils.isDeprecated(ee)) {
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel, result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
htmlWriter.getDeprecatedPhrase(ee))); htmlWriter.getDeprecatedPhrase(ee)));
result.addContent(RawHtml.nbsp);
} }
} }
} }

View file

@ -47,15 +47,16 @@ public enum HtmlStyle {
circle, circle,
classUseContainer, classUseContainer,
colConstructorName, colConstructorName,
colDeprecatedItemName,
colFirst, colFirst,
colLast, colLast,
colSecond, colSecond,
constantsSummary, constantsSummary,
constantValuesContainer, constantValuesContainer,
contentContainer, contentContainer,
deprecatedContent,
deprecatedLabel, deprecatedLabel,
deprecatedSummary, deprecatedSummary,
deprecationBlock,
deprecationComment, deprecationComment,
description, description,
descfrmTypeLabel, descfrmTypeLabel,

View file

@ -74,34 +74,12 @@ doclet.see.class_or_package_not_found=Tag {0}: reference not found: {1}
doclet.see.class_or_package_not_accessible=Tag {0}: reference not accessible: {1} doclet.see.class_or_package_not_accessible=Tag {0}: reference not accessible: {1}
doclet.tag.invalid_usage=invalid usage of tag {0} doclet.tag.invalid_usage=invalid usage of tag {0}
doclet.Deprecated_API=Deprecated API doclet.Deprecated_API=Deprecated API
doclet.Deprecated_For_Removal=Deprecated For Removal doclet.For_Removal=For Removal
doclet.Deprecated_Modules=Deprecated Modules doclet.Annotation_Types=Annotation Types
doclet.Deprecated_Packages=Deprecated Packages doclet.Annotation_Type_Members=Annotation Type Elements
doclet.Deprecated_Classes=Deprecated Classes doclet.for_removal=for removal
doclet.Deprecated_Enums=Deprecated Enums doclet.annotation_types=annotation types
doclet.Deprecated_Interfaces=Deprecated Interfaces doclet.annotation_type_members=annotation type elements
doclet.Deprecated_Exceptions=Deprecated Exceptions
doclet.Deprecated_Annotation_Types=Deprecated Annotation Types
doclet.Deprecated_Errors=Deprecated Errors
doclet.Deprecated_Fields=Deprecated Fields
doclet.Deprecated_Constructors=Deprecated Constructors
doclet.Deprecated_Methods=Deprecated Methods
doclet.Deprecated_Enum_Constants=Deprecated Enum Constants
doclet.Deprecated_Annotation_Type_Members=Deprecated Annotation Type Elements
doclet.deprecated_for_removal=deprecated for removal
doclet.deprecated_modules=deprecated modules
doclet.deprecated_packages=deprecated packages
doclet.deprecated_classes=deprecated classes
doclet.deprecated_enums=deprecated enums
doclet.deprecated_interfaces=deprecated interfaces
doclet.deprecated_exceptions=deprecated exceptions
doclet.deprecated_annotation_types=deprecated annotation types
doclet.deprecated_errors=deprecated errors
doclet.deprecated_fields=deprecated fields
doclet.deprecated_constructors=deprecated constructors
doclet.deprecated_methods=deprecated methods
doclet.deprecated_enum_constants=deprecated enum constants
doclet.deprecated_annotation_type_members=deprecated annotation type elements
doclet.Generated_Docs_Untitled=Generated Documentation (Untitled) doclet.Generated_Docs_Untitled=Generated Documentation (Untitled)
doclet.Other_Packages=Other Packages doclet.Other_Packages=Other Packages
doclet.Description=Description doclet.Description=Description

View file

@ -147,8 +147,8 @@ public class AnnotationTypeBuilder extends AbstractBuilder {
throws DocletException { throws DocletException {
Content annotationInfoTree = writer.getAnnotationInfoTreeHeader(); Content annotationInfoTree = writer.getAnnotationInfoTreeHeader();
buildDeprecationInfo(annotationInfoTree);
buildAnnotationTypeSignature(annotationInfoTree); buildAnnotationTypeSignature(annotationInfoTree);
buildDeprecationInfo(annotationInfoTree);
buildAnnotationTypeDescription(annotationInfoTree); buildAnnotationTypeDescription(annotationInfoTree);
buildAnnotationTypeTagInfo(annotationInfoTree); buildAnnotationTypeTagInfo(annotationInfoTree);

View file

@ -175,8 +175,8 @@ public class ClassBuilder extends AbstractBuilder {
buildInterfaceUsageInfo(classInfoTree); buildInterfaceUsageInfo(classInfoTree);
buildNestedClassInfo(classInfoTree); buildNestedClassInfo(classInfoTree);
buildFunctionalInterfaceInfo(classInfoTree); buildFunctionalInterfaceInfo(classInfoTree);
buildDeprecationInfo(classInfoTree);
buildClassSignature(classInfoTree); buildClassSignature(classInfoTree);
buildDeprecationInfo(classInfoTree);
buildClassDescription(classInfoTree); buildClassDescription(classInfoTree);
buildClassTagInfo(classInfoTree); buildClassTagInfo(classInfoTree);

View file

@ -531,14 +531,16 @@ Table styles
text-align:left; text-align:left;
padding:0px 0px 12px 10px; padding:0px 0px 12px 10px;
} }
th.colFirst, th.colSecond, th.colLast, th.colConstructorName, .useSummary th, .constantsSummary th, .packagesSummary th, th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .useSummary th,
td.colFirst, td.colSecond, td.colLast, .useSummary td, .constantsSummary td { .constantsSummary th, .packagesSummary th, td.colFirst, td.colSecond, td.colLast, .useSummary td,
.constantsSummary td {
vertical-align:top; vertical-align:top;
padding-right:0px; padding-right:0px;
padding-top:8px; padding-top:8px;
padding-bottom:3px; padding-bottom:3px;
} }
th.colFirst, th.colSecond, th.colLast, th.colConstructorName, .constantsSummary th, .packagesSummary th { th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .constantsSummary th,
.packagesSummary th {
background:#dee3e9; background:#dee3e9;
text-align:left; text-align:left;
padding:8px 3px 3px 7px; padding:8px 3px 3px 7px;
@ -547,7 +549,7 @@ td.colFirst, th.colFirst {
white-space:nowrap; white-space:nowrap;
font-size:13px; font-size:13px;
} }
td.colSecond, th.colSecond, td.colLast, th.colConstructorName, th.colLast { td.colSecond, th.colSecond, td.colLast, th.colConstructorName, th.colDeprecatedItemName, th.colLast {
font-size:13px; font-size:13px;
} }
.constantsSummary th, .packagesSummary th { .constantsSummary th, .packagesSummary th {
@ -576,6 +578,7 @@ td.colSecond a:link, td.colSecond a:visited,
th.colFirst a:link, th.colFirst a:visited, th.colFirst a:link, th.colFirst a:visited,
th.colSecond a:link, th.colSecond a:visited, th.colSecond a:link, th.colSecond a:visited,
th.colConstructorName a:link, th.colConstructorName a:visited, th.colConstructorName a:link, th.colConstructorName a:visited,
th.colDeprecatedItemName a:link, th.colDeprecatedItemName a:visited,
.constantValuesContainer td a:link, .constantValuesContainer td a:visited { .constantValuesContainer td a:link, .constantValuesContainer td a:visited {
font-weight:bold; font-weight:bold;
} }
@ -645,8 +648,19 @@ h1.hidden {
.deprecationComment, .emphasizedPhrase, .interfaceName { .deprecationComment, .emphasizedPhrase, .interfaceName {
font-style:italic; font-style:italic;
} }
.deprecationBlock {
font-size:14px;
font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
border-style:solid;
border-width:thin;
border-radius:10px;
padding:10px;
margin-bottom:10px;
margin-right:10px;
display:inline-block;
}
div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase, div.block div.deprecationComment, div.block div.block span.emphasizedPhrase,
div.block div.block span.interfaceName { div.block div.block span.interfaceName {
font-style:normal; font-style:normal;
} }

View file

@ -78,7 +78,7 @@ public class DeprecatedAPIListBuilder {
deprecatedMap = new EnumMap<>(DeprElementKind.class); deprecatedMap = new EnumMap<>(DeprElementKind.class);
for (DeprElementKind kind : DeprElementKind.values()) { for (DeprElementKind kind : DeprElementKind.values()) {
deprecatedMap.put(kind, deprecatedMap.put(kind,
new TreeSet<>(utils.makeGeneralPurposeComparator())); new TreeSet<>(utils.makeDeprecatedComparator()));
} }
buildDeprecatedAPIInfo(); buildDeprecatedAPIInfo();
} }

View file

@ -1733,6 +1733,25 @@ public class Utils {
return packageComparator; return packageComparator;
} }
private Comparator<Element> deprecatedComparator = null;
/**
* Returns a Comparator for deprecated items listed on deprecated list page, by comparing the
* fully qualified names.
*
* @return a Comparator
*/
public Comparator<Element> makeDeprecatedComparator() {
if (deprecatedComparator == null) {
deprecatedComparator = new Utils.ElementComparator() {
@Override
public int compare(Element e1, Element e2) {
return compareFullyQualifiedNames(e1, e2);
}
};
}
return deprecatedComparator;
}
private Comparator<SerialFieldTree> serialFieldTreeComparator = null; private Comparator<SerialFieldTree> serialFieldTreeComparator = null;
/** /**
* Returns a Comparator for SerialFieldTree. * Returns a Comparator for SerialFieldTree.

View file

@ -234,49 +234,6 @@ class JdepsTask {
} }
}, },
new Option(true, CommandOption.CHECK_MODULES) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
Set<String> mods = Set.of(arg.split(","));
task.options.addmods.addAll(mods);
task.command = task.checkModuleDeps(mods);
}
},
new Option(true, CommandOption.GENERATE_MODULE_INFO) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.command = task.genModuleInfo(Paths.get(arg), false);
}
},
new Option(true, CommandOption.GENERATE_OPEN_MODULE) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.command = task.genModuleInfo(Paths.get(arg), true);
}
},
new Option(false, CommandOption.LIST_DEPS) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.command = task.listModuleDeps(false);
}
},
new Option(false, CommandOption.LIST_REDUCED_DEPS) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.command = task.listModuleDeps(true);
}
},
// ---- paths option ---- // ---- paths option ----
new Option(true, "-cp", "-classpath", "--class-path") { new Option(true, "-cp", "-classpath", "--class-path") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
@ -312,15 +269,6 @@ class JdepsTask {
task.options.addmods.addAll(mods); task.options.addmods.addAll(mods);
} }
}, },
new Option(true, "-m", "--module") {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (!task.options.rootModules.isEmpty()) {
throw new BadArgs("err.option.already.specified", opt);
}
task.options.rootModules.add(arg);
task.options.addmods.add(arg);
}
},
new Option(true, "--multi-release") { new Option(true, "--multi-release") {
void process(JdepsTask task, String opt, String arg) throws BadArgs { void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (arg.equalsIgnoreCase("base")) { if (arg.equalsIgnoreCase("base")) {
@ -338,6 +286,70 @@ class JdepsTask {
} }
} }
}, },
new Option(false, "-q", "-quiet") {
void process(JdepsTask task, String opt, String arg) {
task.options.nowarning = true;
}
},
new Option(false, "-version", "--version") {
void process(JdepsTask task, String opt, String arg) {
task.options.version = true;
}
},
// ---- module-specific options ----
new Option(true, "-m", "--module") {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (!task.options.rootModules.isEmpty()) {
throw new BadArgs("err.option.already.specified", opt);
}
task.options.rootModules.add(arg);
task.options.addmods.add(arg);
}
},
new Option(true, CommandOption.GENERATE_MODULE_INFO) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.command = task.genModuleInfo(Paths.get(arg), false);
}
},
new Option(true, CommandOption.GENERATE_OPEN_MODULE) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.command = task.genModuleInfo(Paths.get(arg), true);
}
},
new Option(true, CommandOption.CHECK_MODULES) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
Set<String> mods = Set.of(arg.split(","));
task.options.addmods.addAll(mods);
task.command = task.checkModuleDeps(mods);
}
},
new Option(false, CommandOption.LIST_DEPS) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.command = task.listModuleDeps(false);
}
},
new Option(false, CommandOption.LIST_REDUCED_DEPS) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.command = task.listModuleDeps(true);
}
},
// ---- Target filtering options ---- // ---- Target filtering options ----
new Option(true, "-p", "-package", "--package") { new Option(true, "-p", "-package", "--package") {
@ -424,17 +436,6 @@ class JdepsTask {
} }
}, },
new Option(false, "-q", "-quiet") {
void process(JdepsTask task, String opt, String arg) {
task.options.nowarning = true;
}
},
new Option(false, "-version", "--version") {
void process(JdepsTask task, String opt, String arg) {
task.options.version = true;
}
},
new HiddenOption(false, "-fullversion") { new HiddenOption(false, "-fullversion") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
task.options.fullVersion = true; task.options.fullVersion = true;

View file

@ -86,10 +86,6 @@ main.opt.add-modules=\
\ --add-modules <module-name>[,<module-name>...]\n\ \ --add-modules <module-name>[,<module-name>...]\n\
\ Adds modules to the root set for analysis \ Adds modules to the root set for analysis
main.opt.m=\
\ -m <module-name>\n\
\ --module <module-name> Specify the root module for analysis
main.opt.R=\ main.opt.R=\
\ -R -recursive Recursively traverse all run-time dependences.\n\ \ -R -recursive Recursively traverse all run-time dependences.\n\
\ The -R option implies -filter:none. If -p,\n\ \ The -R option implies -filter:none. If -p,\n\
@ -121,6 +117,11 @@ main.opt.apionly=\
\ type, method parameter types, returned type,\n\ \ type, method parameter types, returned type,\n\
\ checked exception types etc. \ checked exception types etc.
main.opt.m=\n\
\Module dependence analysis options:\n\
\ -m <module-name>\n\
\ --module <module-name> Specify the root module for analysis
main.opt.generate-module-info=\ main.opt.generate-module-info=\
\ --generate-module-info <dir> Generate module-info.java under the specified\n\ \ --generate-module-info <dir> Generate module-info.java under the specified\n\
\ directory. The specified JAR files will be\n\ \ directory. The specified JAR files will be\n\
@ -142,7 +143,6 @@ main.opt.check=\
\ graph after transition reduction. It also\n\ \ graph after transition reduction. It also\n\
\ identifies any unused qualified exports. \ identifies any unused qualified exports.
main.opt.dotoutput=\ main.opt.dotoutput=\
\ -dotoutput <dir>\n\ \ -dotoutput <dir>\n\
\ --dot-output <dir> Destination directory for DOT file output \ --dot-output <dir> Destination directory for DOT file output
@ -157,15 +157,15 @@ main.opt.jdkinternals=\
\ WARNING: JDK internal APIs are inaccessible. \ WARNING: JDK internal APIs are inaccessible.
main.opt.list-deps=\ main.opt.list-deps=\
\ --list-deps Lists the dependences and use of JDK internal\n\ \ --list-deps Lists the module dependences and also the\n\
\ APIs. \ package names of JDK internal APIs if referenced.
main.opt.list-reduced-deps=\ main.opt.list-reduced-deps=\
\ --list-reduced-deps Same as --list-deps with not listing\n\ \ --list-reduced-deps Same as --list-deps with not listing\n\
\ the implied reads edges from the module graph\n\ \ the implied reads edges from the module graph\n\
\ If module M1 depends on M2 and M3,\n\ \ If module M1 reads M2, and M2 requires\n\
\ M2 requires public on M3, then M1 reading M3 is\n\ \ transitive on M3, then M1 reading M3 is implied\n\
\ implied and removed from the module graph. \ and is not shown in the graph.
main.opt.depth=\ main.opt.depth=\
\ -depth=<depth> Specify the depth of the transitive\n\ \ -depth=<depth> Specify the depth of the transitive\n\

View file

@ -40,6 +40,7 @@ import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree; import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MethodTree; import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ModifiersTree; import com.sun.source.tree.ModifiersTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree; import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree; import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree;
@ -59,6 +60,7 @@ import jdk.jshell.TaskFactory.AnalyzeTask;
import jdk.jshell.TaskFactory.BaseTask; import jdk.jshell.TaskFactory.BaseTask;
import jdk.jshell.TaskFactory.CompileTask; import jdk.jshell.TaskFactory.CompileTask;
import jdk.jshell.TaskFactory.ParseTask; import jdk.jshell.TaskFactory.ParseTask;
import jdk.jshell.Wrap.CompoundWrap;
import jdk.jshell.Wrap.Range; import jdk.jshell.Wrap.Range;
import jdk.jshell.Snippet.Status; import jdk.jshell.Snippet.Status;
import jdk.jshell.spi.ExecutionControl.ClassBytecodes; import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
@ -274,26 +276,119 @@ class Eval {
for (Tree unitTree : units) { for (Tree unitTree : units) {
VariableTree vt = (VariableTree) unitTree; VariableTree vt = (VariableTree) unitTree;
String name = vt.getName().toString(); String name = vt.getName().toString();
String typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false); String typeName;
Tree baseType = vt.getType(); String fullTypeName;
TreeDependencyScanner tds = new TreeDependencyScanner(); TreeDependencyScanner tds = new TreeDependencyScanner();
tds.scan(baseType); // Not dependent on initializer Wrap typeWrap;
Wrap anonDeclareWrap = null;
Wrap winit = null;
StringBuilder sbBrackets = new StringBuilder(); StringBuilder sbBrackets = new StringBuilder();
while (baseType instanceof ArrayTypeTree) { Tree baseType = vt.getType();
//TODO handle annotations too if (baseType != null) {
baseType = ((ArrayTypeTree) baseType).getType(); tds.scan(baseType); // Not dependent on initializer
sbBrackets.append("[]"); fullTypeName = typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
while (baseType instanceof ArrayTypeTree) {
//TODO handle annotations too
baseType = ((ArrayTypeTree) baseType).getType();
sbBrackets.append("[]");
}
Range rtype = dis.treeToRange(baseType);
typeWrap = Wrap.rangeWrap(compileSource, rtype);
} else {
Tree init = vt.getInitializer();
if (init != null) {
Range rinit = dis.treeToRange(init);
String initCode = rinit.part(compileSource);
ExpressionInfo ei =
ExpressionToTypeInfo.localVariableTypeForInitializer(initCode, state);
typeName = ei == null ? "java.lang.Object" : ei.typeName;
fullTypeName = ei == null ? "java.lang.Object" : ei.fullTypeName;
if (ei != null && init.getKind() == Tree.Kind.NEW_CLASS &&
((NewClassTree) init).getClassBody() != null) {
NewClassTree nct = (NewClassTree) init;
StringBuilder constructor = new StringBuilder();
constructor.append(fullTypeName).append("(");
String sep = "";
if (ei.enclosingInstanceType != null) {
constructor.append(ei.enclosingInstanceType);
constructor.append(" encl");
sep = ", ";
}
int idx = 0;
for (String type : ei.parameterTypes) {
constructor.append(sep);
constructor.append(type);
constructor.append(" ");
constructor.append("arg" + idx++);
sep = ", ";
}
if (ei.enclosingInstanceType != null) {
constructor.append(") { encl.super (");
} else {
constructor.append(") { super (");
}
sep = "";
for (int i = 0; i < idx; i++) {
constructor.append(sep);
constructor.append("arg" + i++);
sep = ", ";
}
constructor.append("); }");
List<? extends Tree> members = nct.getClassBody().getMembers();
Range bodyRange = dis.treeListToRange(members);
Wrap bodyWrap;
if (bodyRange != null) {
bodyWrap = Wrap.rangeWrap(compileSource, bodyRange);
} else {
bodyWrap = Wrap.simpleWrap(" ");
}
Range argRange = dis.treeListToRange(nct.getArguments());
Wrap argWrap;
if (argRange != null) {
argWrap = Wrap.rangeWrap(compileSource, argRange);
} else {
argWrap = Wrap.simpleWrap(" ");
}
if (ei.enclosingInstanceType != null) {
Range enclosingRanges =
dis.treeToRange(nct.getEnclosingExpression());
Wrap enclosingWrap = Wrap.rangeWrap(compileSource, enclosingRanges);
argWrap = argRange != null ? new CompoundWrap(enclosingWrap,
Wrap.simpleWrap(","),
argWrap)
: enclosingWrap;
}
Wrap hwrap = Wrap.simpleWrap("public static class " + fullTypeName +
(ei.isClass ? " extends " : " implements ") +
typeName + " { " + constructor);
anonDeclareWrap = new CompoundWrap(hwrap, bodyWrap, Wrap.simpleWrap("}"));
winit = new CompoundWrap("new " + fullTypeName + "(", argWrap, ")");
String superType = typeName;
typeName = fullTypeName;
fullTypeName = ei.isClass ? "<anonymous class extending " + superType + ">"
: "<anonymous class implementing " + superType + ">";
}
tds.scan(init);
} else {
fullTypeName = typeName = "java.lang.Object";
}
typeWrap = Wrap.identityWrap(typeName);
} }
Range rtype = dis.treeToRange(baseType);
Range runit = dis.treeToRange(vt); Range runit = dis.treeToRange(vt);
runit = new Range(runit.begin, runit.end - 1); runit = new Range(runit.begin, runit.end - 1);
ExpressionTree it = vt.getInitializer(); ExpressionTree it = vt.getInitializer();
Range rinit = null;
int nameMax = runit.end - 1; int nameMax = runit.end - 1;
SubKind subkind; SubKind subkind;
if (it != null) { if (it != null) {
subkind = SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND; subkind = SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND;
rinit = dis.treeToRange(it); Range rinit = dis.treeToRange(it);
winit = winit == null ? Wrap.rangeWrap(compileSource, rinit) : winit;
nameMax = rinit.begin - 1; nameMax = rinit.begin - 1;
} else { } else {
subkind = SubKind.VAR_DECLARATION_SUBKIND; subkind = SubKind.VAR_DECLARATION_SUBKIND;
@ -304,10 +399,11 @@ class Eval {
} }
int nameEnd = nameStart + name.length(); int nameEnd = nameStart + name.length();
Range rname = new Range(nameStart, nameEnd); Range rname = new Range(nameStart, nameEnd);
Wrap guts = Wrap.varWrap(compileSource, rtype, sbBrackets.toString(), rname, rinit); Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), rname,
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true); winit, anonDeclareWrap);
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts, Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
name, subkind, typeName, name, subkind, fullTypeName,
tds.declareReferences(), modDiag); tds.declareReferences(), modDiag);
snippets.add(snip); snippets.add(snip);
} }

View file

@ -29,14 +29,20 @@ import com.sun.source.tree.ReturnTree;
import com.sun.source.tree.ClassTree; import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ConditionalExpressionTree; import com.sun.source.tree.ConditionalExpressionTree;
import com.sun.source.tree.ExpressionStatementTree;
import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree; import com.sun.source.tree.MethodTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree; import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePath; import com.sun.source.util.TreePath;
import com.sun.source.util.TreePathScanner; import com.sun.source.util.TreePathScanner;
import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types; import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.util.List;
import jdk.jshell.TaskFactory.AnalyzeTask; import jdk.jshell.TaskFactory.AnalyzeTask;
/** /**
@ -63,6 +69,10 @@ class ExpressionToTypeInfo {
public static class ExpressionInfo { public static class ExpressionInfo {
ExpressionTree tree; ExpressionTree tree;
String typeName; String typeName;
String fullTypeName;
List<String> parameterTypes;
String enclosingInstanceType;
boolean isClass;
boolean isNonVoid; boolean isNonVoid;
} }
@ -111,6 +121,16 @@ class ExpressionToTypeInfo {
return null; return null;
} }
} }
@Override
public TreePath visitVariable(VariableTree node, Boolean isTargetContext) {
if (isTargetContext) {
throw new Result(getCurrentPath());
} else {
return null;
}
}
} }
private Type pathToType(TreePath tp) { private Type pathToType(TreePath tp) {
@ -156,6 +176,30 @@ class ExpressionToTypeInfo {
} }
} }
/**
* Entry method: get expression info corresponding to a local variable declaration if its type
* has been inferred automatically from the given initializer.
* @param code the initializer as a string
* @param state a JShell instance
* @return type information
*/
public static ExpressionInfo localVariableTypeForInitializer(String code, JShell state) {
if (code == null || code.isEmpty()) {
return null;
}
try {
OuterWrap codeWrap = state.outerMap.wrapInTrialClass(Wrap.methodWrap("var $$$ = " + code));
AnalyzeTask at = state.taskFactory.new AnalyzeTask(codeWrap);
CompilationUnitTree cu = at.firstCuTree();
if (at.hasErrors() || cu == null) {
return null;
}
return new ExpressionToTypeInfo(at, cu, state).typeOfExpression();
} catch (Exception ex) {
return null;
}
}
private ExpressionInfo typeOfExpression() { private ExpressionInfo typeOfExpression() {
return treeToInfo(findExpressionPath()); return treeToInfo(findExpressionPath());
} }
@ -172,9 +216,11 @@ class ExpressionToTypeInfo {
private ExpressionInfo treeToInfo(TreePath tp) { private ExpressionInfo treeToInfo(TreePath tp) {
if (tp != null) { if (tp != null) {
Tree tree = tp.getLeaf(); Tree tree = tp.getLeaf();
if (tree instanceof ExpressionTree) { boolean isExpression = tree instanceof ExpressionTree;
if (isExpression || tree.getKind() == Kind.VARIABLE) {
ExpressionInfo ei = new ExpressionInfo(); ExpressionInfo ei = new ExpressionInfo();
ei.tree = (ExpressionTree) tree; if (isExpression)
ei.tree = (ExpressionTree) tree;
Type type = pathToType(tp, tree); Type type = pathToType(tp, tree);
if (type != null) { if (type != null) {
switch (type.getKind()) { switch (type.getKind()) {
@ -189,27 +235,56 @@ class ExpressionToTypeInfo {
break; break;
default: { default: {
ei.isNonVoid = true; ei.isNonVoid = true;
ei.typeName = varTypeName(type); ei.typeName = varTypeName(type, false);
if (ei.typeName == null) { ei.fullTypeName = varTypeName(type, true);
ei.typeName = OBJECT_TYPE_NAME;
}
break; break;
} }
} }
} }
if (tree.getKind() == Tree.Kind.VARIABLE) {
Tree init = ((VariableTree) tree).getInitializer();
if (init.getKind() == Tree.Kind.NEW_CLASS &&
((NewClassTree) init).getClassBody() != null) {
NewClassTree nct = (NewClassTree) init;
ClassTree clazz = nct.getClassBody();
MethodTree constructor = (MethodTree) clazz.getMembers().get(0);
ExpressionStatementTree superCallStatement =
(ExpressionStatementTree) constructor.getBody().getStatements().get(0);
MethodInvocationTree superCall =
(MethodInvocationTree) superCallStatement.getExpression();
TreePath superCallPath =
at.trees().getPath(tp.getCompilationUnit(), superCall.getMethodSelect());
Type constrType = pathToType(superCallPath);
ei.parameterTypes = constrType.getParameterTypes()
.stream()
.map(t -> varTypeName(t, false))
.collect(List.collector());
if (nct.getEnclosingExpression() != null) {
TreePath enclPath = new TreePath(tp, nct.getEnclosingExpression());
ei.enclosingInstanceType = varTypeName(pathToType(enclPath), false);
}
ei.isClass = at.task.getTypes().directSupertypes(type).size() == 1;
}
}
return ei; return ei;
} }
} }
return null; return null;
} }
private String varTypeName(Type type) { private String varTypeName(Type type, boolean printIntersectionTypes) {
try { try {
TypePrinter tp = new VarTypePrinter(at.messages(), TypePrinter tp = new TypePrinter(at.messages(),
state.maps::fullClassNameAndPackageToClass, syms, types); state.maps::fullClassNameAndPackageToClass, printIntersectionTypes);
return tp.toString(type); List<Type> captures = types.captures(type);
String res = tp.toString(types.upward(type, captures));
if (res == null)
res = OBJECT_TYPE_NAME;
return res;
} catch (Exception ex) { } catch (Exception ex) {
return null; return OBJECT_TYPE_NAME;
} }
} }

View file

@ -232,7 +232,7 @@ class ReplParser extends JavacParser {
//mods.flags |= Flags.STATIC; //mods.flags |= Flags.STATIC;
List<JCTree> defs List<JCTree> defs
= variableDeclaratorsRest(pos, mods, t, name, false, dc, = variableDeclaratorsRest(pos, mods, t, name, false, dc,
new ListBuffer<JCTree>()).toList(); new ListBuffer<JCTree>(), true).toList();
accept(SEMI); accept(SEMI);
storeEnd(defs.last(), S.prevToken().endPos); storeEnd(defs.last(), S.prevToken().endPos);
return defs; return defs;

View file

@ -134,6 +134,8 @@ import static jdk.jshell.TreeDissector.printType;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
import javax.lang.model.type.IntersectionType;
/** /**
* The concrete implementation of SourceCodeAnalysis. * The concrete implementation of SourceCodeAnalysis.
* @author Robert Field * @author Robert Field
@ -715,6 +717,13 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
return Collections.emptyList(); return Collections.emptyList();
switch (site.getKind()) { switch (site.getKind()) {
case INTERSECTION: {
List<Element> result = new ArrayList<>();
for (TypeMirror bound : ((IntersectionType) site).getBounds()) {
result.addAll(membersOf(at, bound, shouldGenerateDotClassItem));
}
return result;
}
case DECLARED: { case DECLARED: {
TypeElement element = (TypeElement) at.getTypes().asElement(site); TypeElement element = (TypeElement) at.getTypes().asElement(site);
List<Element> result = new ArrayList<>(); List<Element> result = new ArrayList<>();

View file

@ -61,7 +61,20 @@ import javax.lang.model.util.Elements;
import javax.tools.FileObject; import javax.tools.FileObject;
import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject; import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
import java.lang.Runtime.Version; import java.lang.Runtime.Version;
import java.nio.CharBuffer;
import com.sun.source.tree.Tree.Kind; import com.sun.source.tree.Tree.Kind;
import com.sun.tools.javac.code.Kinds;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.parser.Parser;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
import com.sun.tools.javac.tree.JCTree.Tag;
import com.sun.tools.javac.util.Context.Factory;
import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler;
import jdk.jshell.Snippet.Status;
/** /**
* The primary interface to the compiler API. Parsing, analysis, and * The primary interface to the compiler API. Parsing, analysis, and
@ -355,6 +368,7 @@ class TaskFactory {
Iterable<? extends JavaFileObject> compilationUnits = inputs Iterable<? extends JavaFileObject> compilationUnits = inputs
.map(in -> sh.sourceToFileObject(fileManager, in)) .map(in -> sh.sourceToFileObject(fileManager, in))
.collect(Collectors.toList()); .collect(Collectors.toList());
JShellJavaCompiler.preRegister(context, state);
this.task = (JavacTaskImpl) ((JavacTool) compiler).getTask(null, this.task = (JavacTaskImpl) ((JavacTool) compiler).getTask(null,
fileManager, diagnostics, options, null, fileManager, diagnostics, options, null,
compilationUnits, context); compilationUnits, context);
@ -464,4 +478,57 @@ class TaskFactory {
} }
} }
private static final class JShellJavaCompiler extends com.sun.tools.javac.main.JavaCompiler {
public static void preRegister(Context c, JShell state) {
c.put(compilerKey, (Factory<com.sun.tools.javac.main.JavaCompiler>) i -> new JShellJavaCompiler(i, state));
}
private final JShell state;
public JShellJavaCompiler(Context context, JShell state) {
super(context);
this.state = state;
}
@Override
public void processAnnotations(com.sun.tools.javac.util.List<JCCompilationUnit> roots, Collection<String> classnames) {
super.processAnnotations(roots, classnames);
state.maps
.snippetList()
.stream()
.filter(s -> s.status() == Status.VALID)
.filter(s -> s.kind() == Snippet.Kind.VAR)
.filter(s -> s.subKind() == Snippet.SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND)
.forEach(s -> setVariableType(roots, (VarSnippet) s));
}
private void setVariableType(com.sun.tools.javac.util.List<JCCompilationUnit> roots, VarSnippet s) {
ClassSymbol clazz = syms.getClass(syms.unnamedModule, names.fromString(s.classFullName()));
if (clazz == null || !clazz.isCompleted())
return;
VarSymbol field = (VarSymbol) clazz.members().findFirst(names.fromString(s.name()), sym -> sym.kind == Kinds.Kind.VAR);
if (field != null) {
JavaFileObject prev = log.useSource(null);
DiscardDiagnosticHandler h = new DiscardDiagnosticHandler(log);
try {
String typeName = s.typeName();
CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3);
Parser parser = parserFactory.newParser(buf, false, false, false);
JCExpression expr = parser.parseExpression();
if (expr.hasTag(Tag.TYPECAST)) {
JCTypeCast tree = (JCTypeCast) expr;
if (tree.clazz.hasTag(Tag.TYPEINTERSECTION)) {
field.type = attr.attribType(tree.clazz,
((JCClassDecl) roots.head.getTypeDecls().head).sym);
}
}
} finally {
log.popDiagnosticHandler(h);
log.useSource(prev);
}
}
}
}
} }

View file

@ -227,7 +227,7 @@ class TreeDissector {
Type typeImpl = (Type) type; Type typeImpl = (Type) type;
try { try {
TypePrinter tp = new TypePrinter(at.messages(), TypePrinter tp = new TypePrinter(at.messages(),
state.maps::fullClassNameAndPackageToClass); state.maps::fullClassNameAndPackageToClass, true);
return tp.toString(typeImpl); return tp.toString(typeImpl);
} catch (Exception ex) { } catch (Exception ex) {
return null; return null;

View file

@ -32,9 +32,11 @@ import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol; import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.ClassType; import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.code.Type.IntersectionClassType;
import com.sun.tools.javac.util.JavacMessages; import com.sun.tools.javac.util.JavacMessages;
import java.util.Locale; import java.util.Locale;
import java.util.function.BinaryOperator; import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
/** /**
* Print types in source form. * Print types in source form.
@ -45,10 +47,14 @@ class TypePrinter extends Printer {
private final JavacMessages messages; private final JavacMessages messages;
private final BinaryOperator<String> fullClassNameAndPackageToClass; private final BinaryOperator<String> fullClassNameAndPackageToClass;
private final boolean printEnhancedTypes;
TypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) { TypePrinter(JavacMessages messages,
BinaryOperator<String> fullClassNameAndPackageToClass,
boolean printEnhancedTypes) {
this.messages = messages; this.messages = messages;
this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass; this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass;
this.printEnhancedTypes = printEnhancedTypes;
} }
String toString(Type t) { String toString(Type t) {
@ -92,8 +98,18 @@ class TypePrinter extends Printer {
protected String className(ClassType t, boolean longform, Locale locale) { protected String className(ClassType t, boolean longform, Locale locale) {
Symbol sym = t.tsym; Symbol sym = t.tsym;
if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) { if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
return OBJECT; if (printEnhancedTypes) {
return ((IntersectionClassType) t).getExplicitComponents()
.stream()
.map(i -> visit(i, locale))
.collect(Collectors.joining("&"));
} else {
return OBJECT;
}
} else if (sym.name.length() == 0) { } else if (sym.name.length() == 0) {
if (printEnhancedTypes) {
return t.tsym.flatName().toString().substring(t.tsym.outermostClass().flatName().length());
}
// Anonymous // Anonymous
String s; String s;
ClassType norm = (ClassType) t.tsym.type; ClassType norm = (ClassType) t.tsym.type;

View file

@ -1,265 +0,0 @@
/*
* Copyright (c) 2016, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.jshell;
import java.util.HashSet;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.util.JavacMessages;
import java.util.Locale;
import java.util.Set;
import java.util.function.BinaryOperator;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type.CapturedType;
import com.sun.tools.javac.code.Type.StructuralTypeMapping;
import com.sun.tools.javac.code.Type.TypeVar;
import com.sun.tools.javac.code.Type.WildcardType;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.code.Types.SimpleVisitor;
import com.sun.tools.javac.util.List;
import static com.sun.tools.javac.code.BoundKind.EXTENDS;
import static com.sun.tools.javac.code.BoundKind.SUPER;
import static com.sun.tools.javac.code.BoundKind.UNBOUND;
import static com.sun.tools.javac.code.Type.ArrayType;
import static com.sun.tools.javac.code.TypeTag.BOT;
import static com.sun.tools.javac.code.TypeTag.WILDCARD;
/**
* Print variable types in source form.
* TypeProjection and CaptureScanner are copied from Types in the JEP-286
* Sandbox by Maurizio. The checks for Non-Denotable in TypePrinter are
* cribbed from denotableChecker of the same source.
*
* @author Maurizio Cimadamore
* @author Robert Field
*/
class VarTypePrinter extends TypePrinter {
private static final String WILD = "?";
private final Symtab syms;
private final Types types;
VarTypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass,
Symtab syms, Types types) {
super(messages, fullClassNameAndPackageToClass);
this.syms = syms;
this.types = types;
}
@Override
String toString(Type t) {
return super.toString(upward(t));
}
@Override
public String visitTypeVar(TypeVar t, Locale locale) {
/* Any type variable mentioned in the inferred type must have been declared as a type parameter
(i.e cannot have been produced by inference (18.4))
*/
// and beyond that, there are no global type vars, so if there are any
// type variables left, they need to be eliminated
return WILD; // Non-denotable
}
@Override
public String visitCapturedType(CapturedType t, Locale locale) {
/* Any type variable mentioned in the inferred type must have been declared as a type parameter
(i.e cannot have been produced by capture conversion (5.1.10))
*/
return WILD; // Non-denotable
}
public Type upward(Type t) {
List<Type> captures = captures(t);
return upward(t, captures);
}
/************* Following from JEP-286 Types.java ***********/
public Type upward(Type t, List<Type> vars) {
return t.map(new TypeProjection(vars), true);
}
public List<Type> captures(Type t) {
CaptureScanner cs = new CaptureScanner();
Set<Type> captures = new HashSet<>();
cs.visit(t, captures);
return List.from(captures);
}
class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
@Override
public Void visitType(Type t, Set<Type> types) {
return null;
}
@Override
public Void visitClassType(ClassType t, Set<Type> seen) {
if (t.isCompound()) {
types.directSupertypes(t).forEach(s -> visit(s, seen));
} else {
t.allparams().forEach(ta -> visit(ta, seen));
}
return null;
}
@Override
public Void visitArrayType(ArrayType t, Set<Type> seen) {
return visit(t.elemtype, seen);
}
@Override
public Void visitWildcardType(WildcardType t, Set<Type> seen) {
visit(t.type, seen);
return null;
}
@Override
public Void visitTypeVar(TypeVar t, Set<Type> seen) {
if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
visit(t.getUpperBound(), seen);
}
return null;
}
@Override
public Void visitCapturedType(CapturedType t, Set<Type> seen) {
if (seen.add(t)) {
visit(t.getUpperBound(), seen);
visit(t.getLowerBound(), seen);
}
return null;
}
}
class TypeProjection extends StructuralTypeMapping<Boolean> {
List<Type> vars;
Set<Type> seen = new HashSet<>();
public TypeProjection(List<Type> vars) {
this.vars = vars;
}
@Override
public Type visitClassType(ClassType t, Boolean upward) {
if (upward && !t.isCompound() && t.tsym.name.isEmpty()) {
//lift anonymous class type to first supertype (class or interface)
return types.directSupertypes(t).last();
} else if (t.isCompound()) {
List<Type> components = types.directSupertypes(t);
List<Type> components1 = components.map(c -> c.map(this, upward));
if (components == components1) return t;
else return types.makeIntersectionType(components1);
} else {
Type outer = t.getEnclosingType();
Type outer1 = visit(outer, upward);
List<Type> typarams = t.getTypeArguments();
List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, upward));
if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
//not defined
return syms.botType;
}
if (outer1 == outer && typarams1 == typarams) return t;
else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
@Override
protected boolean needsStripping() {
return true;
}
};
}
}
protected Type makeWildcard(Type upper, Type lower) {
BoundKind bk;
Type bound;
if (upper.hasTag(BOT)) {
upper = syms.objectType;
}
boolean isUpperObject = types.isSameType(upper, syms.objectType);
if (!lower.hasTag(BOT) && isUpperObject) {
bound = lower;
bk = SUPER;
} else {
bound = upper;
bk = isUpperObject ? UNBOUND : EXTENDS;
}
return new WildcardType(bound, bk, syms.boundClass);
}
@Override
public Type visitTypeVar(TypeVar t, Boolean upward) {
if (vars.contains(t)) {
try {
if (seen.add(t)) {
return (upward ?
t.getUpperBound() :
(t.getLowerBound() == null) ?
syms.botType :
t.getLowerBound())
.map(this, upward);
} else {
//cycle
return syms.objectType;
}
} finally {
seen.remove(t);
}
} else {
return t;
}
}
@Override
public Type visitWildcardType(WildcardType wt, Boolean upward) {
if (upward) {
return wt.isExtendsBound() ?
wt.type.map(this, upward) :
syms.objectType;
} else {
return wt.isSuperBound() ?
wt.type.map(this, upward) :
syms.botType;
}
}
private Type mapTypeArgument(Type t, boolean upward) {
if (!t.containsAny(vars)) {
return t;
} else if (!t.hasTag(WILDCARD) && !upward) {
//not defined
return syms.botType;
} else {
Type upper = t.map(this, upward);
Type lower = t.map(this, !upward);
return makeWildcard(upper, lower);
}
}
}
}

View file

@ -74,16 +74,15 @@ abstract class Wrap implements GeneralWrap {
* @param rdecl Type name and name * @param rdecl Type name and name
* @return * @return
*/ */
public static Wrap varWrap(String source, Range rtype, String brackets, Range rname, Range rinit) { public static Wrap varWrap(String source, Wrap wtype, String brackets,
Range rname, Wrap winit, Wrap anonDeclareWrap) {
RangeWrap wname = new RangeWrap(source, rname); RangeWrap wname = new RangeWrap(source, rname);
RangeWrap wtype = new RangeWrap(source, rtype);
Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname); Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname);
Wrap wmeth; Wrap wmeth;
if (rinit == null) { if (winit == null) {
wmeth = new CompoundWrap(new NoWrap(" "), " return null;\n"); wmeth = new CompoundWrap(new NoWrap(" "), " return null;\n");
} else { } else {
RangeWrap winit = new RangeWrap(source, rinit);
// int x = y // int x = y
// int x_ = y; return x = x_; // int x_ = y; return x = x_;
// decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;" // decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;"
@ -93,7 +92,8 @@ abstract class Wrap implements GeneralWrap {
); );
} }
Wrap wInitMeth = new DoitMethodWrap(wmeth); Wrap wInitMeth = new DoitMethodWrap(wmeth);
return new CompoundWrap(wVarDecl, wInitMeth); return anonDeclareWrap != null ? new CompoundWrap(wVarDecl, wInitMeth, anonDeclareWrap)
: new CompoundWrap(wVarDecl, wInitMeth);
} }
public static Wrap tempVarWrap(String source, String typename, String name) { public static Wrap tempVarWrap(String source, String typename, String name) {
@ -112,6 +112,14 @@ abstract class Wrap implements GeneralWrap {
return new NoWrap(source); return new NoWrap(source);
} }
public static Wrap identityWrap(String source) {
return new NoWrap(source);
}
public static Wrap rangeWrap(String source, Range range) {
return new RangeWrap(source, range);
}
public static Wrap classMemberWrap(String source) { public static Wrap classMemberWrap(String source) {
Wrap w = new NoWrap(source); Wrap w = new NoWrap(source);
return new CompoundWrap(" public static\n ", w); return new CompoundWrap(" public static\n ", w);

View file

@ -273,7 +273,8 @@ abstract class CompilationPhase {
private static final class LocalVariableTypeCalculationPhase extends CompilationPhase { private static final class LocalVariableTypeCalculationPhase extends CompilationPhase {
@Override @Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler)); final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler,
compiler.getReturnType()));
final ScriptEnvironment senv = compiler.getScriptEnvironment(); final ScriptEnvironment senv = compiler.getScriptEnvironment();
final PrintWriter err = senv.getErr(); final PrintWriter err = senv.getErr();

View file

@ -619,6 +619,10 @@ public final class Compiler implements Loggable {
return types == null ? null : types.get(fn, pos); return types == null ? null : types.get(fn, pos);
} }
Type getReturnType() {
return types == null || !isOnDemandCompilation() ? Type.UNKNOWN : types.getReturnType();
}
/** /**
* Do a compilation job * Do a compilation job
* *

View file

@ -405,10 +405,15 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
// variables). // variables).
private final Deque<Label> catchLabels = new ArrayDeque<>(); private final Deque<Label> catchLabels = new ArrayDeque<>();
LocalVariableTypesCalculator(final Compiler compiler) { private LocalVariableTypesCalculator(final Compiler compiler) {
this.compiler = compiler; this.compiler = compiler;
} }
LocalVariableTypesCalculator(final Compiler compiler, final Type returnType) {
this(compiler);
this.returnType = returnType;
}
private JumpTarget createJumpTarget(final Label label) { private JumpTarget createJumpTarget(final Label label) {
assert !jumpTargets.containsKey(label); assert !jumpTargets.containsKey(label);
final JumpTarget jumpTarget = new JumpTarget(); final JumpTarget jumpTarget = new JumpTarget();

View file

@ -117,6 +117,15 @@ public final class TypeMap {
return null; return null;
} }
/**
* Get the return type required for the call site we're compiling for. This only determines
* whether object return type is required or not.
* @return Type.OBJECT for call sites with object return types, Type.UNKNOWN for everything else
*/
Type getReturnType() {
return returnType.isObject() ? Type.OBJECT : Type.UNKNOWN;
}
@Override @Override
public String toString() { public String toString() {
return toString(""); return toString("");

Some files were not shown because too many files have changed in this diff Show more