Skip to content
Permalink
Browse files
8262891: Compiler implementation for Pattern Matching for switch (Pre…
…view)

Co-authored-by: Brian Goetz <briangoetz@openjdk.org>
Co-authored-by: Mandy Chung <mchung@openjdk.org>
Co-authored-by: Jan Lahoda <jlahoda@openjdk.org>
Reviewed-by: mcimadamore, forax, godin, psandoz, mchung
  • Loading branch information
3 people committed Jun 7, 2021
1 parent 3e48244 commit 908aca29ca60f5f251df8c6a31b2543929be12fc
Showing with 4,795 additions and 292 deletions.
  1. +2 −1 make/CompileInterimLangtools.gmk
  2. +170 −0 src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java
  3. +43 −0 src/java.base/share/classes/jdk/internal/javac/NoPreview.java
  4. +1 −0 src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java
  5. +36 −0 src/jdk.compiler/share/classes/com/sun/source/tree/CaseLabelTree.java
  6. +12 −0 src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java
  7. +35 −0 src/jdk.compiler/share/classes/com/sun/source/tree/DefaultCaseLabelTree.java
  8. +4 −1 src/jdk.compiler/share/classes/com/sun/source/tree/ExpressionTree.java
  9. +50 −0 src/jdk.compiler/share/classes/com/sun/source/tree/GuardedPatternTree.java
  10. +49 −0 src/jdk.compiler/share/classes/com/sun/source/tree/ParenthesizedPatternTree.java
  11. +1 −1 src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java
  12. +26 −0 src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java
  13. +32 −0 src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java
  14. +43 −0 src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java
  15. +44 −0 src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java
  16. +21 −1 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java
  17. +2 −0 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java
  18. +2 −0 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java
  19. +150 −28 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
  20. +94 −55 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
  21. +156 −38 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
  22. +39 −7 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java
  23. +476 −48 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java
  24. +14 −5 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java
  25. +7 −1 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java
  26. +6 −1 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java
  27. +14 −6 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
  28. +103 −27 src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
  29. +31 −3 src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
  30. +165 −10 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java
  31. +38 −3 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java
  32. +23 −2 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java
  33. +38 −1 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java
  34. +20 −2 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java
  35. +16 −1 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java
  36. +19 −1 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java
  37. +11 −5 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java
  38. +133 −0 test/jdk/java/lang/runtime/SwitchBootstrapsTest.java
  39. +12 −5 test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java
  40. +88 −0 test/langtools/tools/javac/classfiles/attributes/LineNumberTable/RuleSwitchBreaks.java
  41. +11 −0 test/langtools/tools/javac/classfiles/attributes/LineNumberTable/TestCase.java
  42. +11 −0 test/langtools/tools/javac/diags/examples/CantRefNonEffectivelyFinalVar.java
  43. +8 −7 test/langtools/tools/javac/diags/examples/{SwitchNullNotAllowed.java → CaseNull.java}
  44. +35 −0 test/langtools/tools/javac/diags/examples/ConstantLabelNotCompatible.java
  45. +36 −0 test/langtools/tools/javac/diags/examples/DuplicateTotalPattern.java
  46. +36 −0 test/langtools/tools/javac/diags/examples/FlowsThroughFromPattern.java
  47. +36 −0 test/langtools/tools/javac/diags/examples/FlowsThroughToPattern.java
  48. +35 −0 test/langtools/tools/javac/diags/examples/NotExhaustiveStatement.java
  49. +36 −0 test/langtools/tools/javac/diags/examples/PatternDominated.java
  50. +35 −0 test/langtools/tools/javac/diags/examples/PatternSwitch.java
  51. +36 −0 test/langtools/tools/javac/diags/examples/TotalPatternAndDefault.java
  52. +1 −1 test/langtools/tools/javac/lib/DPrinter.java
  53. +37 −0 test/langtools/tools/javac/patterns/CaseDefault.java
  54. +2 −0 test/langtools/tools/javac/patterns/CaseDefault.out
  55. +88 −0 test/langtools/tools/javac/patterns/DisambiguateParenthesizedPattern.java
  56. +89 −0 test/langtools/tools/javac/patterns/Domination.java
  57. +9 −0 test/langtools/tools/javac/patterns/Domination.out
  58. +643 −0 test/langtools/tools/javac/patterns/Exhaustiveness.java
  59. +99 −0 test/langtools/tools/javac/patterns/Guards.java
  60. +42 −0 test/langtools/tools/javac/patterns/GuardsErrors.java
  61. +4 −0 test/langtools/tools/javac/patterns/GuardsErrors.out
  62. +168 −0 test/langtools/tools/javac/patterns/NullSwitch.java
  63. +51 −0 test/langtools/tools/javac/patterns/Parenthesized.java
  64. +131 −0 test/langtools/tools/javac/patterns/SealedTypeChanges.java
  65. +26 −0 test/langtools/tools/javac/patterns/SealedTypeChanges2.java
  66. +31 −0 test/langtools/tools/javac/patterns/SimpleAndGuardPattern.java
  67. +193 −0 test/langtools/tools/javac/patterns/SwitchErrors.java
  68. +44 −0 test/langtools/tools/javac/patterns/SwitchErrors.out
  69. +344 −0 test/langtools/tools/javac/patterns/Switches.java
  70. +70 −0 test/langtools/tools/javac/stackmap/OrdinarySwitchStackMapTest.java
  71. +6 −5 test/langtools/tools/javac/switchextra/SwitchNoExtraTypes.out
  72. +4 −2 test/langtools/tools/javac/switchextra/SwitchObject.out
  73. +139 −0 test/langtools/tools/javac/switchnull/SwitchNull.java
  74. +2 −0 test/langtools/tools/javac/switchnull/SwitchNullDisabled-preview.out
  75. +4 −2 test/langtools/tools/javac/switchnull/SwitchNullDisabled.java
  76. +1 −1 test/langtools/tools/javac/switchnull/SwitchNullDisabled.out
  77. +25 −21 test/langtools/tools/javac/tree/SourceTreeScannerTest.java
  78. +1 −0 test/langtools/tools/jdeps/listdeps/ListModuleDeps.java
