Skip to content

Attempting to add match-failed + partial deconstructors. No support for partial deconstructor exhaustiveness groups yet. #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@
*
* @since 23
*/
@PreviewFeature(feature= PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
//TODO: maybe MatchSuccessTree?
public interface MatchTree extends StatementTree {

/**
* Returns the expression for this {@code match} statement.
*
* @return the expression
*/
@PreviewFeature(feature= PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
List<? extends ExpressionTree> getArguments();
}
12 changes: 11 additions & 1 deletion src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,17 @@ public enum Kind {
* @since 23
*/
@PreviewFeature(feature=PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
MATCH(MatchTree.class);
MATCH(MatchTree.class), //TODO: maybe MATCH_SUCCESS

/**
* Used for instances of {@link MatchFailTree}.
*
* @since 25
*/
@PreviewFeature(feature=PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
MATCH_FAILED(MatchFailTree.class),

;

Kind(Class<? extends Tree> intf) {
associatedInterface = intf;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

package com.sun.source.tree;

import jdk.internal.javac.PreviewFeature;

/**
* A visitor of trees, in the style of the visitor design pattern.
* Classes implementing this interface are used to operate
Expand Down Expand Up @@ -629,4 +631,14 @@ public interface TreeVisitor<R,P> {
* @return a result value
*/
R visitMatchStatement(MatchTree node, P p);

/**
* Visits an {@code MatchFailTree} node.
* @param node the node being visited
* @param p a parameter value
* @return a result value
* @since 25
*/
@PreviewFeature(feature=PreviewFeature.Feature.PATTERN_DECLARATIONS, reflective=true)
R visitMatchFailStatement(MatchFailTree node, P p);
}
Original file line number Diff line number Diff line change
Expand Up @@ -1085,5 +1085,18 @@ public R visitMatchStatement(MatchTree 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 visitMatchFailStatement(MatchFailTree node, P p) {
return defaultAction(node, p);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -1240,4 +1240,19 @@ public R visitYield(YieldTree node, P p) {
public R visitMatchStatement(MatchTree node, P p) {
return scan(node.getArguments(), p);
}

/**
* {@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 visitMatchFailStatement(MatchFailTree node, P p) {
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,10 @@ public static EnumSet<Flag> asFlagSet(long flags) {
*/
public static final long THROWS = 1L<<47;

/*
* Currently available: Bit 48.
/**
* Flag to indicate the given deconstructor is partial
*/
public static final long PARTIAL = 1L<<48; //Trees + Symbols

/**
* Flag that marks a synthetic method body for a lambda expression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1200,12 +1200,16 @@ public void visitMethodDef(JCMethodDecl tree) {
}
}

//TODO: should these checks/flag setting be done in MemberEnter?
if (m.isPattern() && tree.thrown.nonEmpty()) {
log.error(tree.pos(), Errors.PatternDeclarationCantThrowException);
}

if (m.isDeconstructor()) {
m.patternFlags.add(PatternFlags.DECONSTRUCTOR);
if ((tree.mods.flags & Flags.PARTIAL) == 0) {
m.patternFlags.add(PatternFlags.TOTAL);
}
}

// annotation method checks
Expand Down Expand Up @@ -2457,6 +2461,14 @@ public void visitMatch(JCMatch tree) {
result = null;
}

@Override
public void visitMatchFail(JCMatchFail tree) {
if ((env.enclMethod.sym.flags_field & Flags.PARTIAL) == 0) {
log.error(tree.pos(), Errors.UnmarkedPartialDeconstructor);
}
result = null;
}

public void visitTypeTestStatement(JCInstanceOfStatement tree) {
attribExpr(tree.expr, env);
attribExpr(tree.pattern, env);
Expand Down Expand Up @@ -4647,7 +4659,11 @@ private List<MethodSymbol> candidatesWithArity(Type site, int nestedPatternCount
.collect(List.collector());

PatternType pt = new PatternType(recordComponents, syms.voidType, syms.methodClass);
patternDeclarations = patternDeclarations.prepend(new MethodSymbol(PUBLIC | SYNTHETIC | PATTERN, ((ClassSymbol) site.tsym).name, pt, site.tsym));
MethodSymbol synthetized = new MethodSymbol(PUBLIC | SYNTHETIC | PATTERN, ((ClassSymbol) site.tsym).name, pt, site.tsym);

synthetized.patternFlags.add(PatternFlags.DECONSTRUCTOR);
synthetized.patternFlags.add(PatternFlags.TOTAL);
patternDeclarations = patternDeclarations.prepend(synthetized);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ private void clearPendingExits(boolean inMethod) {
while (exits.nonEmpty()) {
PendingExit exit = exits.head;
exits = exits.tail;
Assert.check((inMethod && (exit.tree.hasTag(RETURN) || exit.tree.hasTag(MATCH))) ||
Assert.check((inMethod && (exit.tree.hasTag(RETURN) || exit.tree.hasTag(MATCH) || exit.tree.hasTag(MATCHFAIL))) ||
log.hasErrorOn(exit.tree.pos()));
}
}
Expand Down Expand Up @@ -725,6 +725,10 @@ public void visitTypeTestStatement(JCInstanceOfStatement tree) {
alive = alive.or(resolveBreaks(tree, prevPendingExits));
}

public void visitMatchFail(JCMatchFail tree) {
recordExit(new PendingExit(tree));
}

public void visitForeachLoop(JCEnhancedForLoop tree) {
visitVarDef(tree.var);
ListBuffer<PendingExit> prevPendingExits = pendingExits;
Expand Down Expand Up @@ -827,6 +831,11 @@ private boolean exhausts(JCExpression selector, List<JCCase> cases) {

for (var l : c.labels) {
if (l instanceof JCPatternCaseLabel patternLabel) {
if (patternLabel.pat instanceof JCRecordPattern rec &&
rec.patternDeclaration != null &&
!rec.patternDeclaration.patternFlags.contains(PatternFlags.TOTAL)) {
continue;
}
for (Type component : components(selector.type)) {
patternSet.add(makePatternDescription(component, patternLabel.pat));
}
Expand Down Expand Up @@ -1585,6 +1594,7 @@ else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
if (!(exit instanceof ThrownPendingExit)) {
Assert.check(exit.tree.hasTag(RETURN) ||
exit.tree.hasTag(MATCH) ||
exit.tree.hasTag(MATCHFAIL) ||
log.hasErrorOn(exit.tree.pos()));
} else {
// uncaught throws will be reported later
Expand Down Expand Up @@ -1846,6 +1856,10 @@ public void visitMatch(JCMatch tree) {
recordExit(new PendingExit(tree));
}

public void visitMatchFail(JCMatchFail tree) {
recordExit(new PendingExit(tree));
}

public void visitThrow(JCThrow tree) {
scan(tree.expr);
Symbol sym = TreeInfo.symbol(tree.expr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCLambda;
import com.sun.tools.javac.tree.JCTree.JCMatchFail;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCPattern;
Expand Down Expand Up @@ -135,6 +136,7 @@ public static TransPatterns instance(Context context) {
private final Symtab syms;
private final Attr attr;
private final Resolve rs;
private final TypeEnvs typeEnvs;
private final Types types;
private final Operators operators;
private final Names names;
Expand Down Expand Up @@ -196,6 +198,7 @@ protected TransPatterns(Context context) {
syms = Symtab.instance(context);
attr = Attr.instance(context);
rs = Resolve.instance(context);
typeEnvs = TypeEnvs.instance(context);
make = TreeMaker.instance(context);
types = Types.instance(context);
operators = Operators.instance(context);
Expand Down Expand Up @@ -1043,6 +1046,11 @@ public void visitMatch(JCMatch tree) {
result = make.at(tree.pos).Block(0, stats.toList());
}

@Override
public void visitMatchFail(JCMatchFail tree) {
result = make.at(tree.pos).Return(makeNull());
}

private class PrimitiveGenerator extends Types.SignatureGenerator {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2949,6 +2949,20 @@ List<JCStatement> blockStatement() {
List<JCExpression> args = arguments();
accept(SEMI);
return List.of(toP(F.at(pos).Match(name, args)));
} else if (next.kind == SUB) {
Token nextNext = S.token(2);
if (nextNext.kind == IDENTIFIER) {
if (nextNext.name().contentEquals("fail")) {
checkSourceLevel(Feature.PATTERN_DECLARATIONS);
nextToken();
nextToken();
nextToken();
accept(LPAREN);
accept(RPAREN);
accept(SEMI);
return List.of(toP(F.at(pos).MatchFail()));
}
}
}
} else
if (token.name() == names.yield && allowYieldStatement) {
Expand Down Expand Up @@ -3627,6 +3641,7 @@ protected JCModifiers modifiersOpt(JCModifiers partial) {
case STRICTFP : flag = Flags.STRICTFP; break;
case MONKEYS_AT : flag = Flags.ANNOTATION; break;
case DEFAULT : flag = Flags.DEFAULT; break;
case CASE : flag = Flags.PARTIAL; break;
case ERROR : flag = 0; nextToken(); break;
case IDENTIFIER : {
if (isNonSealedClassStart(false)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,9 @@ compiler.err.missing.ret.stmt=\
compiler.err.missing.match.stmt=\
missing match statement

compiler.err.missing.match.stmt=\
missing match statement

# 0: type
compiler.misc.missing.ret.val=\
missing return value
Expand Down Expand Up @@ -4290,3 +4293,6 @@ compiler.warn.attempt.to.synchronize.on.instance.of.value.based.class=\
compiler.err.enclosing.class.type.non.denotable=\
enclosing class type: {0}\n\
is non-denotable, try casting to a denotable type

compiler.err.unmarked.partial.deconstructor=\
deconstructor not marked as partial, match-fail illegal
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ public enum Tag {
*/
MATCH,

/** Match fail statements, of type MatchFail.
*/
MATCHFAIL,

/** Method invocation expressions, of type Apply.
*/
APPLY,
Expand Down Expand Up @@ -1808,6 +1812,28 @@ public Tag getTag() {
}
}

/**
* The match-fail statement
*/
public static class JCMatchFail extends JCStatement implements MatchFailTree {

protected JCMatchFail() {
}
@Override
public void accept(Visitor v) { v.visitMatchFail(this); }

@DefinedBy(Api.COMPILER_TREE)
public Kind getKind() { return Kind.MATCH_FAILED; }
@Override @DefinedBy(Api.COMPILER_TREE)
public <R,D> R accept(TreeVisitor<R,D> v, D d) {
return v.visitMatchFailStatement(this, d);
}
@Override
public Tag getTag() {
return MATCHFAIL;
}
}

/**
* A continue of a loop.
*/
Expand Down Expand Up @@ -3631,6 +3657,7 @@ public abstract static class Visitor {
public void visitBreak(JCBreak that) { visitTree(that); }
public void visitYield(JCYield that) { visitTree(that); }
public void visitMatch(JCMatch that) { visitTree(that); }
public void visitMatchFail(JCMatchFail that) { visitTree(that); }
public void visitContinue(JCContinue that) { visitTree(that); }
public void visitReturn(JCReturn that) { visitTree(that); }
public void visitThrow(JCThrow that) { visitTree(that); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,13 @@ public JCTree visitMatchStatement(MatchTree node, P p) {
return M.at(t.pos).Match(t.clazz, args);
}

@DefinedBy(Api.COMPILER_TREE)
public JCTree visitMatchFailStatement(MatchFailTree node, P p) {
JCMatchFail t = (JCMatchFail) node;

return M.at(t.pos).MatchFail();
}

@DefinedBy(Api.COMPILER_TREE)
public JCTree visitCase(CaseTree node, P p) {
JCCase t = (JCCase) node;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,12 @@ public JCMatch Match(Name clazz, List<JCExpression> args) {
return tree;
}

public JCMatchFail MatchFail() {
JCMatchFail tree = new JCMatchFail();
tree.pos = pos;
return tree;
}

public JCMethodInvocation Apply(List<JCExpression> typeargs,
JCExpression fn,
List<JCExpression> args)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ public void visitMatch(JCMatch tree) {
scan(tree.args);
}

public void visitMatchFail(JCMatchFail tree) {
}

public void visitContinue(JCContinue tree) {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@ public void visitMatch(JCMatch tree) {
result = tree;
}

@Override
public void visitMatchFail(JCMatchFail tree) {
result = tree;
}

public void visitContinue(JCContinue tree) {
result = tree;
}
Expand Down
Loading