diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfStatementTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfStatementTree.java
new file mode 100644
index 00000000000..31de7182de9
--- /dev/null
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfStatementTree.java
@@ -0,0 +1,40 @@
+package com.sun.source.tree;
+
+import jdk.internal.javac.PreviewFeature;
+
+/**
+ * A tree node for an {@code instanceof} statement.
+ *
+ * For example:
+ *
+ * expression instanceof record pattern;
+ *
+ *
+ * @jls 14.22 The {@code instanceof} Statement
+ *
+ * @author Aggelos Biboudis
+ * @since 23
+ */
+public interface InstanceOfStatementTree extends StatementTree {
+ /**
+ * Returns the pattern for the {@code instanceof} statement.
+ * @return pattern
+ */
+ @PreviewFeature(feature=PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
+ Tree getPattern();
+
+ /**
+ * Returns the expression to be pattern matched.
+ * @return the expression
+ */
+ @PreviewFeature(feature=PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
+ ExpressionTree getExpression();
+
+ /**
+ * Returns the type for which to check.
+ * @return the type
+ * @see #getPattern()
+ */
+ @PreviewFeature(feature=PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
+ Tree getType();
+}
\ No newline at end of file
diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java
index af444818faa..5ec2c219120 100644
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java
@@ -175,6 +175,14 @@ public enum Kind {
*/
INSTANCE_OF(InstanceOfTree.class),
+ /**
+ * Used for instances of {@link InstanceOfStatementTree}.
+ *
+ * @since 23
+ */
+ @PreviewFeature(feature=PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
+ INSTANCEOF_STATEMENT(InstanceOfStatementTree.class),
+
/**
* Used for instances of {@link LabeledStatementTree}.
*/
diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java
index 0947d0e38ff..7fd27a1e943 100644
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java
@@ -514,6 +514,14 @@ public interface TreeVisitor {
*/
R visitInstanceOf(InstanceOfTree node, P p);
+ /**
+ * Visits an {@code InstanceOfStatementTree} node.
+ * @param node the node being visited
+ * @param p a parameter value
+ * @return a result value
+ */
+ R visitInstanceOfStatement(InstanceOfStatementTree node, P p);
+
/**
* Visits a {@code UnaryTree} node.
* @param node the node being visited
diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java
index c16140ba69e..828212ecbab 100644
--- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java
@@ -629,6 +629,20 @@ public R visitInstanceOf(InstanceOfTree node, P p) {
return defaultAction(node, p);
}
+ /**
+ * {@inheritDoc}
+ *
+ * @implSpec This implementation calls {@code defaultAction}.
+ *
+ * @param node {@inheritDoc}
+ * @param p {@inheritDoc}
+ * @return the result of {@code defaultAction}
+ */
+ @Override
+ public R visitInstanceOfStatement(InstanceOfStatementTree node, P p) {
+ return defaultAction(node, p);
+ }
+
/**
* {@inheritDoc}
*
@@ -1070,4 +1084,6 @@ public R visitYield(YieldTree node, P p) {
public R visitMatchStatement(MatchTree node, P p) {
return defaultAction(node, p);
}
+
+
}
diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java
index 85db93f533d..f733bbc81d5 100644
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java
@@ -762,6 +762,22 @@ public R visitInstanceOf(InstanceOfTree node, P p) {
return r;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @implSpec This implementation scans the children in left to right order.
+ *
+ * @param node {@inheritDoc}
+ * @param p {@inheritDoc}
+ * @return the result of scanning
+ */
+ @Override
+ public R visitInstanceOfStatement(InstanceOfStatementTree node, P p) {
+ R r = scan(node.getPattern(), p);
+ r = scanAndReduce(node.getExpression(), p, r);
+ return r;
+ }
+
/**
* {@inheritDoc}
*
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
index 376c510fb91..99266fd6aab 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -2439,6 +2439,19 @@ public void visitMatch(JCMatch tree) {
result = null;
}
+ public void visitTypeTestStatement(JCInstanceOfStatement tree) {
+ attribExpr(tree.expr, env);
+ attribExpr(tree.pattern, env);
+
+ matchBindings.bindingsWhenTrue.forEach(env.info.scope::enter);
+ matchBindings.bindingsWhenTrue.forEach(BindingSymbol::preserveBinding);
+
+ Type clazztype = tree.pattern.type;
+ checkCastablePattern(tree.expr.pos(), tree.expr.type, clazztype);
+
+ result = null;
+ }
+
public void visitContinue(JCContinue tree) {
tree.target = findJumpTarget(tree.pos(), tree.getTag(), tree.label, env);
result = null;
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
index a8e3c41fa70..97f8e553fe7 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
@@ -696,6 +696,34 @@ public void visitMatch(JCMatch tree) {
recordExit(new PendingExit(tree));
}
+ public void visitTypeTestStatement(JCInstanceOfStatement tree) {
+ ListBuffer prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<>();
+
+ if (tree.pattern instanceof JCRecordPattern rp) {
+ visitRecordPattern(rp);
+ }
+
+ List singletonCaseList = List.of(make.Case(
+ CaseTree.CaseKind.STATEMENT,
+ List.of(make.PatternCaseLabel(tree.pattern)),
+ null,
+ List.nil(),
+ null)
+ );
+
+ boolean isExhaustive =
+ exhausts(tree.expr, singletonCaseList);
+
+ if (!isExhaustive) {
+ log.error(tree, Errors.NotExhaustiveStatement); // TODO replace with instanceof-related error since this refers to switch
+ }
+
+ scan(tree.expr);
+
+ alive = alive.or(resolveBreaks(tree, prevPendingExits));
+ }
+
public void visitForeachLoop(JCEnhancedForLoop tree) {
visitVarDef(tree.var);
ListBuffer prevPendingExits = pendingExits;
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java
index af6bdc4f639..40e32bdc934 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java
@@ -56,6 +56,8 @@
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.JCInstanceOfStatement;
+import com.sun.tools.javac.tree.JCTree.JCThrow;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCSwitch;
import com.sun.tools.javac.tree.JCTree.JCMatch;
@@ -266,6 +268,44 @@ public void visitTypeTest(JCInstanceOf tree) {
}
}
+ @Override
+ public void visitTypeTestStatement(JCInstanceOfStatement tree) {
+ /**
+ * A statement of the form
+ *
+ *
+ * instanceof ;
+ *
+ *
+ * (where is any pattern) is translated to:
+ *
+ * {@code
+ * if (!( instanceof()) {
+ * throw new MatchException(null, null);
+ * }
+ * }
+ *
+ */
+ bindingContext = new BasicBindingContext();
+ try {
+ List matchExParams = List.of(makeNull(), makeNull());
+ JCThrow thr = make.Throw(makeNewClass(syms.matchExceptionType, matchExParams));
+
+ JCExpression expr = translate(tree.expr);
+
+ JCInstanceOf instanceOfTree = make.TypeTest(expr, tree.pattern);
+ tree.type = syms.booleanType;
+
+ JCIf ifNode = make.If(makeUnary(Tag.NOT,
+ translate(instanceOfTree)).setType(syms.booleanType), thr, null);
+
+ result = bindingContext.decorateStatement(ifNode);
+ } finally {
+ bindingContext.pop();
+ }
+ }
+
+
@Override
public void visitAnyPattern(JCTree.JCAnyPattern that) {
result = make.Literal(true);
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java
index db3199dcc22..e5d45a78b7f 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java
@@ -1078,6 +1078,12 @@ public void visitTypeTest(JCInstanceOf tree) {
result = tree;
}
+ public void visitTypeTestStatement(JCInstanceOfStatement tree) {
+ tree.expr = translate(tree.expr, null);
+ tree.pattern = translate(tree.pattern, null);
+ result = tree;
+ }
+
public void visitIndexed(JCArrayAccess tree) {
tree.indexed = translate(tree.indexed, erasure(tree.indexed.type));
tree.index = translate(tree.index, syms.intType);
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
index d7c7b785f59..585b376509d 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
@@ -33,6 +33,7 @@
import javax.lang.model.SourceVersion;
import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.InstanceOfStatementTree;
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
import com.sun.source.tree.ModuleTree.ModuleKind;
@@ -3016,11 +3017,17 @@ List blockStatement() {
F.at(pos);
return localVariableDeclarations(mods, t, dc);
} else {
- // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
- t = checkExprStat(t);
- accept(SEMI);
- JCExpressionStatement expr = toP(F.at(pos).Exec(t));
- return List.of(expr);
+ if (t.getTag() == TYPETEST && allowPatternDeclarations) {
+ t = term2Rest(t, TreeInfo.orPrec);
+ accept(SEMI);
+ return List.of(toP(F.at(pos).TypeTestStatement(((JCInstanceOf) t).expr, ((JCInstanceOf)t ).getPattern())));
+ } else {
+ // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
+ t = checkExprStat(t);
+ accept(SEMI);
+ JCExpressionStatement expr = toP(F.at(pos).Exec(t));
+ return List.of(expr);
+ }
}
}
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java
index 93abe29bb42..4fca6fd5c06 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java
@@ -245,6 +245,10 @@ public enum Tag {
*/
TYPETEST,
+ /** Type test statements, of type TypeTest.
+ */
+ TYPETEST_STATEMENT,
+
/** Patterns.
*/
ANYPATTERN,
@@ -1769,6 +1773,38 @@ public Tag getTag() {
}
}
+ /**
+ * The match statement
+ */
+ public static class JCInstanceOfStatement extends JCStatement implements InstanceOfStatementTree {
+ public JCPattern pattern;
+ public JCExpression expr;
+
+ protected JCInstanceOfStatement(JCExpression expr, JCPattern pattern) {
+ this.pattern = pattern;
+ this.expr = expr;
+ }
+ @Override
+ public void accept(Visitor v) { v.visitTypeTestStatement(this); }
+
+ @DefinedBy(Api.COMPILER_TREE)
+ public Kind getKind() { return Kind.INSTANCEOF_STATEMENT; }
+ @Override @DefinedBy(Api.COMPILER_TREE)
+ public Tree getPattern() { return pattern; }
+ @DefinedBy(Api.COMPILER_TREE)
+ public JCTree getType() { return pattern instanceof JCPattern ? pattern.hasTag(BINDINGPATTERN) ? ((JCBindingPattern) pattern).var.vartype : null : pattern; }
+ @DefinedBy(Api.COMPILER_TREE)
+ public JCExpression getExpression() { return expr; }
+ @Override @DefinedBy(Api.COMPILER_TREE)
+ public R accept(TreeVisitor v, D d) {
+ return v.visitInstanceOfStatement(this, d);
+ }
+ @Override
+ public Tag getTag() {
+ return TYPETEST_STATEMENT;
+ }
+ }
+
/**
* A continue of a loop.
*/
@@ -3605,6 +3641,7 @@ public abstract static class Visitor {
public void visitBinary(JCBinary that) { visitTree(that); }
public void visitTypeCast(JCTypeCast that) { visitTree(that); }
public void visitTypeTest(JCInstanceOf that) { visitTree(that); }
+ public void visitTypeTestStatement(JCInstanceOfStatement that) { visitTree(that); }
public void visitAnyPattern(JCAnyPattern that) { visitTree(that); }
public void visitBindingPattern(JCBindingPattern that) { visitTree(that); }
public void visitDefaultCaseLabel(JCDefaultCaseLabel that) { visitTree(that); }
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java
index c918f5ce7c8..fc16645dca0 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java
@@ -1420,6 +1420,23 @@ public void visitTypeTest(JCInstanceOf tree) {
}
}
+ public void visitTypeTestStatement(JCInstanceOfStatement tree) {
+ try {
+ open(prec, TreeInfo.ordPrec);
+ printExpr(tree.expr, TreeInfo.ordPrec);
+ print(" instanceof ");
+ if (tree.pattern instanceof JCPattern) {
+ printPattern(tree.pattern);
+ } else {
+ printExpr(tree.getType(), TreeInfo.ordPrec + 1);
+ }
+ close(prec, TreeInfo.ordPrec);
+ print(';');
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
public void visitIndexed(JCArrayAccess tree) {
try {
printExpr(tree.indexed, TreeInfo.postfixPrec);
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java
index ffd97458079..1637132a2f2 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java
@@ -507,6 +507,14 @@ public JCTree visitInstanceOf(InstanceOfTree node, P p) {
return M.at(t.pos).TypeTest(expr, pattern);
}
+ @DefinedBy(Api.COMPILER_TREE)
+ public JCTree visitInstanceOfStatement(InstanceOfStatementTree node, P p) {
+ JCInstanceOfStatement t = (JCInstanceOfStatement) node;
+ JCExpression expr = copy(t.expr, p);
+ JCPattern pattern = copy(t.pattern, p);
+ return M.at(t.pos).TypeTestStatement(expr, pattern);
+ }
+
@DefinedBy(Api.COMPILER_TREE)
public JCTree visitAnyPattern(AnyPatternTree node, P p) {
JCAnyPattern t = (JCAnyPattern) node;
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java
index 466148f6c3e..9596c098a01 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java
@@ -498,6 +498,13 @@ public JCInstanceOf TypeTest(JCExpression expr, JCTree clazz) {
return tree;
}
+ public JCInstanceOfStatement TypeTestStatement(JCExpression expr, JCPattern pattern) {
+ JCInstanceOfStatement tree = new JCInstanceOfStatement(expr, pattern);
+ tree.pos = pos;
+ return tree;
+ }
+
+
public JCAnyPattern AnyPattern() {
JCAnyPattern tree = new JCAnyPattern();
tree.pos = pos;
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java
index cf9244ab941..d5d473d6a5c 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java
@@ -315,6 +315,11 @@ public void visitTypeTest(JCInstanceOf tree) {
scan(tree.pattern);
}
+ public void visitTypeTestStatement(JCInstanceOfStatement tree) {
+ scan(tree.expr);
+ scan(tree.pattern);
+ }
+
public void visitBindingPattern(JCBindingPattern tree) {
scan(tree.var);
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java
index 440b74b4a2e..c7d1b8bab74 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java
@@ -371,6 +371,12 @@ public void visitTypeTest(JCInstanceOf tree) {
result = tree;
}
+ public void visitTypeTestStatement(JCInstanceOfStatement tree) {
+ tree.pattern = translate(tree.pattern);
+ tree.expr = translate(tree.expr);
+ result = tree;
+ }
+
public void visitBindingPattern(JCBindingPattern tree) {
tree.var = translate(tree.var);
result = tree;
diff --git a/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementErrors.java b/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementErrors.java
new file mode 100644
index 00000000000..e31976f82c3
--- /dev/null
+++ b/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementErrors.java
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary
+ * @enablePreview
+ * @compile/fail/ref=InstanceOfStatementErrors.out -XDrawDiagnostics -XDshould-stop.at=FLOW InstanceOfStatementErrors.java
+ */
+
+import java.util.List;
+
+public class InstanceOfStatementErrors {
+ static void exhaustivity_error1(Object point) {
+ point instanceof Point(var x, var y);
+ }
+
+ sealed interface IPoint permits Point {}
+ record Point(Integer x, Integer y) implements IPoint { }
+ record OPoint(Object x, Object y) { }
+}
\ No newline at end of file
diff --git a/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementErrors.out b/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementErrors.out
new file mode 100644
index 00000000000..15d9970521c
--- /dev/null
+++ b/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementErrors.out
@@ -0,0 +1,2 @@
+InstanceOfStatementErrors.java:12:9: compiler.err.not.exhaustive.statement
+1 error
diff --git a/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementInMethodsTest.java b/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementInMethodsTest.java
new file mode 100644
index 00000000000..48827ffe213
--- /dev/null
+++ b/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementInMethodsTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.
+ */
+
+import java.util.Objects;
+import java.util.function.Supplier;
+
+/**
+ * @test
+ * @enablePreview
+ * @compile -parameters InstanceOfStatementInMethodsTest.java
+ * @run main InstanceOfStatementInMethodsTest
+ */
+public class InstanceOfStatementInMethodsTest {
+ public static void main(String[] args) {
+ basicTest();
+ assertMatchExceptionWithNested(InstanceOfStatementInMethodsTest::raiseExceptionTest, TestPatternFailed.class);
+ }
+
+ static void basicTest() {
+ Point p = new Point(1, 2);
+ p instanceof Point(Integer a, Integer b);
+ assertEquals(3, a + b);
+
+ IPoint ip = new Point(3, 4);
+ ip instanceof Point(var c, var d);
+ assertEquals(7, c + d);
+
+ p = new Point(1, null);
+ p instanceof Point(var e, var f);
+ assertEquals(null, f);
+
+ PointP wp = new PointP(1, 2);
+ wp instanceof PointP(int ap, double bp);
+ assertEquals(2.0d, bp);
+ }
+
+ static Integer raiseExceptionTest() {
+ PointEx pointEx = new PointEx(1, 2);
+ pointEx instanceof PointEx(Integer a_ex, Integer b_noex);
+ return a_ex;
+ }
+
+ sealed interface IPoint permits Point {}
+ record Point(Integer x, Integer y) implements IPoint { }
+ record PointP(int x, double y) { }
+ record PointEx(Integer x, Integer y) {
+ @Override
+ public Integer x() {
+ throw new TestPatternFailed(EXCEPTION_MESSAGE);
+ }
+ }
+ static final String EXCEPTION_MESSAGE = "exception-message";
+ public static class TestPatternFailed extends AssertionError {
+ public TestPatternFailed(String message) {
+ super(message);
+ }
+ }
+
+ // error handling
+ static void fail(String message) {
+ throw new AssertionError(message);
+ }
+
+ static void assertEquals(Object expected, Object actual) {
+ if (!Objects.equals(expected, actual)) {
+ throw new AssertionError("Expected: " + expected + "," +
+ "got: " + actual);
+ }
+ }
+
+ static void assertMatchExceptionWithNested(Supplier f, Class> nestedExceptionClass) {
+ try {
+ f.get();
+ fail("Expected an exception, but none happened!");
+ }
+ catch(Exception ex) {
+ assertEquals(MatchException.class, ex.getClass());
+
+ MatchException me = (MatchException) ex;
+
+ assertEquals(nestedExceptionClass, me.getCause().getClass());
+ }
+ }
+
+ static void assertEx(Supplier f, Class> exceptionClass) {
+ try {
+ f.get();
+ fail("Expected an exception, but none happened!");
+ }
+ catch(Exception ex) {
+ assertEquals(exceptionClass, ex.getClass());
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementInPatternsTest.java b/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementInPatternsTest.java
new file mode 100644
index 00000000000..ff5eaeb0b04
--- /dev/null
+++ b/test/langtools/tools/javac/patterns/declarations/InstanceOfStatementInPatternsTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.
+ */
+
+import java.util.Objects;
+
+/**
+ * @test
+ * @enablePreview
+ * @compile -parameters InstanceOfStatementInPatternsTest.java
+ * @run main InstanceOfStatementInPatternsTest
+ */
+public class InstanceOfStatementInPatternsTest {
+
+ public static void main(String... args) {
+ assertEquals("B", testB(new B(new H("B"))));
+ assertEquals("AB", testC(new C(new A("A"), new B(new H("B")))));
+ try {
+ testC(new C(new A("A"), new B(null)));
+ throw new AssertionError("Expected an MatchException, but none thrown.");
+ } catch (MatchException ex) {
+ ;
+ }
+ }
+
+ static String testB(B b) {
+ return switch(b) {
+ case B(String s) -> s;
+ };
+ }
+
+ static String testC(C c) {
+ return switch(c) {
+ case C(String x, String y) -> x + y;
+ };
+ }
+
+ // dependency to super class
+ static class Base {
+ String s;
+ public Base(String s) {
+ this.s = s;
+ }
+ pattern Base(String s) {
+ match Base(this.s);
+ }
+ }
+ static class A extends Base {
+ public A(String s) {
+ super(s);
+ }
+ pattern A(String s) {
+ this instanceof Base(String ss); // instanceof calls super
+ match A(ss);
+ }
+ }
+
+ // dependency to field
+ record H(T t) { }
+ static class B {
+ H h;
+
+ public B(H s) { h = s; }
+
+ pattern B(String s) {
+ h instanceof H(String ss); // not calling in super, just a regulard instanceof
+ // unconditional apart from null in the remainder
+ match B(ss);
+ }
+ }
+
+ // multiple instanceof statements
+ static class C {
+ A a;
+ B b;
+ public C(A a, B b) {this.a = a; this.b = b;}
+ public pattern C(String x, String y) {
+ a instanceof A(var xx); // not calling in super, just a regulard instanceof
+ b instanceof B(var yy);
+ match C(xx, yy);
+ }
+ }
+
+ private static void assertEquals(T expected, T actual) {
+ if (!Objects.equals(expected, actual)) {
+ throw new AssertionError("Expected: " + expected + ", but got: " + actual);
+ }
+ }
+}
\ No newline at end of file