Skip to content
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

8282274: Compiler implementation for Pattern Matching for switch (Third Preview) #8182

Closed
wants to merge 26 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b47f6c0
Moving guards to switches.
lahodaj Feb 10, 2022
2f02c93
Moving guards to cases.
lahodaj Feb 11, 2022
e92ca08
Updating null handling.
lahodaj Feb 11, 2022
78a3fb2
Merge branch 'case-guard' into type-patterns-third
lahodaj Mar 18, 2022
5e0f558
Merge branch 'switch-null' into type-patterns-third
lahodaj Mar 18, 2022
757924e
Adding MatchException.
lahodaj Apr 1, 2022
66b4f01
Merge branch 'master' into type-patterns-third
lahodaj Apr 4, 2022
5d55161
Guards should be a property of (pattern) case labels, not cases.
lahodaj Apr 7, 2022
8c1b413
Merge branch 'master' into type-patterns-third
lahodaj Apr 7, 2022
3eba02a
Cleanup
lahodaj Apr 11, 2022
da8401d
Adding a test for a NPE from guards.
lahodaj Apr 11, 2022
d7e2eb0
Fixing tests.
lahodaj Apr 12, 2022
ef7a7d6
Cleanup.
lahodaj Apr 12, 2022
311d68a
Adjusting to review feedback.
lahodaj Apr 18, 2022
dc00154
Cleanup - more total -> unconditional pattern renaming.
lahodaj Apr 19, 2022
76f2d05
Cleanup, fixing tests.
lahodaj Apr 21, 2022
2e27be0
Merge branch 'master' into type-patterns-third
lahodaj Apr 22, 2022
9f290cd
Reference-type pattern is not applicable at a selector of a primitive…
lahodaj Apr 26, 2022
a4ac056
Merge branch 'master' into type-patterns-third
lahodaj Apr 27, 2022
115605a
Reducing MatchException constructors.
lahodaj Apr 28, 2022
cb5c1d2
Merge branch 'master' into type-patterns-third
lahodaj May 3, 2022
1101ad4
Merge branch 'master' into type-patterns-third
lahodaj May 9, 2022
9fe0a1d
Case label elements cannot be unguarded if they have a guard of a typ…
lahodaj May 12, 2022
b0fb8dc
Updating naming to more closely follow the spec: total patterns are r…
lahodaj May 12, 2022
e903084
Cleanup as suggested on the PR review.
lahodaj May 13, 2022
2299195
Fixing test - restoring accidentally removed condition.
lahodaj May 16, 2022
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
27 changes: 14 additions & 13 deletions src/java.base/share/classes/java/lang/MatchException.java
Original file line number Diff line number Diff line change
@@ -30,16 +30,17 @@
/**
* Thrown to indicate an unexpected failure in pattern matching.
*
* MatchException may be thrown when an exhaustive pattern matching language construct
* (such as a switch expression) encounters a match target that does not match any of the provided
* patterns at runtime. This can currently arise from the following case:
* <ul>
* <li>Separate compilation anomalies, where a sealed interface has a different
* set of permitted subtypes at runtime than it had at compilation time,
* an enum has a different set of constants at runtime than it had at compilation time,
* or the type hierarchy has changed in incompatible ways between compile time and run time.
* </li>
* </ul>
* {@code MatchException} may be thrown when an exhaustive pattern matching language construct
* (such as a switch expression) encounters a value that does not match any of the provided
* patterns at runtime. This can currently arise for separate compilation anomalies,
* where a sealed interface has a different set of permitted subtypes at runtime than
* it had at compilation time, an enum has a different set of constants at runtime than
* it had at compilation time, or the type hierarchy has changed in incompatible ways between
* compile time and run time.
*
* @jls 14.11.3 Execution of a switch Statement
* @jls 14.30.2 Pattern Matching
* @jls 15.28.2 Run-Time Evaluation of switch Expressions
*
* @since 19
*/
@@ -49,7 +50,7 @@ public class MatchException extends RuntimeException {
private static final long serialVersionUID = 0L;

/**
* Constructs an {@code MatchException} with no detail message.
* Constructs an {@code MatchException} with no detail message.
*/
public MatchException() {
super();
@@ -70,7 +71,7 @@ public MatchException(String message) {
* Constructs an {@code MatchException} with the specified cause.
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
*/
@@ -85,7 +86,7 @@ public MatchException(Throwable cause) {
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks odd - it seems like the sentence is like this:

the cause ( foo ). (bar). E.g. the test in parenthesis exceeds the test outside parenthesis by a wide margin. I suggest both here and in the "message" @param to avoid the parenthesis and split the sentence instead. Examples:

* @param  message the detail message. The message is saved for later retrieval
*  by the {@link #getMessage()} method).

and

* @param cause the cause. The cause is saved for later retrieval by the
*  {@link #getCause()} method). A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.

Of course this is just an idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this text is taken form another exception in java.lang. If that would be OK, I'd look at this in a followup/separate issue.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok!

* {@link #getCause()} method). (A {@code null} value is
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
*/
Original file line number Diff line number Diff line change
@@ -187,7 +187,7 @@ public boolean isPreview(Feature feature) {
return switch (feature) {
case CASE_NULL -> true;
case PATTERN_SWITCH -> true;
case TOTAL_PATTERN_IN_INSTACEOF -> true;
case UNCONDITIONAL_PATTERN_IN_INSTANCEOF -> 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'
Original file line number Diff line number Diff line change
@@ -239,7 +239,7 @@ public enum Feature {
CASE_NULL(JDK17, Fragments.FeatureCaseNull, DiagKind.NORMAL),
PATTERN_SWITCH(JDK17, Fragments.FeaturePatternSwitch, DiagKind.PLURAL),
REDUNDANT_STRICTFP(JDK17),
TOTAL_PATTERN_IN_INSTACEOF(JDK17, Fragments.FeatureTotalPatternsInInstanceof, DiagKind.PLURAL),
UNCONDITIONAL_PATTERN_IN_INSTANCEOF(JDK17, Fragments.FeatureTotalPatternsInInstanceof, DiagKind.PLURAL),
;

enum DiagKind {
Original file line number Diff line number Diff line change
@@ -174,8 +174,8 @@ protected Attr(Context context) {
allowRecords = Feature.RECORDS.allowedInSource(source);
allowPatternSwitch = (preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH)) &&
Feature.PATTERN_SWITCH.allowedInSource(source);
allowTotalPatternsInstance = (preview.isEnabled() || !preview.isPreview(Feature.TOTAL_PATTERN_IN_INSTACEOF)) &&
Feature.TOTAL_PATTERN_IN_INSTACEOF.allowedInSource(source);
allowUnconditionalPatternsInstance = (preview.isEnabled() || !preview.isPreview(Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF)) &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: perhaps adding "Of" to this already long variable name doesn't add much in terms of chars, but makes the meaning of the variable name clearer?

Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF.allowedInSource(source);
sourceName = source.name;
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");

@@ -222,7 +222,7 @@ protected Attr(Context context) {

/** Are total patterns in instanceof allowed
*/
private final boolean allowTotalPatternsInstance;
private final boolean allowUnconditionalPatternsInstance;

/**
* Switch: warn about use of variable before declaration?
@@ -1794,7 +1794,7 @@ private void handleSwitch(JCTree switchTree,
}
matchBindings = matchBindingsComputer.caseGuard(c, afterPattern, matchBindings);
}
boolean unconditional = TreeInfo.unconditionalCaseLabel(pat);
boolean unconditional = TreeInfo.unrefinedCaseLabel(pat);
boolean isTotal = unconditional &&
!patternType.isErroneous() &&
types.isSubtype(types.erasure(seltype), patternType);
@@ -4109,10 +4109,10 @@ public void visitTypeTest(JCInstanceOf tree) {
clazztype = tree.pattern.type;
if (types.isSubtype(exprtype, clazztype) &&
!exprtype.isErroneous() && !clazztype.isErroneous()) {
if (!allowTotalPatternsInstance) {
if (!allowUnconditionalPatternsInstance) {
log.error(tree.pos(), Errors.InstanceofPatternNoSubtype(exprtype, clazztype));
} else if (preview.isPreview(Feature.TOTAL_PATTERN_IN_INSTACEOF)) {
preview.warnPreview(tree.pattern.pos(), Feature.TOTAL_PATTERN_IN_INSTACEOF);
} else if (preview.isPreview(Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF)) {
preview.warnPreview(tree.pattern.pos(), Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF);
}
}
typeTree = TreeInfo.primaryPatternTree((JCPattern) tree.pattern).var.vartype;
Original file line number Diff line number Diff line change
@@ -671,7 +671,7 @@ public void visitSwitch(JCSwitch tree) {
JCCase c = l.head;
for (JCCaseLabel pat : c.labels) {
scan(pat);
if (TreeInfo.unconditionalCaseLabel(pat)) {
if (TreeInfo.unrefinedCaseLabel(pat)) {
handleConstantCaseLabel(constants, pat);
}
}
@@ -714,7 +714,7 @@ public void visitSwitchExpression(JCSwitchExpression tree) {
JCCase c = l.head;
for (JCCaseLabel pat : c.labels) {
scan(pat);
if (TreeInfo.unconditionalCaseLabel(pat)) {
if (TreeInfo.unrefinedCaseLabel(pat)) {
handleConstantCaseLabel(constants, pat);
}
}
Original file line number Diff line number Diff line change
@@ -1346,7 +1346,7 @@ public static boolean isErrorEnumSwitch(JCExpression selector, List<JCCase> case

public static PatternPrimaryType primaryPatternType(JCTree pat) {
return switch (pat.getTag()) {
case BINDINGPATTERN -> new PatternPrimaryType(((JCBindingPattern) pat).type);
case BINDINGPATTERN -> new PatternPrimaryType(pat.type);
case PARENTHESIZEDPATTERN -> primaryPatternType(((JCParenthesizedPattern) pat).pattern);
default -> throw new AssertionError();
};
@@ -1369,7 +1369,7 @@ public static boolean expectedExhaustive(JCSwitch tree) {
.anyMatch(l -> TreeInfo.isNull(l));
}

public static boolean unconditionalCaseLabel(JCCaseLabel cse) {
public static boolean unrefinedCaseLabel(JCCaseLabel cse) {
if (!cse.isPattern()) {
return true;
}