Skip to content

Commit 58bfec1

Browse files
authored
Add instanceof statement (#10)
1 parent 934602d commit 58bfec1

20 files changed

+509
-5
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.sun.source.tree;
2+
3+
import jdk.internal.javac.PreviewFeature;
4+
5+
/**
6+
* A tree node for an {@code instanceof} statement.
7+
*
8+
* For example:
9+
* <pre>
10+
* <em>expression</em> instanceof <em>record pattern</em>;
11+
* </pre>
12+
*
13+
* @jls 14.22 The {@code instanceof} Statement
14+
*
15+
* @author Aggelos Biboudis
16+
* @since 23
17+
*/
18+
public interface InstanceOfStatementTree extends StatementTree {
19+
/**
20+
* Returns the pattern for the {@code instanceof} statement.
21+
* @return pattern
22+
*/
23+
@PreviewFeature(feature=PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
24+
Tree getPattern();
25+
26+
/**
27+
* Returns the expression to be pattern matched.
28+
* @return the expression
29+
*/
30+
@PreviewFeature(feature=PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
31+
ExpressionTree getExpression();
32+
33+
/**
34+
* Returns the type for which to check.
35+
* @return the type
36+
* @see #getPattern()
37+
*/
38+
@PreviewFeature(feature=PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
39+
Tree getType();
40+
}

src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,14 @@ public enum Kind {
175175
*/
176176
INSTANCE_OF(InstanceOfTree.class),
177177

178+
/**
179+
* Used for instances of {@link InstanceOfStatementTree}.
180+
*
181+
* @since 23
182+
*/
183+
@PreviewFeature(feature=PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
184+
INSTANCEOF_STATEMENT(InstanceOfStatementTree.class),
185+
178186
/**
179187
* Used for instances of {@link LabeledStatementTree}.
180188
*/

src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,14 @@ public interface TreeVisitor<R,P> {
514514
*/
515515
R visitInstanceOf(InstanceOfTree node, P p);
516516

517+
/**
518+
* Visits an {@code InstanceOfStatementTree} node.
519+
* @param node the node being visited
520+
* @param p a parameter value
521+
* @return a result value
522+
*/
523+
R visitInstanceOfStatement(InstanceOfStatementTree node, P p);
524+
517525
/**
518526
* Visits a {@code UnaryTree} node.
519527
* @param node the node being visited

src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,20 @@ public R visitInstanceOf(InstanceOfTree node, P p) {
629629
return defaultAction(node, p);
630630
}
631631

632+
/**
633+
* {@inheritDoc}
634+
*
635+
* @implSpec This implementation calls {@code defaultAction}.
636+
*
637+
* @param node {@inheritDoc}
638+
* @param p {@inheritDoc}
639+
* @return the result of {@code defaultAction}
640+
*/
641+
@Override
642+
public R visitInstanceOfStatement(InstanceOfStatementTree node, P p) {
643+
return defaultAction(node, p);
644+
}
645+
632646
/**
633647
* {@inheritDoc}
634648
*
@@ -1070,4 +1084,6 @@ public R visitYield(YieldTree node, P p) {
10701084
public R visitMatchStatement(MatchTree node, P p) {
10711085
return defaultAction(node, p);
10721086
}
1087+
1088+
10731089
}

src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,22 @@ public R visitInstanceOf(InstanceOfTree node, P p) {
762762
return r;
763763
}
764764

765+
/**
766+
* {@inheritDoc}
767+
*
768+
* @implSpec This implementation scans the children in left to right order.
769+
*
770+
* @param node {@inheritDoc}
771+
* @param p {@inheritDoc}
772+
* @return the result of scanning
773+
*/
774+
@Override
775+
public R visitInstanceOfStatement(InstanceOfStatementTree node, P p) {
776+
R r = scan(node.getPattern(), p);
777+
r = scanAndReduce(node.getExpression(), p, r);
778+
return r;
779+
}
780+
765781
/**
766782
* {@inheritDoc}
767783
*

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,6 +2439,19 @@ public void visitMatch(JCMatch tree) {
24392439
result = null;
24402440
}
24412441

2442+
public void visitTypeTestStatement(JCInstanceOfStatement tree) {
2443+
attribExpr(tree.expr, env);
2444+
attribExpr(tree.pattern, env);
2445+
2446+
matchBindings.bindingsWhenTrue.forEach(env.info.scope::enter);
2447+
matchBindings.bindingsWhenTrue.forEach(BindingSymbol::preserveBinding);
2448+
2449+
Type clazztype = tree.pattern.type;
2450+
checkCastablePattern(tree.expr.pos(), tree.expr.type, clazztype);
2451+
2452+
result = null;
2453+
}
2454+
24422455
public void visitContinue(JCContinue tree) {
24432456
tree.target = findJumpTarget(tree.pos(), tree.getTag(), tree.label, env);
24442457
result = null;

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,34 @@ public void visitMatch(JCMatch tree) {
696696
recordExit(new PendingExit(tree));
697697
}
698698

699+
public void visitTypeTestStatement(JCInstanceOfStatement tree) {
700+
ListBuffer<PendingExit> prevPendingExits = pendingExits;
701+
pendingExits = new ListBuffer<>();
702+
703+
if (tree.pattern instanceof JCRecordPattern rp) {
704+
visitRecordPattern(rp);
705+
}
706+
707+
List<JCCase> singletonCaseList = List.of(make.Case(
708+
CaseTree.CaseKind.STATEMENT,
709+
List.of(make.PatternCaseLabel(tree.pattern)),
710+
null,
711+
List.nil(),
712+
null)
713+
);
714+
715+
boolean isExhaustive =
716+
exhausts(tree.expr, singletonCaseList);
717+
718+
if (!isExhaustive) {
719+
log.error(tree, Errors.NotExhaustiveStatement); // TODO replace with instanceof-related error since this refers to switch
720+
}
721+
722+
scan(tree.expr);
723+
724+
alive = alive.or(resolveBreaks(tree, prevPendingExits));
725+
}
726+
699727
public void visitForeachLoop(JCEnhancedForLoop tree) {
700728
visitVarDef(tree.var);
701729
ListBuffer<PendingExit> prevPendingExits = pendingExits;

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
import com.sun.tools.javac.tree.JCTree.JCIdent;
5757
import com.sun.tools.javac.tree.JCTree.JCIf;
5858
import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
59+
import com.sun.tools.javac.tree.JCTree.JCInstanceOfStatement;
60+
import com.sun.tools.javac.tree.JCTree.JCThrow;
5961
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
6062
import com.sun.tools.javac.tree.JCTree.JCSwitch;
6163
import com.sun.tools.javac.tree.JCTree.JCMatch;
@@ -266,6 +268,44 @@ public void visitTypeTest(JCInstanceOf tree) {
266268
}
267269
}
268270

271+
@Override
272+
public void visitTypeTestStatement(JCInstanceOfStatement tree) {
273+
/**
274+
* A statement of the form
275+
*
276+
* <pre>
277+
* <expression> instanceof <pattern>;
278+
* </pre>
279+
*
280+
* (where <pattern> is any pattern) is translated to:
281+
*
282+
* <pre>{@code
283+
* if (!(<expression> instanceof(<pattern>)) {
284+
* throw new MatchException(null, null);
285+
* }
286+
* }</pre>
287+
*
288+
*/
289+
bindingContext = new BasicBindingContext();
290+
try {
291+
List<JCExpression> matchExParams = List.of(makeNull(), makeNull());
292+
JCThrow thr = make.Throw(makeNewClass(syms.matchExceptionType, matchExParams));
293+
294+
JCExpression expr = translate(tree.expr);
295+
296+
JCInstanceOf instanceOfTree = make.TypeTest(expr, tree.pattern);
297+
tree.type = syms.booleanType;
298+
299+
JCIf ifNode = make.If(makeUnary(Tag.NOT,
300+
translate(instanceOfTree)).setType(syms.booleanType), thr, null);
301+
302+
result = bindingContext.decorateStatement(ifNode);
303+
} finally {
304+
bindingContext.pop();
305+
}
306+
}
307+
308+
269309
@Override
270310
public void visitAnyPattern(JCTree.JCAnyPattern that) {
271311
result = make.Literal(true);

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,12 @@ public void visitTypeTest(JCInstanceOf tree) {
10781078
result = tree;
10791079
}
10801080

1081+
public void visitTypeTestStatement(JCInstanceOfStatement tree) {
1082+
tree.expr = translate(tree.expr, null);
1083+
tree.pattern = translate(tree.pattern, null);
1084+
result = tree;
1085+
}
1086+
10811087
public void visitIndexed(JCArrayAccess tree) {
10821088
tree.indexed = translate(tree.indexed, erasure(tree.indexed.type));
10831089
tree.index = translate(tree.index, syms.intType);

src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import javax.lang.model.SourceVersion;
3434

3535
import com.sun.source.tree.CaseTree;
36+
import com.sun.source.tree.InstanceOfStatementTree;
3637
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
3738
import com.sun.source.tree.ModuleTree.ModuleKind;
3839

@@ -3016,11 +3017,17 @@ List<JCStatement> blockStatement() {
30163017
F.at(pos);
30173018
return localVariableDeclarations(mods, t, dc);
30183019
} else {
3019-
// This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
3020-
t = checkExprStat(t);
3021-
accept(SEMI);
3022-
JCExpressionStatement expr = toP(F.at(pos).Exec(t));
3023-
return List.of(expr);
3020+
if (t.getTag() == TYPETEST && allowPatternDeclarations) {
3021+
t = term2Rest(t, TreeInfo.orPrec);
3022+
accept(SEMI);
3023+
return List.of(toP(F.at(pos).TypeTestStatement(((JCInstanceOf) t).expr, ((JCInstanceOf)t ).getPattern())));
3024+
} else {
3025+
// This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
3026+
t = checkExprStat(t);
3027+
accept(SEMI);
3028+
JCExpressionStatement expr = toP(F.at(pos).Exec(t));
3029+
return List.of(expr);
3030+
}
30243031
}
30253032
}
30263033
}

0 commit comments

Comments
 (0)