@@ -49,7 +49,8 @@ TARGETS += $(patsubst %, $(BUILDTOOLS_OUTPUTDIR)/gensrc/%/module-info.java, \
$(INTERIM_LANGTOOLS_MODULES))

$(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \
FILES := $(TOPDIR)/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java, \
FILES := $(TOPDIR)/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java \
$(TOPDIR)/src/java.base/share/classes/jdk/internal/javac/NoPreview.java, \
DEST := $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/javac/, \
))

@@ -0,0 +1,170 @@
/*
* Copyright (c) 2017, 2021, 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 java.lang.runtime;

import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Stream;

import jdk.internal.javac.PreviewFeature;

import static java.util.Objects.requireNonNull;

/**
* Bootstrap methods for linking {@code invokedynamic} call sites that implement
* the selection functionality of the {@code switch} statement. The bootstraps
* take additional static arguments corresponding to the {@code case} labels
* of the {@code switch}, implicitly numbered sequentially from {@code [0..N)}.
*
* @since 17
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING)
public class SwitchBootstraps {

private SwitchBootstraps() {}

private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();

private static final MethodHandle DO_SWITCH;

static {
try {
DO_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doSwitch",
MethodType.methodType(int.class, Object.class, int.class, Object[].class));
}
catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}

/**
* Bootstrap method for linking an {@code invokedynamic} call site that
* implements a {@code switch} on a target of a reference type. The static
* arguments are an array of case labels which must be non-null and of type
* {@code String} or {@code Integer} or {@code Class}.
* <p>
* The type of the returned {@code CallSite}'s method handle will have
* a return type of {@code int}. It has two parameters: the first argument
* will be an {@code Object} instance ({@code target}) and the second
* will be {@code int} ({@code restart}).
* <p>
* If the {@code target} is {@code null}, then the method of the call site
* returns {@literal -1}.
* <p>
* If the {@code target} is not {@code null}, then the method of the call site
* returns the index of the first element in the {@code labels} array starting from
* the {@code restart} index matching one of the following conditions:
* <ul>
* <li>the element is of type {@code Class} that is assignable
* from the target's class; or</li>
* <li>the element is of type {@code String} or {@code Integer} and
* equals to the target.</li>
* </ul>
* <p>
* If no element in the {@code labels} array matches the target, then
* the method of the call site return the length of the {@code labels} array.
*
* @param lookup Represents a lookup context with the accessibility
* privileges of the caller. When used with {@code invokedynamic},
* this is stacked automatically by the VM.
* @param invocationName unused
* @param invocationType The invocation type of the {@code CallSite} with two parameters,
* a reference type, an {@code int}, and {@code int} as a return type.
* @param labels case labels - {@code String} and {@code Integer} constants
* and {@code Class} instances, in any combination
* @return a {@code CallSite} returning the first matching element as described above
*
* @throws NullPointerException if any argument is {@code null}
* @throws IllegalArgumentException if any element in the labels array is null, if the
* invocation type is not not a method type of first parameter of a reference type,
* second parameter of type {@code int} and with {@code int} as its return type,
* or if {@code labels} contains an element that is not of type {@code String},
* {@code Integer} or {@code Class}.
* @throws Throwable if there is any error linking the call site
* @jvms 4.4.6 The CONSTANT_NameAndType_info Structure
* @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures
*/
public static CallSite typeSwitch(MethodHandles.Lookup lookup,
String invocationName,
MethodType invocationType,
Object... labels) throws Throwable {
if (invocationType.parameterCount() != 2
|| (!invocationType.returnType().equals(int.class))
|| invocationType.parameterType(0).isPrimitive()
|| !invocationType.parameterType(1).equals(int.class))
throw new IllegalArgumentException("Illegal invocation type " + invocationType);
requireNonNull(labels);

labels = labels.clone();
Stream.of(labels).forEach(SwitchBootstraps::verifyLabel);

MethodHandle target = MethodHandles.insertArguments(DO_SWITCH, 2, (Object) labels);
return new ConstantCallSite(target);
}

