-
Notifications
You must be signed in to change notification settings - Fork 129
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
[Switch][Record Patterns] Unchecked conversion error missing from ECJ #3069
base: master
Are you sure you want to change the base?
Conversation
@srikanth-sankaran please have a look at the different parties involved in compatibility checking for (record) patterns. Quite likely the code can be simplified by being more explicit about which part is responsible for which aspect of checking. |
scope.problemReporter().incompatiblePatternType(this, other, patternType); | ||
return false; | ||
} else { | ||
if (!checkCastTypesCompatibility(scope, patternType, other, null, true)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see the swap of arguments?
Thanks for the quick follow up Stephan. I'll review this Monday first thing - tomorrow is a holiday in India. Not just a regular holiday but one where you are not supposed to use any tools of your trade! 😊 (https://en.m.wikipedia.org/wiki/Ayudha_Puja) And after I wrap up #2720 early next week I’ll join you in the grammar work in full earnest. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am happy to look over once the current set of feedback is addressed.
Still feel it is a bit of a smell that we have in CaseStatement this:
if (expressionType != TypeBinding.NULL && !(e instanceof RecordPattern)) {
There is something in the flow that could be adjusted so we don't have to have this check for type test patterns alone - what obviates it for record patterns, why doesn't the same thing obviate it for non-record patterns too ? Don't know yet
@@ -277,6 +277,9 @@ public TypeBinding resolveType(BlockScope scope) { | |||
if (expressionType == null || checkedType == null) | |||
return null; | |||
|
|||
if (this.pattern instanceof RecordPattern) // subsequent tests are not relevant for RecordPatterns | |||
return this.resolvedType = TypeBinding.BOOLEAN; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks ok. However the short circuited code has a tendency to mischaracterize a type incompatibility as an unsafe cast. I have raised a separate ticket for that. See #3074
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reworked in df50953 - do you like it better now?
return false; | ||
} | ||
applicable = false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way this is coded it appears there could be a scenario where the cast is illegal but also unsafe. I doubt that to be valid ever.
If I change applicable = false;
to be return applicable = false;
I don't see any test failing.
If this is a valid observation, it could allow for some simplification of the code by we could get rid of the new variable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reworked in df50953 - do you like it better now?
case X<String>(int x): | ||
^^^^^^^^^^^^^^^^ | ||
Type X<String> cannot be safely cast to Object | ||
---------- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks backwards - no ? The error is that Object cannot be safely cast to X and not the other way around ??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ups, right, we keep confusing ourselves by naming parameters as "right" and "left", which was ok-ish, while only one syntax was involved, but in pattern matching, where is right, where is left??
(ironically, I just fixed the same kind of bug a few lines up, and then introduced a new instanced of the bug here).
Next commit will include a bit of renaming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in bc53322
" ^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + | ||
"Incompatible conditional operand types R<capture#1-of ? extends I> and R\n" + | ||
" ^^^^^^^^^^^^^\n" + | ||
"Type mismatch: cannot convert from R<capture#1-of ? extends I> to R\n" + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test doesn't compile with javac so unable to verify behavior - bug in javac
I get:
X.java:10: error: illegal start of type
if (p instanceof R<>(String a)) {
^
1 error
@srikanth-sankaran after my first commit focused on (local) correctness, in df50953 I made an attempt to define a basic rule for assigning responsibilities:
I could imagine that this can be taken even one step further. There are still differences between I also slightly unified problem reporting: let the problem reporter select the problemID based on the error location rather than defining separate reporting methods. As one effect this allowed me to remove a reporting method, which was a bit sloppy with short vs long readable names. I'm not yet 100% convinced of the idea to share Let me know if you like better now, or if you see potential for further clarification. |
Yes, this is on my radar. I will review this before tomorrow. Thanks for your patience. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good - except for the minor points called out.
leftShortName = leftName; | ||
rightShortName = rightName; | ||
int problemId = IProblem.IncompatibleTypesInEqualityOperator; // name is misleading, also used for instanceof patterns | ||
if (location instanceof Pattern p && p.getEnclosingPattern() instanceof RecordPattern) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the comment about the name IncompatibleTypesInEqualityOperator
being misleading valid ?? 4 lines down we seems to be overriding with IncompatibleTypesInConditionalOperator
??
It would seem the choice of emission of IncompatibleTypesInConditionalOperator
by org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression.checkForPrimitives(BlockScope, TypeBinding, TypeBinding)
via a call to org.eclipse.jdt.internal.compiler.problem.ProblemReporter.notCompatibleTypesError(Expression, TypeBinding, TypeBinding)
is the source of confusion. See also the comment in PIPTSH.java
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, the comment looks a bit stale, but the general question stays: is it appropriate to use problem ids designed for conditional expression and equality expression when reporting problems of pattern matching?
I'll remove the comment and raise a new issue for that discussion.
"3. ERROR in X.java (at line 9)\n" + | ||
" case List<String> s: \n" + | ||
" ^^^^^^^^^^^^^^\n" + | ||
"This case label is dominated by one of the preceding case labels\n" + | ||
"----------\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gather this diagnostic going away is because of the early exit in CaseStatement ? If so, OK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, when isApplicable()
returns false, we've seen enough, resolveCasePattern()
returns NotAConstant
, hence no ResolvedCase
is created and SwitchStatement.resolve()
has nothing to check dominance for.
Incompatible conditional operand types X and int | ||
---------- | ||
"""); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I so much like javac's message : incompatible types: X cannot be converted to int
- I don't know where this conditional operand types terminology originated but I am OK with that staying and perhaps being taken up separately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'conditional operand types' has been in use for instanceof expressions for at least very very long time (like: for ever?), see, e.g., org.eclipse.jdt.core.tests.compiler.regression.CastTest.test027()
I filed #3119 for follow-up.
+ try to balance responsibility about type checking between - Pattern.isApplicable() - don't yet report in nested position - RecordPattern.resolveType() - failed to check isApplicable() - InstanceOfExpression.resolveType() - avoid pattern-agnostic checks + added the 1st(!) test for inapplicable record pattern in switch
+ enclosing instanceof and case stmt are responsible for its invocation + make isApplicable() more capable to issue the desired problems + let problem reporter see the error location to select problemID + more renaming for clarity Test changes: + compatibility errors more consistently mark the entire instanceof expr + remove unwanted type qualifiers + don't expect some secondary errors
f80e7ba
to
7e73c2b
Compare
try to balance responsibility about type checking between
added the 1st(!) test for inapplicable record pattern in switch
fixes #3066