-
Notifications
You must be signed in to change notification settings - Fork 163
Fix compile error with final field assignment in constructor with prologue in local class in constructor #4701
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
Fix compile error with final field assignment in constructor with prologue in local class in constructor #4701
Conversation
f0b0f26 to
962c1d9
Compare
|
Two previous Jenkins build silently did nothing... I've manually triggered Jenkins build https://ci.eclipse.org/jdt/job/eclipse.jdt.core-Github/job/PR-4701/3/console If the problem persists, please file a ticket at https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/issues/ or ping me here. |
| AbstractMethodDeclaration method = this.methods[i]; | ||
| if (method.isConstructor()) { | ||
| FlowInfo ctorInfo = flowInfo.copy(); | ||
| FlowInfo ctorInfo = flowInfo.unconditionalFieldLessCopy(); |
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.
Cool, this effectively fixes the issue, but something smells strangely here: the flow info that produced the bogus error concerned the field a of the outer class, i.e., we were actually misinterpreting the field index 0.
@coehlrich do you think we can streamline this code section wrt field of the enclosing class? See this comment few lines above:
// discards info about fields of inclosing classes
Given that no analysis within the current type should bother about fields of the enclosing class (?), could we find a single location for calling unconditionalFieldLessCopy() once and for all?
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.
Currently internalAnalyseCode uses flowInfo without calling unconditionalFieldLessCopy in 5 locations:
- 2 times as arguments for
InitializationFlowContextwhich only uses it ingetInitsForFinalBlankInitializationCheckwhich also looks for the correct parent before returning the correspondingFlowInfo - 2 times for calls to
reachModewhich is copied when callingunconditionalFieldLessCopy - 1 time as an argument when calling
analyseCodeon all methods that aren't for initialization
None of the regression tests failed when adding flowInfo = flowInfo.unconditionalFieldLessCopy() to the top of internalAnalyseCode
While looking into this I did also notice that constructors with prologues aren't checked to see if all of the blank final fields have been initialized
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.
all uses of the methods relating to fields in FlowInfo in ast either only look at fields in the same class or have a check for if the current class is the same as the one containing the field with some also only calling it on the output of getInitsForFinalBlankInitializationCheck. for subclasses of FlowContext I couldn't get it to recognize final field assignments for the outer class in finally blocks or in the condition of a while loop (which still did give a compile error).
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.
Code change looks good to me ...
for subclasses of
FlowContextI couldn't get it to recognize final field assignments for the outer class in finally blocks or in the condition of a while loop (which still did give a compile error).
Are you saying the fix still isn't complete? If so can you give an example?
Otherwise please explain the implications of your observation :)
Also by merging #4721 I created a conflict in the test class. Please resolve it, thanks.
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.
@coehlrich did you see my latest comment above?
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.
For
FinallyFlowContextandLoopingFlowContextthose classes only check bindings fromrecordFinalAssignmentwhich is called byrecordSettingFinalwhich is only being called right beforeFlowInfo.markAsDefinitelyAssignedifFlowInfo.isPotentiallyAssignedreturns false.
What is the impact of this observation? Do you see a bug?
if FlowInfo.isPotentiallyAssigned() returns true at the point before an assignment, we already report an error. What else do we need to pay attention to?
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.
@coehlrich how can we bring this discussion to a conclusion? I still haven't understood if you still see a problem.
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.
recordSettingFinal is only called with a field in cases where allowBlankFinalFieldAssigned returns true which checks if the current class is the same class as the one that directly contains the field so FinallyFlowContext and LoopingFlowerContext can't check fields from an enclosing class.
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.
Does this observation allow you to create a failing test?
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.
recordSettingFinalis only called with a field in cases whereallowBlankFinalFieldAssignedreturns true which checks if the current class is the same class as the one that directly contains the field soFinallyFlowContextandLoopingFlowerContextcan't check fields from an enclosing class.
I finally found the time to check myself, if this lets me identify a bug. So for the case of fields from an enclosing class allowBlankFinalFieldAssigned() returns false, correct. This implies that in such cases we'll never invoke flowContext.recordSettingFinal() regardless of the type of flow context.
But the above false directly catapults us into the else branch reading like this:
} else {
currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
}So this case is reported as an error without further consultation of flow info nor flow context.
Adding your remark about getInitsForFinalBlankInitializationCheck() we seem to be in the business of reporting missing initialization? But in those cases we are always below a check needBlankFinalFieldInitializationCheck() to the effect that we only ever complain about missing assignments for fields of the current class, which indeed is the right thing to do, as assignment-to-final is the sole responsibility of the class declaring the field.
So, thanks for checking left and right regarding the handling of fields from enclosing classes. If you still see a problem please speak up. Otherwise I will just refresh the branch, add one more test and try to get it merged before tomorrow's M3.
840812c to
e2dd748
Compare
|
Jenkins had another issue with building this PR. For a while after the builds failed the https://ci.eclipse.org/jdt/ was timing out while https://ci.eclipse.org was fine. |
e2dd748 to
89af88c
Compare
prologue in local class in constructor
+ preserve (move) previous code comment + add a test with assignment to outer-field from finally
89af88c to
1b01370
Compare
|
Thanks, @coehlrich ! |
What it does
Fixes #4700
How to test
Attempt to compile
Author checklist