private static void verifyLabel(Object label) {
if (label == null) {
throw new IllegalArgumentException("null label found");
}
Class<?> labelClass = label.getClass();
if (labelClass != Class.class &&
labelClass != String.class &&
labelClass != Integer.class) {
throw new IllegalArgumentException("label with illegal type found: " + label.getClass());
}
}

private static int doSwitch(Object target, int startIndex, Object[] labels) {
if (target == null)
return -1;

// Dumbest possible strategy
Class<?> targetClass = target.getClass();
for (int i = startIndex; i < labels.length; i++) {
Object label = labels[i];
if (label instanceof Class<?> c) {
if (c.isAssignableFrom(targetClass))
return i;
} else if (label instanceof Integer constant) {
if (target instanceof Number input && constant.intValue() == input.intValue()) {
return i;
} else if (target instanceof Character input && constant.intValue() == input.charValue()) {
return i;
}
} else if (label.equals(target)) {
return i;
}
}

return labels.length;
}

}
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2021, 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.internal.javac;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* The element annotated with this annotation should not be marked as a preview element.
*/
@Target({ElementType.METHOD,
ElementType.CONSTRUCTOR,
ElementType.FIELD,
ElementType.PACKAGE,
ElementType.MODULE,
ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface NoPreview {
}
@@ -58,6 +58,7 @@
* This one can only be removed after JDK 17
*/
SEALED_CLASSES,
SWITCH_PATTERN_MATCHING,
/**
* A key for testing.
*/
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2021, 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 com.sun.source.tree;

import jdk.internal.javac.PreviewFeature;

/**
* A marker interface for {@code Tree}s that may be used as {@link CaseTree} labels.
*
* @since 17
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
public interface CaseLabelTree extends Tree {}
@@ -27,6 +27,8 @@

import java.util.List;

import jdk.internal.javac.PreviewFeature;

/**
* A tree node for a {@code case} in a {@code switch} statement or expression.
*
@@ -65,6 +67,16 @@
*/
List<? extends ExpressionTree> getExpressions();

/**
* Returns the labels for this case.
* For {@code default} case return a list with a single element, {@link DefaultCaseLabelTree}.
*
* @return labels for this case
* @since 17
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
List<? extends CaseLabelTree> getLabels();

/**
* For case with kind {@linkplain CaseKind#STATEMENT},
* returns the statements labeled by the case.
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2021, 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 com.sun.source.tree;

import jdk.internal.javac.PreviewFeature;

/**
* A case label that marks {@code default} in {@code case null, default}.
*
* @since 17
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
public interface DefaultCaseLabelTree extends CaseLabelTree {}
@@ -25,6 +25,8 @@

package com.sun.source.tree;

import jdk.internal.javac.NoPreview;

/**
* A tree node used as the base class for the different types of
* expressions.
@@ -35,4 +37,5 @@
* @author Jonathan Gibbons
* @since 1.6
*/
public interface ExpressionTree extends Tree {}
@NoPreview
public interface ExpressionTree extends Tree, CaseLabelTree {}
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2017, 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 com.sun.source.tree;

import jdk.internal.javac.PreviewFeature;

/**
* A guard pattern tree.
*
* @since 17
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
public interface GuardedPatternTree extends PatternTree {

/**
* The guarded pattern expression.
* @return the guarded pattern
*/
public PatternTree getPattern();

/**
* The guard expression.
* @return the guard expression
*/
public ExpressionTree getExpression();

}

1 comment on commit 908aca2

@openjdk-notifier

This comment has been minimized.

Copy link

@openjdk-notifier openjdk-notifier bot commented on 908aca2 Jun 7, 2021

Please sign in to comment.