# HG changeset patch
# User jlahoda
# Date 1574841601 -3600
# Node ID 7799a51dbe30736ca12e007af5ba96a7bb610010
# Parent 88502b1cf76fd9aa09bd66648915b612f9fc0f0c
8231826: Implement javac changes for pattern matching for instanceof
Reviewed-by: mcimadamore
Contributed-by: brian.goetz@oracle.com, gavin.bierman@oracle.com, maurizio.cimadamore@oracle.com, srikanth.adayapalam@oracle.com, vicente.romero@oracle.com, jan.lahoda@oracle.com
diff -r 88502b1cf76f -r 7799a51dbe30 src/java.base/share/classes/jdk/internal/PreviewFeature.java
--- a/src/java.base/share/classes/jdk/internal/PreviewFeature.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/java.base/share/classes/jdk/internal/PreviewFeature.java Wed Nov 27 09:00:01 2019 +0100
@@ -54,6 +54,8 @@
public boolean essentialAPI() default false;
public enum Feature {
- TEXT_BLOCKS;
+ PATTERN_MATCHING_IN_INSTANCEOF,
+ TEXT_BLOCKS,
+ ;
}
}
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/source/tree/BindingPatternTree.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/BindingPatternTree.java Wed Nov 27 09:00:01 2019 +0100
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017, 2019, 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 javax.lang.model.element.Name;
+
+/**
+ * {@preview Associated with pattern matching for instanceof, a preview feature of
+ * the Java language.
+ *
+ * This interface is associated with pattern matching for instanceof, a preview
+ * feature of the Java language. Preview features
+ * may be removed in a future release, or upgraded to permanent
+ * features of the Java language.}
+ *
+ * A binding pattern tree
+ *
+ * @since 14
+ */
+public interface BindingPatternTree extends PatternTree {
+
+ /**
+ * Returns the type of the bind variable.
+ * @return the type
+ */
+ Tree getType();
+
+ /**
+ * A binding variable name.
+ * @return the name of the binding variable
+ */
+ Name getBinding();
+
+}
+
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java Wed Nov 27 09:00:01 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, 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
@@ -51,4 +51,33 @@
* @return the type
*/
Tree getType();
+
+ /**
+ * {@preview Associated with pattern matching for instanceof, a preview feature of
+ * the Java language.
+ *
+ * This method is associated with pattern matching for instanceof, a preview
+ * feature of the Java language. Preview features
+ * may be removed in a future release, or upgraded to permanent
+ * features of the Java language.}
+ *
+ * Returns the tested pattern, or null if this instanceof does not use
+ * a pattern.
+ *
+ *
For instanceof with a pattern, i.e. in the following form:
+ *
+ * expression instanceof typevariable name
+ *
+ * returns the pattern.
+ *
+ *
For instanceof without a pattern, i.e. in the following form:
+ *
+ * expression instanceof type
+ *
+ * returns null.
+ *
+ * @return the tested pattern, or null if this instanceof does not use a pattern.
+ * @since 14
+ */
+ PatternTree getPattern();
}
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java Wed Nov 27 09:00:01 2019 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017, 2019, 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;
+
+/**
+ * {@preview Associated with pattern matching for instanceof, a preview feature of
+ * the Java language.
+ *
+ * This interface is associated with pattern matching for instanceof, a preview
+ * feature of the Java language. Preview features
+ * may be removed in a future release, or upgraded to permanent
+ * features of the Java language.}
+ *
+ * A tree node used as the base class for the different kinds of
+ * statements.
+ *
+ * @since 14
+ */
+public interface PatternTree extends Tree {}
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java Wed Nov 27 09:00:01 2019 +0100
@@ -220,6 +220,21 @@
PARENTHESIZED(ParenthesizedTree.class),
/**
+ * {@preview Associated with pattern matching for instanceof, a preview feature of
+ * the Java language.
+ *
+ * This enum constant is associated with pattern matching for instanceof, a preview
+ * feature of the Java language. Preview features
+ * may be removed in a future release, or upgraded to permanent
+ * features of the Java language.}
+ *
+ * Used for instances of {@link BindingPatternTree}.
+ *
+ * @since 14
+ */
+ BINDING_PATTERN(BindingPatternTree.class),
+
+ /**
* Used for instances of {@link PrimitiveTypeTree}.
*/
PRIMITIVE_TYPE(PrimitiveTypeTree.class),
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java Wed Nov 27 09:00:01 2019 +0100
@@ -258,6 +258,23 @@
R visitLiteral(LiteralTree node, P p);
/**
+ * {@preview Associated with pattern matching for instanceof, a preview feature of
+ * the Java language.
+ *
+ * This method is associated with pattern matching for instanceof, a preview
+ * feature of the Java language. Preview features
+ * may be removed in a future release, or upgraded to permanent
+ * features of the Java language.}
+ *
+ * Visits an BindingPattern node.
+ * @param node the node being visited
+ * @param p a parameter value
+ * @return a result value
+ * @since 14
+ */
+ R visitBindingPattern(BindingPatternTree node, P p);
+
+ /**
* Visits a MethodTree node.
* @param node the node being visited
* @param p a parameter value
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java
--- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java Wed Nov 27 09:00:01 2019 +0100
@@ -557,6 +557,19 @@
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of {@code defaultAction}
+ * @since 14
+ */
+ @Override
+ public R visitBindingPattern(BindingPatternTree node, P p) {
+ return defaultAction(node, p);
+ }
+
+ /**
+ * {@inheritDoc} This implementation calls {@code defaultAction}.
+ *
+ * @param node {@inheritDoc}
+ * @param p {@inheritDoc}
+ * @return the result of {@code defaultAction}
*/
@Override
public R visitArrayAccess(ArrayAccessTree node, P p) {
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java Wed Nov 27 09:00:01 2019 +0100
@@ -667,7 +667,11 @@
@Override
public R visitInstanceOf(InstanceOfTree node, P p) {
R r = scan(node.getExpression(), p);
- r = scanAndReduce(node.getType(), p, r);
+ if (node.getPattern() != null) {
+ r = scanAndReduce(node.getPattern(), p, r);
+ } else {
+ r = scanAndReduce(node.getType(), p, r);
+ }
return r;
}
@@ -677,6 +681,19 @@
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of scanning
+ * @since 14
+ */
+ @Override
+ public R visitBindingPattern(BindingPatternTree node, P p) {
+ return scan(node.getType(), p);
+ }
+
+ /**
+ * {@inheritDoc} This implementation scans the children in left to right order.
+ *
+ * @param node {@inheritDoc}
+ * @param p {@inheritDoc}
+ * @return the result of scanning
*/
@Override
public R visitArrayAccess(ArrayAccessTree node, P p) {
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java Wed Nov 27 09:00:01 2019 +0100
@@ -334,6 +334,16 @@
*/
public static final long PREVIEW_ESSENTIAL_API = 1L<<58; //any Symbol kind
+ /**
+ * Flag to indicate the given variable is a match binding variable.
+ */
+ public static final long MATCH_BINDING = 1L<<59;
+
+ /**
+ * A flag to indicate a match binding variable whose scope extends after the current statement.
+ */
+ public static final long MATCH_BINDING_TO_OUTER = 1L<<60;
+
/** Modifier masks.
*/
public static final int
@@ -453,7 +463,9 @@
ANONCONSTR_BASED(Flags.ANONCONSTR_BASED),
NAME_FILLED(Flags.NAME_FILLED),
PREVIEW_API(Flags.PREVIEW_API),
- PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API);
+ PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API),
+ MATCH_BINDING(Flags.MATCH_BINDING),
+ MATCH_BINDING_TO_OUTER(Flags.MATCH_BINDING_TO_OUTER);
Flag(long flag) {
this.value = flag;
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java Wed Nov 27 09:00:01 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -165,7 +165,9 @@
* @return true, if given feature is a preview feature.
*/
public boolean isPreview(Feature feature) {
- if (feature == Feature.TEXT_BLOCKS)
+ if (feature == Feature.PATTERN_MATCHING_IN_INSTANCEOF ||
+ feature == Feature.REIFIABLE_TYPES_INSTANCEOF ||
+ feature == Feature.TEXT_BLOCKS)
return true;
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
//When real preview features will be added, this method can be implemented to return 'true'
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java Wed Nov 27 09:00:01 2019 +0100
@@ -198,7 +198,10 @@
SWITCH_MULTIPLE_CASE_LABELS(JDK14, Fragments.FeatureMultipleCaseLabels, DiagKind.PLURAL),
SWITCH_RULE(JDK14, Fragments.FeatureSwitchRules, DiagKind.PLURAL),
SWITCH_EXPRESSION(JDK14, Fragments.FeatureSwitchExpressions, DiagKind.PLURAL),
- TEXT_BLOCKS(JDK14, Fragments.FeatureTextBlocks, DiagKind.PLURAL);
+ TEXT_BLOCKS(JDK14, Fragments.FeatureTextBlocks, DiagKind.PLURAL),
+ PATTERN_MATCHING_IN_INSTANCEOF(JDK14, Fragments.FeaturePatternMatchingInstanceof, DiagKind.NORMAL),
+ REIFIABLE_TYPES_INSTANCEOF(JDK14, Fragments.FeatureReifiableTypesInstanceof, DiagKind.PLURAL),
+ ;
enum DiagKind {
NORMAL,
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Wed Nov 27 09:00:01 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, 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
@@ -390,22 +390,26 @@
sym.getKind() == ElementKind.LOCAL_VARIABLE ||
sym.getKind() == ElementKind.RESOURCE_VARIABLE ||
sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
- // Make sure all type annotations from the symbol are also
- // on the owner. If the owner is an initializer block, propagate
- // to the type.
- final long ownerFlags = sym.owner.flags();
- if ((ownerFlags & Flags.BLOCK) != 0) {
- // Store init and clinit type annotations with the ClassSymbol
- // to allow output in Gen.normalizeDefs.
- ClassSymbol cs = (ClassSymbol) sym.owner.owner;
- if ((ownerFlags & Flags.STATIC) != 0) {
- cs.appendClassInitTypeAttributes(typeAnnotations);
- } else {
- cs.appendInitTypeAttributes(typeAnnotations);
- }
+ appendTypeAnnotationsToOwner(sym, typeAnnotations);
+ }
+ }
+
+ private void appendTypeAnnotationsToOwner(Symbol sym, List typeAnnotations) {
+ // Make sure all type annotations from the symbol are also
+ // on the owner. If the owner is an initializer block, propagate
+ // to the type.
+ final long ownerFlags = sym.owner.flags();
+ if ((ownerFlags & Flags.BLOCK) != 0) {
+ // Store init and clinit type annotations with the ClassSymbol
+ // to allow output in Gen.normalizeDefs.
+ ClassSymbol cs = (ClassSymbol) sym.owner.owner;
+ if ((ownerFlags & Flags.STATIC) != 0) {
+ cs.appendClassInitTypeAttributes(typeAnnotations);
} else {
- sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes());
+ cs.appendInitTypeAttributes(typeAnnotations);
}
+ } else {
+ sym.owner.appendUniqueTypeAttributes(typeAnnotations);
}
}
@@ -943,10 +947,11 @@
" within frame " + frame);
}
+ case BINDING_PATTERN:
case VARIABLE:
- VarSymbol v = ((JCVariableDecl)frame).sym;
+ VarSymbol v = frame.hasTag(Tag.BINDINGPATTERN) ? ((JCBindingPattern) frame).symbol : ((JCVariableDecl) frame).sym;
if (v.getKind() != ElementKind.FIELD) {
- v.owner.appendUniqueTypeAttributes(v.getRawTypeAttributes());
+ appendTypeAnnotationsToOwner(v, v.getRawTypeAttributes());
}
switch (v.getKind()) {
case LOCAL_VARIABLE:
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Wed Nov 27 09:00:01 2019 +0100
@@ -1122,6 +1122,13 @@
}
@Override
+ public void visitBindingPattern(JCTree.JCBindingPattern tree) {
+ //type binding pattern's type will be annotated separatelly, avoid
+ //adding its annotations into the owning method here (would clash
+ //with repeatable annotations).
+ }
+
+ @Override
public void visitClassDef(JCClassDecl tree) {
// We can only hit a classdef if it is declared within
// a method. Ignore it - the class will be visited
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Wed Nov 27 09:00:01 2019 +0100
@@ -49,6 +49,7 @@
import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
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.DiamondInvalidArg;
@@ -110,6 +111,7 @@
final Enter enter;
final Target target;
final Types types;
+ final Preview preview;
final JCDiagnostic.Factory diags;
final TypeAnnotations typeAnnotations;
final DeferredLintHandler deferredLintHandler;
@@ -117,6 +119,7 @@
final Dependencies dependencies;
final Annotate annotate;
final ArgumentAttr argumentAttr;
+ final MatchBindingsComputer matchBindingsComputer;
public static Attr instance(Context context) {
Attr instance = context.get(attrKey);
@@ -145,6 +148,7 @@
cfolder = ConstFold.instance(context);
target = Target.instance(context);
types = Types.instance(context);
+ preview = Preview.instance(context);
diags = JCDiagnostic.Factory.instance(context);
annotate = Annotate.instance(context);
typeAnnotations = TypeAnnotations.instance(context);
@@ -152,6 +156,7 @@
typeEnvs = TypeEnvs.instance(context);
dependencies = Dependencies.instance(context);
argumentAttr = ArgumentAttr.instance(context);
+ matchBindingsComputer = MatchBindingsComputer.instance(context);
Options options = Options.instance(context);
@@ -161,6 +166,9 @@
allowLambda = Feature.LAMBDA.allowedInSource(source);
allowDefaultMethods = Feature.DEFAULT_METHODS.allowedInSource(source);
allowStaticInterfaceMethods = Feature.STATIC_INTERFACE_METHODS.allowedInSource(source);
+ allowReifiableTypesInInstanceof =
+ Feature.REIFIABLE_TYPES_INSTANCEOF.allowedInSource(source) &&
+ (!preview.isPreview(Feature.REIFIABLE_TYPES_INSTANCEOF) || preview.isEnabled());
sourceName = source.name;
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
@@ -193,6 +201,10 @@
*/
boolean allowStaticInterfaceMethods;
+ /** Switch: reifiable types in instanceof enabled?
+ */
+ boolean allowReifiableTypesInInstanceof;
+
/**
* Switch: warn about use of variable before declaration?
* RFE: 6425594
@@ -292,6 +304,8 @@
isAssignableAsBlankFinal(v, env)))) {
if (v.isResourceVariable()) { //TWR resource
log.error(pos, Errors.TryResourceMayNotBeAssigned(v));
+ } else if ((v.flags() & MATCH_BINDING) != 0) {
+ log.error(pos, Errors.PatternBindingMayNotBeAssigned(v));
} else {
log.error(pos, Errors.CantAssignValToFinalVar(v));
}
@@ -1298,29 +1312,73 @@
public void visitDoLoop(JCDoWhileLoop tree) {
attribStat(tree.body, env.dup(tree));
attribExpr(tree.cond, env, syms.booleanType);
+ if (!breaksOutOf(tree, tree.body)) {
+ //include condition's body when false after the while, if cannot get out of the loop
+ List bindings = matchBindingsComputer.getMatchBindings(tree.cond, false);
+
+ bindings.forEach(env.info.scope::enter);
+ bindings.forEach(BindingSymbol::preserveBinding);
+ }
result = null;
}
public void visitWhileLoop(JCWhileLoop tree) {
attribExpr(tree.cond, env, syms.booleanType);
- attribStat(tree.body, env.dup(tree));
+ // include condition's bindings when true in the body:
+ Env whileEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, true));
+ try {
+ attribStat(tree.body, whileEnv.dup(tree));
+ } finally {
+ whileEnv.info.scope.leave();
+ }
+ if (!breaksOutOf(tree, tree.body)) {
+ //include condition's bindings when false after the while, if cannot get out of the loop
+ List bindings =
+ matchBindingsComputer.getMatchBindings(tree.cond, false);
+
+ bindings.forEach(env.info.scope::enter);
+ bindings.forEach(BindingSymbol::preserveBinding);
+ }
result = null;
}
+ private boolean breaksOutOf(JCTree loop, JCTree body) {
+ preFlow(body);
+ return flow.breaksOutOf(env, loop, body, make);
+ }
+
public void visitForLoop(JCForLoop tree) {
Env loopEnv =
env.dup(env.tree, env.info.dup(env.info.scope.dup()));
try {
attribStats(tree.init, loopEnv);
- if (tree.cond != null) attribExpr(tree.cond, loopEnv, syms.booleanType);
- loopEnv.tree = tree; // before, we were not in loop!
- attribStats(tree.step, loopEnv);
- attribStat(tree.body, loopEnv);
+ List matchBindings = List.nil();
+ if (tree.cond != null) {
+ attribExpr(tree.cond, loopEnv, syms.booleanType);
+ // include condition's bindings when true in the body and step:
+ matchBindings = matchBindingsComputer.getMatchBindings(tree.cond, true);
+ }
+ Env bodyEnv = bindingEnv(loopEnv, matchBindings);
+ try {
+ bodyEnv.tree = tree; // before, we were not in loop!
+ attribStats(tree.step, bodyEnv);
+ attribStat(tree.body, bodyEnv);
+ } finally {
+ bodyEnv.info.scope.leave();
+ }
result = null;
}
finally {
loopEnv.info.scope.leave();
}
+ if (!breaksOutOf(tree, tree.body)) {
+ //include condition's body when false after the while, if cannot get out of the loop
+ List bindings =
+ matchBindingsComputer.getMatchBindings(tree.cond, false);
+
+ bindings.forEach(env.info.scope::enter);
+ bindings.forEach(BindingSymbol::preserveBinding);
+ }
}
public void visitForeachLoop(JCEnhancedForLoop tree) {
@@ -1673,8 +1731,26 @@
unknownExprInfo :
resultInfo.dup(conditionalContext(resultInfo.checkContext));
- Type truetype = attribTree(tree.truepart, env, condInfo);
- Type falsetype = attribTree(tree.falsepart, env, condInfo);
+
+ // x ? y : z
+ // include x's bindings when true in y
+ // include x's bindings when false in z
+
+ Type truetype;
+ Env trueEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, true));
+ try {
+ truetype = attribTree(tree.truepart, trueEnv, condInfo);
+ } finally {
+ trueEnv.info.scope.leave();
+ }
+
+ Type falsetype;
+ Env falseEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, false));
+ try {
+ falsetype = attribTree(tree.falsepart, falseEnv, condInfo);
+ } finally {
+ falseEnv.info.scope.leave();
+ }
Type owntype = (tree.polyKind == PolyKind.STANDALONE) ?
condType(List.of(tree.truepart.pos(), tree.falsepart.pos()),
@@ -1829,15 +1905,77 @@
BOOLEAN,
};
+ Env bindingEnv(Env env, List bindings) {
+ Env env1 = env.dup(env.tree, env.info.dup(env.info.scope.dup()));
+ bindings.forEach(env1.info.scope::enter);
+ return env1;
+ }
+
public void visitIf(JCIf tree) {
attribExpr(tree.cond, env, syms.booleanType);
- attribStat(tree.thenpart, env);
- if (tree.elsepart != null)
- attribStat(tree.elsepart, env);
+
+ // if (x) { y } [ else z ]
+ // include x's bindings when true in y
+ // include x's bindings when false in z
+
+ List thenBindings = matchBindingsComputer.getMatchBindings(tree.cond, true);
+ Env thenEnv = bindingEnv(env, thenBindings);
+
+ try {
+ attribStat(tree.thenpart, thenEnv);
+ } finally {
+ thenEnv.info.scope.leave();
+ }
+
+ preFlow(tree.thenpart);
+ boolean aliveAfterThen = flow.aliveAfter(env, tree.thenpart, make);
+ boolean aliveAfterElse;
+ List elseBindings = matchBindingsComputer.getMatchBindings(tree.cond, false);
+
+ if (tree.elsepart != null) {
+ Env elseEnv = bindingEnv(env, elseBindings);
+ try {
+ attribStat(tree.elsepart, elseEnv);
+ } finally {
+ elseEnv.info.scope.leave();
+ }
+ preFlow(tree.elsepart);
+ aliveAfterElse = flow.aliveAfter(env, tree.elsepart, make);
+ } else {
+ aliveAfterElse = true;
+ }
+
chk.checkEmptyIf(tree);
+
+ List afterIfBindings = List.nil();
+
+ if (aliveAfterThen && !aliveAfterElse) {
+ afterIfBindings = thenBindings;
+ } else if (aliveAfterElse && !aliveAfterThen) {
+ afterIfBindings = elseBindings;
+ }
+
+ afterIfBindings.forEach(env.info.scope::enter);
+ afterIfBindings.forEach(BindingSymbol::preserveBinding);
+
result = null;
}
+ void preFlow(JCTree tree) {
+ new PostAttrAnalyzer() {
+ @Override
+ public void scan(JCTree tree) {
+ if (tree == null ||
+ (tree.type != null &&
+ tree.type == Type.stuckType)) {
+ //don't touch stuck expressions!
+ return;
+ }
+ super.scan(tree);
+ }
+ }.scan(tree);
+ }
+
public void visitExec(JCExpressionStatement tree) {
//a fresh environment is required for 292 inference to work properly ---
//see Infer.instantiatePolymorphicSignatureInstance()
@@ -3521,7 +3659,32 @@
public void visitBinary(JCBinary tree) {
// Attribute arguments.
Type left = chk.checkNonVoid(tree.lhs.pos(), attribExpr(tree.lhs, env));
- Type right = chk.checkNonVoid(tree.rhs.pos(), attribExpr(tree.rhs, env));
+ // x && y
+ // include x's bindings when true in y
+
+ // x || y
+ // include x's bindings when false in y
+
+ List matchBindings;
+ switch (tree.getTag()) {
+ case AND:
+ matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, true);
+ break;
+ case OR:
+ matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, false);
+ break;
+ default:
+ matchBindings = List.nil();
+ break;
+ }
+ Env rhsEnv = bindingEnv(env, matchBindings);
+ Type right;
+ try {
+ right = chk.checkNonVoid(tree.rhs.pos(), attribExpr(tree.rhs, rhsEnv));
+ } finally {
+ rhsEnv.info.scope.leave();
+ }
+
// Find operator.
Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag(), left, right);
Type owntype = types.createErrorType(tree.type);
@@ -3587,19 +3750,63 @@
public void visitTypeTest(JCInstanceOf tree) {
Type exprtype = chk.checkNullOrRefType(
tree.expr.pos(), attribExpr(tree.expr, env));
- Type clazztype = attribType(tree.clazz, env);
+ Type clazztype;
+ JCTree typeTree;
+ if (tree.pattern.getTag() == BINDINGPATTERN) {
+ attribTree(tree.pattern, env, unknownExprInfo);
+ clazztype = tree.pattern.type;
+ JCBindingPattern pattern = (JCBindingPattern) tree.pattern;
+ typeTree = pattern.vartype;
+ if (!clazztype.hasTag(TYPEVAR)) {
+ clazztype = chk.checkClassOrArrayType(pattern.vartype.pos(), clazztype);
+ }
+ } else {
+ clazztype = attribType(tree.pattern, env);
+ typeTree = tree.pattern;
+ }
if (!clazztype.hasTag(TYPEVAR)) {
- clazztype = chk.checkClassOrArrayType(tree.clazz.pos(), clazztype);
+ clazztype = chk.checkClassOrArrayType(typeTree.pos(), clazztype);
}
if (!clazztype.isErroneous() && !types.isReifiable(clazztype)) {
- log.error(tree.clazz.pos(), Errors.IllegalGenericTypeForInstof);
- clazztype = types.createErrorType(clazztype);
- }
- chk.validate(tree.clazz, env, false);
+ boolean valid = false;
+ if (allowReifiableTypesInInstanceof) {
+ if (preview.isPreview(Feature.REIFIABLE_TYPES_INSTANCEOF)) {
+ preview.warnPreview(tree.expr.pos(), Feature.REIFIABLE_TYPES_INSTANCEOF);
+ }
+ Warner warner = new Warner();
+ if (!types.isCastable(exprtype, clazztype, warner)) {
+ chk.basicHandler.report(tree.expr.pos(),
+ diags.fragment(Fragments.InconvertibleTypes(exprtype, clazztype)));
+ } else if (warner.hasLint(LintCategory.UNCHECKED)) {
+ log.error(tree.expr.pos(),
+ Errors.InstanceofReifiableNotSafe(exprtype, clazztype));
+ } else {
+ valid = true;
+ }
+ } else {
+ log.error(typeTree.pos(), Errors.IllegalGenericTypeForInstof);
+ }
+ if (!valid) {
+ clazztype = types.createErrorType(clazztype);
+ }
+ }
+ chk.validate(typeTree, env, false);
chk.checkCastable(tree.expr.pos(), exprtype, clazztype);
result = check(tree, syms.booleanType, KindSelector.VAL, resultInfo);
}
+ public void visitBindingPattern(JCBindingPattern tree) {
+ ResultInfo varInfo = new ResultInfo(KindSelector.TYP, resultInfo.pt, resultInfo.checkContext);
+ tree.type = attribTree(tree.vartype, env, varInfo);
+ VarSymbol v = tree.symbol = new BindingSymbol(tree.name, tree.vartype.type, env.info.scope.owner);
+ if (chk.checkUnique(tree.pos(), v, env.info.scope)) {
+ chk.checkTransparentVar(tree.pos(), v, env.info.scope);
+ }
+ annotate.queueScanTreeAndTypeAnnotate(tree.vartype, env, v, tree.pos());
+ annotate.flush();
+ result = tree.type;
+ }
+
public void visitIndexed(JCArrayAccess tree) {
Type owntype = types.createErrorType(tree.type);
Type atype = attribExpr(tree.indexed, env);
@@ -4991,8 +5198,8 @@
super.visitTypeCast(tree);
}
public void visitTypeTest(JCInstanceOf tree) {
- if (tree.clazz != null && tree.clazz.type != null)
- validateAnnotatedType(tree.clazz, tree.clazz.type);
+ if (tree.pattern != null && !(tree.pattern instanceof JCPattern) && tree.pattern.type != null)
+ validateAnnotatedType(tree.pattern, tree.pattern.type);
super.visitTypeTest(tree);
}
public void visitNewClass(JCNewClass tree) {
@@ -5253,6 +5460,15 @@
}
@Override
+ public void visitBindingPattern(JCBindingPattern that) {
+ if (that.symbol == null) {
+ that.symbol = new BindingSymbol(that.name, that.type, syms.noSymbol);
+ that.symbol.adr = 0;
+ }
+ super.visitBindingPattern(that);
+ }
+
+ @Override
public void visitNewClass(JCNewClass that) {
if (that.constructor == null) {
that.constructor = new MethodSymbol(0, names.init,
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Wed Nov 27 09:00:01 2019 +0100
@@ -3486,6 +3486,11 @@
duplicateErasureError(pos, sym, byName);
sym.flags_field |= CLASH;
return true;
+ } else if ((sym.flags() & MATCH_BINDING) != 0 &&
+ (byName.flags() & MATCH_BINDING) != 0 &&
+ (byName.flags() & MATCH_BINDING_TO_OUTER) == 0) {
+ //this error will be reported separatelly in MatchBindingsComputer
+ return false;
} else {
duplicateError(pos, byName);
return false;
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java Wed Nov 27 09:00:01 2019 +0100
@@ -59,9 +59,10 @@
ATTR(4),
FLOW(5),
TRANSTYPES(6),
- UNLAMBDA(7),
- LOWER(8),
- GENERATE(9);
+ TRANSPATTERNS(7),
+ UNLAMBDA(8),
+ LOWER(9),
+ GENERATE(10);
CompileState(int value) {
this.value = value;
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Wed Nov 27 09:00:01 2019 +0100
@@ -255,6 +255,41 @@
}
}
+ public boolean aliveAfter(Env env, JCTree that, TreeMaker make) {
+ //we need to disable diagnostics temporarily; the problem is that if
+ //"that" contains e.g. an unreachable statement, an error
+ //message will be reported and will cause compilation to skip the flow analyis
+ //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
+ //related errors, which will allow for more errors to be detected
+ Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
+ try {
+ SnippetAliveAnalyzer analyzer = new SnippetAliveAnalyzer();
+
+ analyzer.analyzeTree(env, that, make);
+ return analyzer.isAlive();
+ } finally {
+ log.popDiagnosticHandler(diagHandler);
+ }
+ }
+
+ public boolean breaksOutOf(Env env, JCTree loop, JCTree body, TreeMaker make) {
+ //we need to disable diagnostics temporarily; the problem is that if
+ //"that" contains e.g. an unreachable statement, an error
+ //message will be reported and will cause compilation to skip the flow analyis
+ //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
+ //related errors, which will allow for more errors to be detected
+ Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
+ try {
+ boolean[] breaksOut = new boolean[1];
+ SnippetBreakAnalyzer analyzer = new SnippetBreakAnalyzer(loop);
+
+ analyzer.analyzeTree(env, body, make);
+ return analyzer.breaksOut();
+ } finally {
+ log.popDiagnosticHandler(diagHandler);
+ }
+ }
+
/**
* Definite assignment scan mode
*/
@@ -1467,6 +1502,38 @@
}
/**
+ * Determine if alive after the given tree.
+ */
+ class SnippetAliveAnalyzer extends AliveAnalyzer {
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ //skip
+ }
+ public boolean isAlive() {
+ return super.alive != Liveness.DEAD;
+ }
+ }
+
+ class SnippetBreakAnalyzer extends AliveAnalyzer {
+ private final JCTree loop;
+ private boolean breaksOut;
+
+ public SnippetBreakAnalyzer(JCTree loop) {
+ this.loop = loop;
+ }
+
+ @Override
+ public void visitBreak(JCBreak tree) {
+ breaksOut |= (super.alive == Liveness.ALIVE && tree.target == loop);
+ super.visitBreak(tree);
+ }
+
+ public boolean breaksOut() {
+ return breaksOut;
+ }
+ }
+
+ /**
* Specialized pass that performs DA/DU on a lambda
*/
class LambdaAssignAnalyzer extends AssignAnalyzer {
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java Wed Nov 27 09:00:01 2019 +0100
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2017, 2019, 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.tools.javac.comp;
+
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBinary;
+import com.sun.tools.javac.tree.JCTree.JCConditional;
+import com.sun.tools.javac.tree.JCTree.JCUnary;
+import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Name;
+
+
+public class MatchBindingsComputer extends TreeScanner {
+ protected static final Context.Key matchBindingsComputerKey = new Context.Key<>();
+
+ private final Log log;
+ private final Types types;
+ boolean whenTrue;
+ List bindings;
+
+ public static MatchBindingsComputer instance(Context context) {
+ MatchBindingsComputer instance = context.get(matchBindingsComputerKey);
+ if (instance == null)
+ instance = new MatchBindingsComputer(context);
+ return instance;
+ }
+
+ protected MatchBindingsComputer(Context context) {
+ this.log = Log.instance(context);
+ this.types = Types.instance(context);
+ }
+
+ public List getMatchBindings(JCTree expression, boolean whenTrue) {
+ this.whenTrue = whenTrue;
+ this.bindings = List.nil();
+ scan(expression);
+ return bindings;
+ }
+
+ @Override
+ public void visitBindingPattern(JCBindingPattern tree) {
+ bindings = whenTrue ? List.of(tree.symbol) : List.nil();
+ }
+
+ @Override
+ public void visitBinary(JCBinary tree) {
+ switch (tree.getTag()) {
+ case AND:
+ // e.T = union(x.T, y.T)
+ // e.F = intersection(x.F, y.F)
+ scan(tree.lhs);
+ List lhsBindings = bindings;
+ scan(tree.rhs);
+ List rhsBindings = bindings;
+ bindings = whenTrue ? union(tree, lhsBindings, rhsBindings) : intersection(tree, lhsBindings, rhsBindings);
+ break;
+ case OR:
+ // e.T = intersection(x.T, y.T)
+ // e.F = union(x.F, y.F)
+ scan(tree.lhs);
+ lhsBindings = bindings;
+ scan(tree.rhs);
+ rhsBindings = bindings;
+ bindings = whenTrue ? intersection(tree, lhsBindings, rhsBindings) : union(tree, lhsBindings, rhsBindings);
+ break;
+ default:
+ super.visitBinary(tree);
+ break;
+ }
+ }
+
+ @Override
+ public void visitUnary(JCUnary tree) {
+ switch (tree.getTag()) {
+ case NOT:
+ // e.T = x.F // flip 'em
+ // e.F = x.T
+ whenTrue = !whenTrue;
+ scan(tree.arg);
+ whenTrue = !whenTrue;
+ break;
+ default:
+ super.visitUnary(tree);
+ break;
+ }
+ }
+
+ @Override
+ public void visitConditional(JCConditional tree) {
+ /* if e = "x ? y : z", then:
+ e.T = union(intersect(y.T, z.T), intersect(x.T, z.T), intersect(x.F, y.T))
+ e.F = union(intersect(y.F, z.F), intersect(x.T, z.F), intersect(x.F, y.F))
+ */
+ if (whenTrue) {
+ List xT, yT, zT, xF;
+ scan(tree.cond);
+ xT = bindings;
+ scan(tree.truepart);
+ yT = bindings;
+ scan(tree.falsepart);
+ zT = bindings;
+ whenTrue = false;
+ scan(tree.cond);
+ xF = bindings;
+ whenTrue = true;
+ bindings = union(tree, intersection(tree, yT, zT), intersection(tree, xT, zT), intersection(tree, xF, yT));
+ } else {
+ List xF, yF, zF, xT;
+ scan(tree.cond);
+ xF = bindings;
+ scan(tree.truepart);
+ yF = bindings;
+ scan(tree.falsepart);
+ zF = bindings;
+ whenTrue = true;
+ scan(tree.cond);
+ xT = bindings;
+ whenTrue = false;
+ bindings = union(tree, intersection(tree, yF, zF), intersection(tree, xT, zF), intersection(tree, xF, yF));
+ }
+ }
+
+ private List intersection(JCTree tree, List lhsBindings, List rhsBindings) {
+ // It is an error if, for intersection(a,b), if a and b contain the same variable name (may be eventually relaxed to merge variables of same type)
+ List list = List.nil();
+ for (BindingSymbol v1 : lhsBindings) {
+ for (BindingSymbol v2 : rhsBindings) {
+ if (v1.name == v2.name) {
+ log.error(tree.pos(), Errors.MatchBindingExists);
+ list = list.append(v2);
+ }
+ }
+ }
+ return list;
+ }
+
+ @SafeVarargs
+ private final List union(JCTree tree, List lhsBindings, List ... rhsBindings_s) {
+ // It is an error if for union(a,b), a and b contain the same name (disjoint union).
+ List list = lhsBindings;
+ for (List rhsBindings : rhsBindings_s) {
+ for (BindingSymbol v : rhsBindings) {
+ for (BindingSymbol ov : list) {
+ if (ov.name == v.name) {
+ log.error(tree.pos(), Errors.MatchBindingExists);
+ }
+ }
+ list = list.append(v);
+ }
+ }
+ return list;
+ }
+
+ @Override
+ public void scan(JCTree tree) {
+ bindings = List.nil();
+ super.scan(tree);
+ }
+
+ public static class BindingSymbol extends VarSymbol {
+
+ public BindingSymbol(Name name, Type type, Symbol owner) {
+ super(Flags.FINAL | Flags.HASINIT | Flags.MATCH_BINDING, name, type, owner);
+ }
+
+ public boolean isAliasFor(BindingSymbol b) {
+ return aliases().containsAll(b.aliases());
+ }
+
+ List aliases() {
+ return List.of(this);
+ }
+
+ public void preserveBinding() {
+ flags_field |= Flags.MATCH_BINDING_TO_OUTER;
+ }
+
+ public boolean isPreserved() {
+ return (flags_field & Flags.MATCH_BINDING_TO_OUTER) != 0;
+ }
+ }
+
+}
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java Wed Nov 27 09:00:01 2019 +0100
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2017, 2019, 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.tools.javac.comp;
+
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCAssign;
+import com.sun.tools.javac.tree.JCTree.JCBinary;
+import com.sun.tools.javac.tree.JCTree.JCConditional;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCForLoop;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.tree.JCTree.JCIf;
+import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
+import com.sun.tools.javac.tree.JCTree.JCLabeledStatement;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
+import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
+import com.sun.tools.javac.tree.JCTree.Tag;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeTranslator;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Names;
+import com.sun.tools.javac.util.Options;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
+import static com.sun.tools.javac.code.TypeTag.BOT;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
+import com.sun.tools.javac.jvm.Target;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.LetExpr;
+import com.sun.tools.javac.util.List;
+
+/**
+ * This pass translates pattern-matching constructs, such as instanceof .
+ */
+public class TransPatterns extends TreeTranslator {
+
+ protected static final Context.Key transPatternsKey = new Context.Key<>();
+
+ public static TransPatterns instance(Context context) {
+ TransPatterns instance = context.get(transPatternsKey);
+ if (instance == null)
+ instance = new TransPatterns(context);
+ return instance;
+ }
+
+ private final Symtab syms;
+ private final Types types;
+ private final Operators operators;
+ private final Log log;
+ private final ConstFold constFold;
+ private final Names names;
+ private final Target target;
+ private final MatchBindingsComputer matchBindingsComputer;
+ private TreeMaker make;
+
+ BindingContext bindingContext = new BindingContext() {
+ @Override
+ VarSymbol getBindingFor(BindingSymbol varSymbol) {
+ return null;
+ }
+
+ @Override
+ JCStatement decorateStatement(JCStatement stat) {
+ return stat;
+ }
+
+ @Override
+ JCExpression decorateExpression(JCExpression expr) {
+ return expr;
+ }
+
+ @Override
+ BindingContext pop() {
+ //do nothing
+ return this;
+ }
+
+ @Override
+ boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) {
+ return false;
+ }
+ };
+
+ JCLabeledStatement pendingMatchLabel = null;
+
+ boolean debugTransPatterns;
+
+ private MethodSymbol currentMethodSym = null;
+
+ protected TransPatterns(Context context) {
+ context.put(transPatternsKey, this);
+ syms = Symtab.instance(context);
+ make = TreeMaker.instance(context);
+ types = Types.instance(context);
+ operators = Operators.instance(context);
+ log = Log.instance(context);
+ constFold = ConstFold.instance(context);
+ names = Names.instance(context);
+ target = Target.instance(context);
+ matchBindingsComputer = MatchBindingsComputer.instance(context);
+ debugTransPatterns = Options.instance(context).isSet("debug.patterns");
+ }
+
+ @Override
+ public void visitTypeTest(JCInstanceOf tree) {
+ if (tree.pattern.hasTag(Tag.BINDINGPATTERN)) {
+ //E instanceof T N
+ //=>
+ //(let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp))
+ JCBindingPattern patt = (JCBindingPattern)tree.pattern;
+ VarSymbol pattSym = patt.symbol;
+ Type tempType = tree.expr.type.hasTag(BOT) ?
+ syms.objectType
+ : tree.expr.type;
+ VarSymbol temp = new VarSymbol(pattSym.flags() | Flags.SYNTHETIC,
+ names.fromString(pattSym.name.toString() + target.syntheticNameChar() + "temp"),
+ tempType,
+ patt.symbol.owner);
+ JCExpression translatedExpr = translate(tree.expr);
+ Type castTargetType = types.boxedTypeOrType(pattSym.erasure(types));
+
+ result = makeTypeTest(make.Ident(temp), make.Type(castTargetType));
+
+ VarSymbol bindingVar = bindingContext.getBindingFor(patt.symbol);
+ if (bindingVar != null) {
+ JCAssign fakeInit = (JCAssign)make.at(tree.pos).Assign(
+ make.Ident(bindingVar), convert(make.Ident(temp), castTargetType)).setType(bindingVar.erasure(types));
+ result = makeBinary(Tag.AND, (JCExpression)result,
+ makeBinary(Tag.EQ, fakeInit, convert(make.Ident(temp), castTargetType)));
+ }
+ result = make.at(tree.pos).LetExpr(make.VarDef(temp, translatedExpr), (JCExpression)result).setType(syms.booleanType);
+ ((LetExpr) result).needsCond = true;
+ } else {
+ super.visitTypeTest(tree);
+ }
+ }
+
+ @Override
+ public void visitBinary(JCBinary tree) {
+ List matchBindings;
+ switch (tree.getTag()) {
+ case AND:
+ matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, true);
+ break;
+ case OR:
+ matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, false);
+ break;
+ default:
+ matchBindings = List.nil();
+ break;
+ }
+
+ bindingContext = new BasicBindingContext(matchBindings);
+ try {
+ super.visitBinary(tree);
+ result = bindingContext.decorateExpression(tree);
+ } finally {
+ bindingContext.pop();
+ }
+ }
+
+ @Override
+ public void visitConditional(JCConditional tree) {
+ bindingContext = new BasicBindingContext(
+ matchBindingsComputer.getMatchBindings(tree.cond, true)
+ .appendList(matchBindingsComputer.getMatchBindings(tree.cond, false)));
+ try {
+ super.visitConditional(tree);
+ result = bindingContext.decorateExpression(tree);
+ } finally {
+ bindingContext.pop();
+ }
+ }
+
+ @Override
+ public void visitIf(JCIf tree) {
+ bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+ try {
+ super.visitIf(tree);
+ result = bindingContext.decorateStatement(tree);
+ } finally {
+ bindingContext.pop();
+ }
+ }
+
+ @Override
+ public void visitForLoop(JCForLoop tree) {
+ bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+ try {
+ super.visitForLoop(tree);
+ result = bindingContext.decorateStatement(tree);
+ } finally {
+ bindingContext.pop();
+ }
+ }
+
+ @Override
+ public void visitWhileLoop(JCWhileLoop tree) {
+ bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+ try {
+ super.visitWhileLoop(tree);
+ result = bindingContext.decorateStatement(tree);
+ } finally {
+ bindingContext.pop();
+ }
+ }
+
+ @Override
+ public void visitDoLoop(JCDoWhileLoop tree) {
+ bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+ try {
+ super.visitDoLoop(tree);
+ result = bindingContext.decorateStatement(tree);
+ } finally {
+ bindingContext.pop();
+ }
+ }
+
+ @Override
+ public void visitMethodDef(JCMethodDecl tree) {
+ MethodSymbol prevMethodSym = currentMethodSym;
+ try {
+ currentMethodSym = tree.sym;
+ super.visitMethodDef(tree);
+ } finally {
+ currentMethodSym = prevMethodSym;
+ }
+ }
+
+ @Override
+ public void visitIdent(JCIdent tree) {
+ VarSymbol bindingVar = null;
+ if ((tree.sym.flags() & Flags.MATCH_BINDING) != 0) {
+ bindingVar = bindingContext.getBindingFor((BindingSymbol)tree.sym);
+ }
+ if (bindingVar == null) {
+ super.visitIdent(tree);
+ } else {
+ result = make.at(tree.pos).Ident(bindingVar);
+ }
+ }
+
+ @Override
+ public void visitBlock(JCBlock tree) {
+ ListBuffer statements = new ListBuffer<>();
+ bindingContext = new BasicBindingContext(List.nil()) {
+ boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) {
+ //{
+ // if (E instanceof T N) {
+ // return ;
+ // }
+ // //use of N:
+ //}
+ //=>
+ //{
+ // T N;
+ // if ((let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp))) {
+ // return ;
+ // }
+ // //use of N:
+ //}
+ hoistedVarMap.put(binding, var.sym);
+ statements.append(var);
+ return true;
+ }
+ };
+ try {
+ for (List l = tree.stats; l.nonEmpty(); l = l.tail) {
+ statements.append(translate(l.head));
+ }
+
+ tree.stats = statements.toList();
+ result = tree;
+ } finally {
+ bindingContext.pop();
+ }
+ }
+
+ public JCTree translateTopLevelClass(Env env, JCTree cdef, TreeMaker make) {
+ try {
+ this.make = make;
+ translate(cdef);
+ } finally {
+ // note that recursive invocations of this method fail hard
+ this.make = null;
+ }
+
+ return cdef;
+ }
+
+ /** Make an instanceof expression.
+ * @param lhs The expression.
+ * @param type The type to be tested.
+ */
+
+ JCInstanceOf makeTypeTest(JCExpression lhs, JCExpression type) {
+ JCInstanceOf tree = make.TypeTest(lhs, type);
+ tree.type = syms.booleanType;
+ return tree;
+ }
+
+ /** Make an attributed binary expression (copied from Lower).
+ * @param optag The operators tree tag.
+ * @param lhs The operator's left argument.
+ * @param rhs The operator's right argument.
+ */
+ JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) {
+ JCBinary tree = make.Binary(optag, lhs, rhs);
+ tree.operator = operators.resolveBinary(tree, optag, lhs.type, rhs.type);
+ tree.type = tree.operator.type.getReturnType();
+ return tree;
+ }
+
+ JCExpression convert(JCExpression expr, Type target) {
+ JCExpression result = make.at(expr.pos()).TypeCast(make.Type(target), expr);
+ result.type = target;
+ return result;
+ }
+
+ private List getMatchBindings(JCExpression cond) {
+ return matchBindingsComputer.getMatchBindings(cond, true)
+ .appendList(matchBindingsComputer.getMatchBindings(cond, false));
+ }
+ abstract class BindingContext {
+ abstract VarSymbol getBindingFor(BindingSymbol varSymbol);
+ abstract JCStatement decorateStatement(JCStatement stat);
+ abstract JCExpression decorateExpression(JCExpression expr);
+ abstract BindingContext pop();
+ abstract boolean tryPrepend(BindingSymbol binding, JCVariableDecl var);
+ }
+
+ class BasicBindingContext extends BindingContext {
+ List matchBindings;
+ Map hoistedVarMap;
+ BindingContext parent;
+
+ public BasicBindingContext(List matchBindings) {
+ this.matchBindings = matchBindings;
+ this.parent = bindingContext;
+ this.hoistedVarMap = matchBindings.stream()
+ .filter(v -> parent.getBindingFor(v) == null)
+ .collect(Collectors.toMap(v -> v, v -> {
+ VarSymbol res = new VarSymbol(v.flags(), v.name, v.type, v.owner);
+ res.setTypeAttributes(v.getRawTypeAttributes());
+ return res;
+ }));
+ }
+
+ @Override
+ VarSymbol getBindingFor(BindingSymbol varSymbol) {
+ VarSymbol res = parent.getBindingFor(varSymbol);
+ if (res != null) {
+ return res;
+ }
+ return hoistedVarMap.entrySet().stream()
+ .filter(e -> e.getKey().isAliasFor(varSymbol))
+ .findFirst()
+ .map(e -> e.getValue()).orElse(null);
+ }
+
+ @Override
+ JCStatement decorateStatement(JCStatement stat) {
+ if (hoistedVarMap.isEmpty()) return stat;
+ //if (E instanceof T N) {
+ // //use N
+ //}
+ //=>
+ //{
+ // T N;
+ // if ((let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp))) {
+ // //use N
+ // }
+ //}
+ ListBuffer stats = new ListBuffer<>();
+ for (Entry e : hoistedVarMap.entrySet()) {
+ JCVariableDecl decl = makeHoistedVarDecl(stat.pos, e.getValue());
+ if (!e.getKey().isPreserved() ||
+ !parent.tryPrepend(e.getKey(), decl)) {
+ stats.add(decl);
+ }
+ }
+ if (stats.nonEmpty()) {
+ stats.add(stat);
+ stat = make.at(stat.pos).Block(0, stats.toList());
+ }
+ return stat;
+ }
+
+ @Override
+ JCExpression decorateExpression(JCExpression expr) {
+ //E instanceof T N && /*use of N*/
+ //=>
+ //(let T N; (let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp)) && /*use of N*/)
+ for (VarSymbol vsym : hoistedVarMap.values()) {
+ expr = make.at(expr.pos).LetExpr(makeHoistedVarDecl(expr.pos, vsym), expr).setType(expr.type);
+ }
+ return expr;
+ }
+
+ @Override
+ BindingContext pop() {
+ return bindingContext = parent;
+ }
+
+ @Override
+ boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) {
+ return false;
+ }
+
+ private JCVariableDecl makeHoistedVarDecl(int pos, VarSymbol varSymbol) {
+ return make.at(pos).VarDef(varSymbol, null);
+ }
+ }
+}
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Wed Nov 27 09:00:01 2019 +0100
@@ -567,6 +567,13 @@
result = tree;
}
+ public void visitBindingPattern(JCBindingPattern tree) {
+ if (tree.vartype != null) {
+ tree.vartype = translate(tree.vartype, null);
+ }
+ result = tree;
+ }
+
public void visitSwitchExpression(JCSwitchExpression tree) {
Type selsuper = types.supertype(tree.selector.type);
boolean enumSwitch = selsuper != null &&
@@ -780,7 +787,7 @@
public void visitTypeTest(JCInstanceOf tree) {
tree.expr = translate(tree.expr, null);
- tree.clazz = translate(tree.clazz, null);
+ tree.pattern = translate(tree.pattern, null);
result = tree;
}
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java Wed Nov 27 09:00:01 2019 +0100
@@ -35,6 +35,7 @@
import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCAssignOp;
import com.sun.tools.javac.tree.JCTree.JCBinary;
+import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCBreak;
import com.sun.tools.javac.tree.JCTree.JCCase;
@@ -253,6 +254,18 @@
}
@Override
+ public void visitBindingPattern(JCBindingPattern tree) {
+ JCBindingPattern that = (JCBindingPattern) parameter;
+ result =
+ scan(tree.vartype, that.vartype)
+ && tree.name == that.name;
+ if (!result) {
+ return;
+ }
+ equiv.put(tree.symbol, that.symbol);
+ }
+
+ @Override
public void visitBlock(JCBlock tree) {
JCBlock that = (JCBlock) parameter;
result = tree.flags == that.flags && scan(tree.stats, that.stats);
@@ -591,7 +604,7 @@
@Override
public void visitTypeTest(JCInstanceOf tree) {
JCInstanceOf that = (JCInstanceOf) parameter;
- result = scan(tree.expr, that.expr) && scan(tree.clazz, that.clazz);
+ result = scan(tree.expr, that.expr) && scan(tree.pattern, that.pattern);
}
@Override
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java Wed Nov 27 09:00:01 2019 +0100
@@ -106,6 +106,12 @@
}
@Override
+ public void visitBindingPattern(JCTree.JCBindingPattern tree) {
+ symbolHashes.computeIfAbsent(tree.symbol, k -> symbolHashes.size());
+ super.visitBindingPattern(tree);
+ }
+
+ @Override
public void visitVarDef(JCVariableDecl tree) {
symbolHashes.computeIfAbsent(tree.sym, k -> symbolHashes.size());
super.visitVarDef(tree);
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java Wed Nov 27 09:00:01 2019 +0100
@@ -473,7 +473,7 @@
public void visitTypeTest(JCInstanceOf tree) {
SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
sr.mergeWith(csp(tree.expr));
- sr.mergeWith(csp(tree.clazz));
+ sr.mergeWith(csp(tree.pattern));
result = sr;
}
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Wed Nov 27 09:00:01 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, 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
@@ -50,6 +50,7 @@
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
import static com.sun.tools.javac.jvm.UninitializedType.*;
import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
+import java.util.Arrays;
/** An internal structure that corresponds to the code attribute of
* methods in a classfile. The class also provides some utility operations to
@@ -2075,6 +2076,7 @@
lvar[adr] = v.dup();
v.closeRange(length);
putVar(v);
+ fillLocalVarPosition(v);
} else {
v.removeLastRange();
}
@@ -2106,20 +2108,31 @@
private void fillLocalVarPosition(LocalVar lv) {
if (lv == null || lv.sym == null || lv.sym.isExceptionParameter()|| !lv.sym.hasTypeAnnotations())
return;
- LocalVar.Range widestRange = lv.getWidestRange();
+ LocalVar.Range[] validRanges = lv.aliveRanges.stream().filter(r -> r.closed() && r.length > 0).toArray(s -> new LocalVar.Range[s]);
+ if (validRanges.length == 0)
+ return ;
+ int[] lvarOffset = Arrays.stream(validRanges).mapToInt(r -> r.start_pc).toArray();
+ int[] lvarLength = Arrays.stream(validRanges).mapToInt(r -> r.length).toArray();
+ int[] lvarIndex = Arrays.stream(validRanges).mapToInt(r -> lv.reg).toArray();
for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) {
TypeAnnotationPosition p = ta.position;
- if (widestRange.closed() && widestRange.length > 0) {
- p.lvarOffset = new int[] { (int)widestRange.start_pc };
- p.lvarLength = new int[] { (int)widestRange.length };
- p.lvarIndex = new int[] { (int)lv.reg };
- p.isValidOffset = true;
- } else {
- p.isValidOffset = false;
- }
+ p.lvarOffset = appendArray(p.lvarOffset, lvarOffset);
+ p.lvarLength = appendArray(p.lvarLength, lvarLength);
+ p.lvarIndex = appendArray(p.lvarIndex, lvarIndex);
+ p.isValidOffset = true;
}
}
+ private int[] appendArray(int[] source, int[] append) {
+ if (source == null || source.length == 0) return append;
+
+ int[] result = new int[source.length + append.length];
+
+ System.arraycopy(source, 0, result, 0, source.length);
+ System.arraycopy(append, 0, result, source.length, append.length);
+ return result;
+ }
+
// Method to be called after compressCatchTable to
// fill in the exception table index for type
// annotations on exception parameters.
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Wed Nov 27 09:00:01 2019 +0100
@@ -2216,7 +2216,7 @@
public void visitTypeTest(JCInstanceOf tree) {
genExpr(tree.expr, tree.expr.type).load();
setTypeAnnotationPositions(tree.pos);
- code.emitop2(instanceof_, makeRef(tree.pos(), tree.clazz.type));
+ code.emitop2(instanceof_, makeRef(tree.pos(), tree.pattern.type));
result = items.makeStackItem(syms.booleanType);
}
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Wed Nov 27 09:00:01 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, 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
@@ -1558,6 +1558,12 @@
env.tree = transTypes.translateTopLevelClass(env.tree, localMake);
compileStates.put(env, CompileState.TRANSTYPES);
+ if (shouldStop(CompileState.TRANSPATTERNS))
+ return;
+
+ env.tree = TransPatterns.instance(context).translateTopLevelClass(env, env.tree, localMake);
+ compileStates.put(env, CompileState.TRANSPATTERNS);
+
if (Feature.LAMBDA.allowedInSource(source) && scanner.hasLambdas) {
if (shouldStop(CompileState.UNLAMBDA))
return;
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Wed Nov 27 09:00:01 2019 +0100
@@ -893,6 +893,7 @@
/* Expression2Rest = {infixop Expression3}
* | Expression3 instanceof Type
+ * | Expression3 instanceof Pattern
* infixop = "||"
* | "&&"
* | "|"
@@ -915,13 +916,24 @@
Token topOp = Tokens.DUMMY;
while (prec(token.kind) >= minprec) {
opStack[top] = topOp;
- top++;
- topOp = token;
- nextToken();
- odStack[top] = (topOp.kind == INSTANCEOF) ? parseType() : term3();
+
+ if (token.kind == INSTANCEOF) {
+ int pos = token.pos;
+ nextToken();
+ JCTree pattern = parseType();
+ if (token.kind == IDENTIFIER) {
+ checkSourceLevel(token.pos, Feature.PATTERN_MATCHING_IN_INSTANCEOF);
+ pattern = toP(F.at(token.pos).BindingPattern(ident(), pattern));
+ }
+ odStack[top] = F.at(pos).TypeTest(odStack[top], pattern);
+ } else {
+ topOp = token;
+ nextToken();
+ top++;
+ odStack[top] = term3();
+ }
while (top > 0 && prec(topOp.kind) >= prec(token.kind)) {
- odStack[top-1] = makeOp(topOp.pos, topOp.kind, odStack[top-1],
- odStack[top]);
+ odStack[top - 1] = F.at(topOp.pos).Binary(optag(topOp.kind), odStack[top - 1], odStack[top]);
top--;
topOp = opStack[top];
}
@@ -938,19 +950,6 @@
return t;
}
//where
- /** Construct a binary or type test node.
- */
- private JCExpression makeOp(int pos,
- TokenKind topOp,
- JCExpression od1,
- JCExpression od2)
- {
- if (topOp == INSTANCEOF) {
- return F.at(pos).TypeTest(od1, od2);
- } else {
- return F.at(pos).Binary(optag(topOp), od1, od2);
- }
- }
/** If tree is a concatenation of string literals, replace it
* by a single literal representing the concatenated string.
*/
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Nov 27 09:00:01 2019 +0100
@@ -546,6 +546,10 @@
auto-closeable resource {0} may not be assigned
# 0: symbol
+compiler.err.pattern.binding.may.not.be.assigned=\
+ pattern binding {0} may not be assigned
+
+# 0: symbol
compiler.err.multicatch.parameter.may.not.be.assigned=\
multi-catch parameter {0} may not be assigned
@@ -1416,6 +1420,10 @@
compiler.misc.varargs.trustme.on.reifiable.varargs=\
Varargs element type {0} is reifiable.
+# 0: type, 1: type
+compiler.err.instanceof.reifiable.not.safe=\
+ {0} cannot be safely cast to {1}
+
# 0: symbol
compiler.misc.varargs.trustme.on.non.varargs.meth=\
Method {0} is not a varargs method.
@@ -2909,6 +2917,12 @@
compiler.misc.feature.var.syntax.in.implicit.lambda=\
var syntax in implicit lambdas
+compiler.misc.feature.pattern.matching.instanceof=\
+ pattern matching in instanceof
+
+compiler.misc.feature.reifiable.types.instanceof=\
+ reifiable types in instanceof
+
compiler.warn.underscore.as.identifier=\
as of release 9, ''_'' is a keyword, and may not be used as an identifier
@@ -3399,6 +3413,9 @@
compiler.err.illegal.argument.for.option=\
illegal argument for {0}: {1}
+compiler.err.match.binding.exists=\
+ illegal attempt to redefine an existing match binding
+
compiler.err.switch.null.not.allowed=\
null label in case is not allowed
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Wed Nov 27 09:00:01 2019 +0100
@@ -38,6 +38,7 @@
import com.sun.tools.javac.code.Directive.RequiresDirective;
import com.sun.tools.javac.code.Scope.*;
import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -238,6 +239,10 @@
*/
TYPETEST,
+ /** Patterns.
+ */
+ BINDINGPATTERN,
+
/** Indexed array expressions, of type Indexed.
*/
INDEXED,
@@ -2135,10 +2140,10 @@
*/
public static class JCInstanceOf extends JCExpression implements InstanceOfTree {
public JCExpression expr;
- public JCTree clazz;
- protected JCInstanceOf(JCExpression expr, JCTree clazz) {
+ public JCTree pattern;
+ protected JCInstanceOf(JCExpression expr, JCTree pattern) {
this.expr = expr;
- this.clazz = clazz;
+ this.pattern = pattern;
}
@Override
public void accept(Visitor v) { v.visitTypeTest(this); }
@@ -2146,7 +2151,13 @@
@DefinedBy(Api.COMPILER_TREE)
public Kind getKind() { return Kind.INSTANCE_OF; }
@DefinedBy(Api.COMPILER_TREE)
- public JCTree getType() { return clazz; }
+ public JCTree getType() { return pattern instanceof JCPattern ? pattern.hasTag(BINDINGPATTERN) ? ((JCBindingPattern) pattern).vartype : null : pattern; }
+
+ @Override @DefinedBy(Api.COMPILER_TREE)
+ public JCPattern getPattern() {
+ return pattern instanceof JCPattern ? (JCPattern) pattern : null;
+ }
+
@DefinedBy(Api.COMPILER_TREE)
public JCExpression getExpression() { return expr; }
@Override @DefinedBy(Api.COMPILER_TREE)
@@ -2160,6 +2171,60 @@
}
/**
+ * Pattern matching forms.
+ */
+ public static abstract class JCPattern extends JCTree
+ implements PatternTree {
+ public JCExpression constExpression() {
+ return null;
+ }
+ }
+
+ public static class JCBindingPattern extends JCPattern
+ implements BindingPatternTree {
+ public Name name;
+ public BindingSymbol symbol;
+ public JCTree vartype;
+
+ protected JCBindingPattern(Name name, BindingSymbol symbol, JCTree vartype) {
+ this.name = name;
+ this.symbol = symbol;
+ this.vartype = vartype;
+ }
+
+ @DefinedBy(Api.COMPILER_TREE)
+ public Name getBinding() {
+ return name;
+ }
+
+ @Override @DefinedBy(Api.COMPILER_TREE)
+ public Tree getType() {
+ return vartype;
+ }
+
+ @Override
+ public void accept(Visitor v) {
+ v.visitBindingPattern(this);
+ }
+
+ @DefinedBy(Api.COMPILER_TREE)
+ public Kind getKind() {
+ return Kind.BINDING_PATTERN;
+ }
+
+ @Override
+ @DefinedBy(Api.COMPILER_TREE)
+ public R accept(TreeVisitor v, D d) {
+ return v.visitBindingPattern(this, d);
+ }
+
+ @Override
+ public Tag getTag() {
+ return BINDINGPATTERN;
+ }
+ }
+
+ /**
* An array selection
*/
public static class JCArrayAccess extends JCExpression implements ArrayAccessTree {
@@ -3133,6 +3198,7 @@
JCBinary Binary(Tag opcode, JCExpression lhs, JCExpression rhs);
JCTypeCast TypeCast(JCTree expr, JCExpression type);
JCInstanceOf TypeTest(JCExpression expr, JCTree clazz);
+ JCBindingPattern BindingPattern(Name name, JCTree vartype);
JCArrayAccess Indexed(JCExpression indexed, JCExpression index);
JCFieldAccess Select(JCExpression selected, Name selector);
JCIdent Ident(Name idname);
@@ -3197,6 +3263,7 @@
public void visitBinary(JCBinary that) { visitTree(that); }
public void visitTypeCast(JCTypeCast that) { visitTree(that); }
public void visitTypeTest(JCInstanceOf that) { visitTree(that); }
+ public void visitBindingPattern(JCBindingPattern that) { visitTree(that); }
public void visitIndexed(JCArrayAccess that) { visitTree(that); }
public void visitSelect(JCFieldAccess that) { visitTree(that); }
public void visitReference(JCMemberReference that) { visitTree(that); }
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java Wed Nov 27 09:00:01 2019 +0100
@@ -234,6 +234,14 @@
printExprs(trees, ", ");
}
+
+ /** Derived visitor method: print pattern.
+ */
+
+ public void printPattern(JCTree tree) throws IOException {
+ printExpr(tree);
+ }
+
/** Derived visitor method: print list of statements, each on a separate line.
*/
public void printStats(List extends JCTree> trees) throws IOException {
@@ -877,6 +885,16 @@
}
}
+ public void visitBindingPattern(JCBindingPattern patt) {
+ try {
+ printExpr(patt.vartype);
+ print(" ");
+ print(patt.name);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
public void visitSynchronized(JCSynchronized tree) {
try {
print("synchronized ");
@@ -1283,7 +1301,11 @@
open(prec, TreeInfo.ordPrec);
printExpr(tree.expr, TreeInfo.ordPrec);
print(" instanceof ");
- printExpr(tree.clazz, TreeInfo.ordPrec + 1);
+ if (tree.pattern instanceof JCPattern) {
+ printPattern(tree.pattern);
+ } else {
+ printExpr(tree.getType(), TreeInfo.ordPrec + 1);
+ }
close(prec, TreeInfo.ordPrec);
} catch (IOException e) {
throw new UncheckedIOException(e);
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java Wed Nov 27 09:00:01 2019 +0100
@@ -26,7 +26,6 @@
package com.sun.tools.javac.tree;
import com.sun.source.tree.*;
-import com.sun.source.tree.Tree.Kind;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
@@ -481,8 +480,15 @@
public JCTree visitInstanceOf(InstanceOfTree node, P p) {
JCInstanceOf t = (JCInstanceOf) node;
JCExpression expr = copy(t.expr, p);
- JCTree clazz = copy(t.clazz, p);
- return M.at(t.pos).TypeTest(expr, clazz);
+ JCTree pattern = copy(t.pattern, p);
+ return M.at(t.pos).TypeTest(expr, pattern);
+ }
+
+ @DefinedBy(Api.COMPILER_TREE)
+ public JCTree visitBindingPattern(BindingPatternTree node, P p) {
+ JCBindingPattern t = (JCBindingPattern) node;
+ JCTree vartype = copy(t.vartype, p);
+ return M.at(t.pos).BindingPattern(t.name, vartype);
}
@DefinedBy(Api.COMPILER_TREE)
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java Wed Nov 27 09:00:01 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, 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
@@ -490,6 +490,10 @@
return getStartPos(node.vartype);
}
}
+ case BINDINGPATTERN: {
+ JCBindingPattern node = (JCBindingPattern)tree;
+ return getStartPos(node.vartype);
+ }
case ERRONEOUS: {
JCErroneous node = (JCErroneous)tree;
if (node.errs != null && node.errs.nonEmpty())
@@ -574,7 +578,7 @@
case TYPECAST:
return getEndPos(((JCTypeCast) tree).expr, endPosTable);
case TYPETEST:
- return getEndPos(((JCInstanceOf) tree).clazz, endPosTable);
+ return getEndPos(((JCInstanceOf) tree).pattern, endPosTable);
case WHILELOOP:
return getEndPos(((JCWhileLoop) tree).body, endPosTable);
case ANNOTATED_TYPE:
@@ -847,6 +851,8 @@
if (node.type != null)
return node.type.tsym;
return null;
+ case BINDINGPATTERN:
+ return ((JCBindingPattern) node).symbol;
default:
return null;
}
@@ -1225,4 +1231,5 @@
public static boolean isPackageInfo(JCCompilationUnit tree) {
return tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE);
}
+
}
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java Wed Nov 27 09:00:01 2019 +0100
@@ -29,7 +29,6 @@
import com.sun.source.tree.CaseTree;
import com.sun.source.tree.ModuleTree.ModuleKind;
-import com.sun.source.tree.Tree.Kind;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Attribute.UnresolvedClass;
import com.sun.tools.javac.code.Symbol.*;
@@ -465,6 +464,12 @@
return tree;
}
+ public JCBindingPattern BindingPattern(Name name, JCTree vartype) {
+ JCBindingPattern tree = new JCBindingPattern(name, null, vartype);
+ tree.pos = pos;
+ return tree;
+ }
+
public JCArrayAccess Indexed(JCExpression indexed, JCExpression index) {
JCArrayAccess tree = new JCArrayAccess(indexed, index);
tree.pos = pos;
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java Wed Nov 27 09:00:01 2019 +0100
@@ -299,7 +299,12 @@
public void visitTypeTest(JCInstanceOf tree) {
scan(tree.expr);
- scan(tree.clazz);
+ scan(tree.pattern);
+ }
+
+ public void visitBindingPattern(JCBindingPattern tree) {
+ if (tree.vartype != null)
+ scan(tree.vartype);
}
public void visitIndexed(JCArrayAccess tree) {
diff -r 88502b1cf76f -r 7799a51dbe30 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Mon Sep 09 11:43:16 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Wed Nov 27 09:00:01 2019 +0100
@@ -354,7 +354,12 @@
public void visitTypeTest(JCInstanceOf tree) {
tree.expr = translate(tree.expr);
- tree.clazz = translate(tree.clazz);
+ tree.pattern = translate(tree.pattern);
+ result = tree;
+ }
+
+ public void visitBindingPattern(JCBindingPattern tree) {
+ tree.vartype = translate(tree.vartype);
result = tree;
}
diff -r 88502b1cf76f -r 7799a51dbe30 test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java Mon Sep 09 11:43:16 2019 -0400
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java Wed Nov 27 09:00:01 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -27,12 +27,14 @@
import java.util.List;
import com.sun.tools.classfile.*;
+import java.util.ArrayList;
public class ClassfileTestHelper {
int expected_tinvisibles = 0;
int expected_tvisibles = 0;
int expected_invisibles = 0;
int expected_visibles = 0;
+ List extraOptions = List.of();
//Makes debugging much easier. Set to 'false' for less output.
public Boolean verbose = true;
@@ -48,8 +50,9 @@
}
File compile(File f) {
- int rc = com.sun.tools.javac.Main.compile(new String[] {
- "-g", f.getPath() });
+ List options = new ArrayList<>(List.of("-g", f.getPath()));
+ options.addAll(extraOptions);
+ int rc = com.sun.tools.javac.Main.compile(options.toArray(new String[0]));
if (rc != 0)
throw new Error("compilation failed. rc=" + rc);
String path = f.getPath();
diff -r 88502b1cf76f -r 7799a51dbe30 test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java Mon Sep 09 11:43:16 2019 -0400
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java Wed Nov 27 09:00:01 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -30,9 +30,13 @@
import com.sun.tools.classfile.*;
import java.io.File;
+import java.util.List;
public class CombinationsTargetTest2 extends ClassfileTestHelper {
+ private static final String JDK_VERSION =
+ Integer.toString(Runtime.getRuntime().version().feature());
+
// Test count helps identify test case in event of failure.
int testcount = 0;
@@ -45,7 +49,9 @@
src5("(repeating) type annotations on field in anonymous class", false),
src6("(repeating) type annotations on void method declaration", false),
src7("(repeating) type annotations in use of instanceof", true),
- src8("(repeating) type annotations in use of instanceof in method", true);
+ src7p("(repeating) type annotations in use of instanceof with type test pattern", true),
+ src8("(repeating) type annotations in use of instanceof in method", true),
+ src8p("(repeating) type annotations in use of instanceof with type test pattern in method", true);
String description;
Boolean local;
@@ -92,8 +98,12 @@
test( 0, 0, 0, 2, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src6);
test( 2, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src7);
test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src7);
+ test( 2, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src7p);
+ test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src7p);
test( 4, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src8);
test( 0, 4, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src8);
+ test( 4, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src8p);
+ test( 0, 4, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src8p);
break;
case "FIELD":
test( 8, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src1);
@@ -122,6 +132,7 @@
expected_tinvisibles = tinv;
expected_visibles = vis;
expected_invisibles = inv;
+ extraOptions = List.of();
File testFile = null;
String tname="Test" + N.toString();
hasInnerClass=false;
@@ -385,6 +396,24 @@
"\n\n";
hasInnerClass=false;
break;
+ case src7p: // (repeating) type annotations in use of instanceof with type test pattern
+ /*
+ * class Test10{
+ * String data = "test";
+ * boolean dataIsString = ( data instanceof @A @B @A @B String str);
+ * }
+ */
+ source = new String( source +
+ "// " + src.description + "\n" +
+ "class "+ testname + "{\n" +
+ " String data = \"test\";\n" +
+ " boolean dataIsString = ( data instanceof _As_ _Bs_ String str && str.isEmpty());\n" +
+ "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+ "\n\n";
+ extraOptions = List.of("--enable-preview",
+ "-source", JDK_VERSION);
+ hasInnerClass=false;
+ break;
case src8: // (repeating) type annotations in use of instanceof
/*
* class Test20{
@@ -411,6 +440,34 @@
"\n\n";
hasInnerClass=false;
break;
+ case src8p: // (repeating) type annotations in use of instanceof with type test pattern
+ /*
+ * class Test20{
+ * String data = "test";
+ * Boolean isString() {
+ * if( data instanceof @A @B @A @B String )
+ * return true;
+ * else
+ * return( data instanceof @A @B @A @B String );
+ * }
+ * }
+ */
+ source = new String( source +
+ "// " + src.description + "\n" +
+ "class "+ testname + "{\n" +
+ " String data = \"test\";\n" +
+ " Boolean isString() { \n" +
+ " if( data instanceof _As_ _Bs_ String str)\n" +
+ " return true;\n" +
+ " else\n" +
+ " return( data instanceof _As_ _Bs_ String str && str.isEmpty());\n" +
+ " }\n" +
+ "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+ "\n\n";
+ extraOptions = List.of("--enable-preview",
+ "-source", JDK_VERSION);
+ hasInnerClass=false;
+ break;
}
return imports + source;
diff -r 88502b1cf76f -r 7799a51dbe30 test/langtools/tools/javac/annotations/typeAnnotations/classfile/Patterns.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/Patterns.java Wed Nov 27 09:00:01 2019 +0100
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2009, 2019, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary Verify type annotation on binding patterns
+ * @library /tools/lib
+ * @modules java.compiler
+ * jdk.jdeps/com.sun.tools.javap
+ * @build toolbox.JavapTask
+ * @compile --enable-preview -source ${jdk.version} Patterns.java
+ * @run main/othervm --enable-preview Patterns
+ */
+
+import java.lang.annotation.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import toolbox.JavapTask;
+import toolbox.Task;
+import toolbox.ToolBox;
+
+public class Patterns {
+
+ private ToolBox tb = new ToolBox();
+
+ public static void main(String[] args) throws Exception {
+ new Patterns().run();
+ }
+
+ public void run() throws Exception {
+ String out = new JavapTask(tb)
+ .options("-private",
+ "-verbose")
+ .classpath(System.getProperty("test.classes"))
+ .classes("Patterns$SimpleBindingPattern")
+ .run()
+ .getOutputLines(Task.OutputKind.DIRECT)
+ .stream()
+ .collect(Collectors.joining("\n"));
+
+ String constantPool = out.substring(0, out.indexOf('{'));
+
+ out = out.replaceAll("(?ms) *Code:.*?\n( *RuntimeInvisibleTypeAnnotations:)", "$1");
+ out = out.substring(out.indexOf('{'));
+ out = out.substring(0, out.lastIndexOf('}') + 1);
+
+ String A = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$A;");
+ String CA = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$CA;");
+ String value = snipCPNumber(constantPool, "value");
+
+ String expected = """
+ {
+ private static final java.lang.Object o;
+ descriptor: Ljava/lang/Object;
+ flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
+
+ private static final boolean B1s;
+ descriptor: Z
+ flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
+
+ private static final boolean B1m;
+ descriptor: Z
+ flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
+
+ private final boolean B2s;
+ descriptor: Z
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+ private final boolean B2m;
+ descriptor: Z
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+ public Patterns$SimpleBindingPattern();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeInvisibleTypeAnnotations:
+ 0: #_A_(): LOCAL_VARIABLE, {start_pc=257, length=18, index=2}
+ Patterns$SimpleBindingPattern$A
+ 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=297, length=19, index=3}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+ 2: #_A_(): LOCAL_VARIABLE, {start_pc=22, length=18, index=1}
+ Patterns$SimpleBindingPattern$A
+ 3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=62, length=18, index=1}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+ 4: #_A_(): LOCAL_VARIABLE, {start_pc=101, length=18, index=2}
+ Patterns$SimpleBindingPattern$A
+ 5: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=141, length=19, index=3}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+ 6: #_A_(): LOCAL_VARIABLE, {start_pc=179, length=18, index=2}
+ Patterns$SimpleBindingPattern$A
+ 7: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=219, length=19, index=3}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+
+ void testPatterns();
+ descriptor: ()V
+ flags: (0x0000)
+ RuntimeInvisibleTypeAnnotations:
+ 0: #_A_(): LOCAL_VARIABLE, {start_pc=17, length=18, index=2}
+ Patterns$SimpleBindingPattern$A
+ 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=57, length=19, index=3}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+
+ void testPatternsDesugared();
+ descriptor: ()V
+ flags: (0x0000)
+ RuntimeInvisibleTypeAnnotations:
+ 0: #_A_(): LOCAL_VARIABLE, {start_pc=17, length=15, index=1; start_pc=51, length=15, index=1}
+ Patterns$SimpleBindingPattern$A
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ RuntimeInvisibleTypeAnnotations:
+ 0: #_A_(): LOCAL_VARIABLE, {start_pc=22, length=18, index=0}
+ Patterns$SimpleBindingPattern$A
+ 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=61, length=18, index=0}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+ 2: #_A_(): LOCAL_VARIABLE, {start_pc=100, length=18, index=1}
+ Patterns$SimpleBindingPattern$A
+ 3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=137, length=18, index=2}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+ }""".replace("_A_", A).replace("_CA_", CA).replace("_value_", value);
+
+ if (!expected.equals(out)) {
+ throw new AssertionError("Unexpected output:\n" + out + "\nexpected:\n" + expected);
+ }
+ }
+
+ private String snipCPNumber(String constantPool, String expectedConstant) {
+ Matcher m = Pattern.compile("#([0-9]+).*" + Pattern.quote(expectedConstant))
+ .matcher(constantPool);
+ if (!m.find()) {
+ throw new AssertionError("Cannot find constant pool item");
+ }
+
+ return m.group(1);
+ }
+
+ /*********************** Test class *************************/
+ static class SimpleBindingPattern {
+ @Target(ElementType.TYPE_USE)
+ @Repeatable(CA.class)
+ @interface A {}
+ @Target(ElementType.TYPE_USE)
+ @interface CA {
+ public A[] value();
+ }
+
+ private static final Object o = "";
+ private static final boolean B1s = o instanceof @A String s && s.isEmpty();
+ private static final boolean B1m = o instanceof @A @A String s && s.isEmpty();
+ private final boolean B2s = o instanceof @A String s && s.isEmpty();
+ private final boolean B2m = o instanceof @A @A String s && s.isEmpty();
+
+ static {
+ boolean B3s = o instanceof @A String s && s.isEmpty();
+ boolean B3m = o instanceof @A @A String s && s.isEmpty();
+ }
+
+ {
+ boolean B4s = o instanceof @A String s && s.isEmpty();
+ boolean B4m = o instanceof @A @A String s && s.isEmpty();
+ }
+
+ {
+ boolean B5s = o instanceof @A String s && s.isEmpty();
+ boolean B5m = o instanceof @A @A String s && s.isEmpty();
+ }
+
+ public SimpleBindingPattern() {
+ boolean B6s = o instanceof @A String s && s.isEmpty();
+ boolean B6m = o instanceof @A @A String s && s.isEmpty();
+ }
+
+ void testPatterns() {
+ boolean B7s = o instanceof @A String s && s.isEmpty();
+ boolean B7m = o instanceof @A @A String s && s.isEmpty();
+ }
+
+ void testPatternsDesugared() {
+ @A String s;
+ boolean B8s = o instanceof String && (s = (String) o) == s && s.isEmpty();
+ boolean B8sx = o instanceof String && (s = (String) o) == s && s.isEmpty();
+ }
+ }
+}
diff -r 88502b1cf76f -r 7799a51dbe30 test/langtools/tools/javac/api/TestGetElementReference.java
--- a/test/langtools/tools/javac/api/TestGetElementReference.java Mon Sep 09 11:43:16 2019 -0400
+++ b/test/langtools/tools/javac/api/TestGetElementReference.java Wed Nov 27 09:00:01 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -51,6 +51,9 @@
public class TestGetElementReference {
+ private static final String JDK_VERSION =
+ Integer.toString(Runtime.getRuntime().version().feature());
+
public static void main(String... args) throws IOException {
analyze("TestGetElementReferenceData.java");
analyze("mod/module-info.java", "mod/api/pkg/Api.java");
@@ -66,7 +69,10 @@
}
}
DiagnosticCollector diagnostics = new DiagnosticCollector<>();
- JavacTask ct = (JavacTask) ToolProvider.getSystemJavaCompiler().getTask(null, null, diagnostics, Arrays.asList("-Xjcov"), null, files);
+ List options = List.of("-Xjcov",
+ "--enable-preview",
+ "-source", JDK_VERSION);
+ JavacTask ct = (JavacTask) ToolProvider.getSystemJavaCompiler().getTask(null, null, diagnostics, options, null, files);
Trees trees = Trees.instance(ct);
CompilationUnitTree cut = ct.parse().iterator().next();
diff -r 88502b1cf76f -r 7799a51dbe30 test/langtools/tools/javac/api/TestGetElementReferenceData.java
--- a/test/langtools/tools/javac/api/TestGetElementReferenceData.java Mon Sep 09 11:43:16 2019 -0400
+++ b/test/langtools/tools/javac/api/TestGetElementReferenceData.java Wed Nov 27 09:00:01 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -35,6 +35,8 @@
java.util.List< /*getElement:INTERFACE:java.util.List*/ String> l;
utility/*getElement:METHOD:test.TestGetElementReferenceData.Base.utility()*/();
target(TestGetElementReferenceData :: test/*getElement:METHOD:test.TestGetElementReferenceData.test()*/);
+ Object/*getElement:CLASS:java.lang.Object*/ o = null;
+ if (o/*getElement:LOCAL_VARIABLE:o*/ instanceof String/*getElement:CLASS:java.lang.String*/ str/*getElement:LOCAL_VARIABLE:str*/) ;
}
private static void target(Runnable r) { r.run(); }
public static class Base {
diff -r 88502b1cf76f -r 7799a51dbe30 test/langtools/tools/javac/diags/examples/InstanceofReifiableNotSafe.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/InstanceofReifiableNotSafe.java Wed Nov 27 09:00:01 2019 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.instanceof.reifiable.not.safe
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source ${jdk.version}
+
+import java.util.List;
+
+class InstanceofReifiableNotSafe {
+ boolean test(Object o) {
+ return o instanceof List l;
+ }
+}
diff -r 88502b1cf76f -r 7799a51dbe30 test/langtools/tools/javac/diags/examples/MatchBindingExists.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/MatchBindingExists.java Wed Nov 27 09:00:01 2019 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, 2019, 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.match.binding.exists
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source ${jdk.version}
+
+class MatchBindingExists {
+ public void test(Object o1, Object o2) {
+ if (o1 instanceof String k && o2 instanceof Integer k) {}
+ }
+}
diff -r 88502b1cf76f -r 7799a51dbe30 test/langtools/tools/javac/diags/examples/PatternBindingMayNotBeAssigned.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/PatternBindingMayNotBeAssigned.java Wed Nov 27 09:00:01 2019 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017, 2019, 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.pattern.binding.may.not.be.assigned
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source ${jdk.version}
+
+class ResourceMayNotBeAssigned {
+ void m(Object o) {
+ if (o instanceof String s) {
+ s = "";
+ }
+ }
+}
diff -r 88502b1cf76f -r 7799a51dbe30 test/langtools/tools/javac/diags/examples/PatternMatchingInstanceof.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/PatternMatchingInstanceof.java Wed Nov 27 09:00:01 2019 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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.
+ */
+
+// key: compiler.misc.feature.pattern.matching.instanceof
+// key: compiler.warn.preview.feature.use
+// options: --enable-preview -source ${jdk.version} -Xlint:preview
+
+class PatternMatchingInstanceof {
+ boolean m(Object o) {
+ return o instanceof String s && s.isEmpty();
+ }
+}
diff -r 88502b1cf76f -r 7799a51dbe30 test/langtools/tools/javac/diags/examples/ReifiableTypesInstanceof.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/ReifiableTypesInstanceof.java Wed Nov 27 09:00:01 2019 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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.
+ */
+
+// key: compiler.misc.feature.reifiable.types.instanceof
+// key: compiler.warn.preview.feature.use.plural
+// options: --enable-preview -source ${jdk.version} -Xlint:preview
+
+class PatternMatchingInstanceof {
+ boolean m(I i) {
+ return i instanceof C;
+ }
+ interface I {}
+ class C implements I {}
+}
diff -r 88502b1cf76f -r 7799a51dbe30 test/langtools/tools/javac/lambda/deduplication/Deduplication.java
--- a/test/langtools/tools/javac/lambda/deduplication/Deduplication.java Mon Sep 09 11:43:16 2019 -0400
+++ b/test/langtools/tools/javac/lambda/deduplication/Deduplication.java Wed Nov 27 09:00:01 2019 +0100
@@ -163,6 +163,9 @@
group((Function) x -> switch (x) { default: yield x; },
(Function) x -> switch (x) { default: yield x; });
+
+ group((Function