[ 
https://issues.apache.org/jira/browse/GROOVY-12466?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18130712#comment-18130712
 ] 

ASF GitHub Bot commented on GROOVY-12466:
-----------------------------------------

codecov-commenter commented on PR #3011:
URL: https://github.com/apache/groovy/pull/3011#issuecomment-6358739920

   ## 
[Codecov](https://app.codecov.io/gh/apache/groovy/pull/3011?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 Report
   :x: Patch coverage is `80.00000%` with `1 line` in your changes missing 
coverage. Please review.
   :white_check_mark: Project coverage is 72.4381%. Comparing base 
([`8d2980f`](https://app.codecov.io/gh/apache/groovy/commit/8d2980fd1249cb24b22b91524a4ad71c2c25fb45?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache))
 to head 
([`e744b99`](https://app.codecov.io/gh/apache/groovy/commit/e744b99ec54829a3d873409118f588aa4da802bd?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)).
   :warning: Report is 2 commits behind head on master.
   
   | [Files with missing 
lines](https://app.codecov.io/gh/apache/groovy/pull/3011?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 | Patch % | Lines |
   |---|---|---|
   | 
[...us/groovy/classgen/asm/BinaryExpressionHelper.java](https://app.codecov.io/gh/apache/groovy/pull/3011?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Forg%2Fcodehaus%2Fgroovy%2Fclassgen%2Fasm%2FBinaryExpressionHelper.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3JjL21haW4vamF2YS9vcmcvY29kZWhhdXMvZ3Jvb3Z5L2NsYXNzZ2VuL2FzbS9CaW5hcnlFeHByZXNzaW9uSGVscGVyLmphdmE=)
 | 0.0000% | [0 Missing and 1 partial :warning: 
](https://app.codecov.io/gh/apache/groovy/pull/3011?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 |
   
   <details><summary>Additional details and impacted files</summary>
   
   
   
   [![Impacted file tree 
graph](https://app.codecov.io/gh/apache/groovy/pull/3011/graphs/tree.svg?width=650&height=150&src=pr&token=1r45138NfQ&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)](https://app.codecov.io/gh/apache/groovy/pull/3011?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
   
   ```diff
   @@                Coverage Diff                 @@
   ##               master      #3011        +/-   ##
   ==================================================
   - Coverage     72.4417%   72.4381%   -0.0036%     
     Complexity      40682      40682                
   ==================================================
     Files            1644       1644                
     Lines          142897     142900         +3     
     Branches        26877      26880         +3     
   ==================================================
   - Hits           103517     103514         -3     
   - Misses          29825      29826         +1     
   - Partials         9555       9560         +5     
   ```
   
   | [Files with missing 
lines](https://app.codecov.io/gh/apache/groovy/pull/3011?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 | Coverage Δ | |
   |---|---|---|
   | 
[...ehaus/groovy/classgen/ClassCompletionVerifier.java](https://app.codecov.io/gh/apache/groovy/pull/3011?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Forg%2Fcodehaus%2Fgroovy%2Fclassgen%2FClassCompletionVerifier.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3JjL21haW4vamF2YS9vcmcvY29kZWhhdXMvZ3Jvb3Z5L2NsYXNzZ2VuL0NsYXNzQ29tcGxldGlvblZlcmlmaWVyLmphdmE=)
 | `85.0000% <100.0000%> (+0.0268%)` | :arrow_up: |
   | 
[...codehaus/groovy/classgen/VariableScopeVisitor.java](https://app.codecov.io/gh/apache/groovy/pull/3011?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Forg%2Fcodehaus%2Fgroovy%2Fclassgen%2FVariableScopeVisitor.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3JjL21haW4vamF2YS9vcmcvY29kZWhhdXMvZ3Jvb3Z5L2NsYXNzZ2VuL1ZhcmlhYmxlU2NvcGVWaXNpdG9yLmphdmE=)
 | `94.1781% <100.0000%> (ø)` | |
   | 
[...dehaus/groovy/classgen/asm/indy/IndyBinHelper.java](https://app.codecov.io/gh/apache/groovy/pull/3011?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Forg%2Fcodehaus%2Fgroovy%2Fclassgen%2Fasm%2Findy%2FIndyBinHelper.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3JjL21haW4vamF2YS9vcmcvY29kZWhhdXMvZ3Jvb3Z5L2NsYXNzZ2VuL2FzbS9pbmR5L0luZHlCaW5IZWxwZXIuamF2YQ==)
 | `96.9697% <100.0000%> (+0.0947%)` | :arrow_up: |
   | 
[...us/groovy/classgen/asm/BinaryExpressionHelper.java](https://app.codecov.io/gh/apache/groovy/pull/3011?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Forg%2Fcodehaus%2Fgroovy%2Fclassgen%2Fasm%2FBinaryExpressionHelper.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3JjL21haW4vamF2YS9vcmcvY29kZWhhdXMvZ3Jvb3Z5L2NsYXNzZ2VuL2FzbS9CaW5hcnlFeHByZXNzaW9uSGVscGVyLmphdmE=)
 | `89.0688% <0.0000%> (-0.1204%)` | :arrow_down: |
   
   ... and [12 files with indirect coverage 
changes](https://app.codecov.io/gh/apache/groovy/pull/3011/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
   </details>
   <details><summary> :rocket: New features to boost your workflow: </summary>
   
   - :snowflake: [Test 
Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, 
report on failures, and find test suite problems.
   - :package: [JS Bundle 
Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save 
yourself from yourself by tracking and limiting bundle sizes in JS merges.
   </details>




> GEP-15: compound assignment that resolves to a *Assign method is refused for 
> final parameters and for final fields used inside their own class
> ----------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12466
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12466
>             Project: Groovy
>          Issue Type: Bug
>          Components: Compiler, Static Type Checker
>    Affects Versions: 6.0.0
>            Reporter: Paul King
>            Assignee: Paul King
>            Priority: Major
>
> h2. Problem
> GEP-15 lets a class define {{plusAssign}}, {{minusAssign}}, 
> {{leftShiftAssign}} and the other {{*Assign}} methods. The 6.0 documentation 
> (core-operators, "compound assignment") says that when the compiler resolves 
> such a method statically, the receiver "is mutated in place, no reassignment 
> occurs (so {{final}} fields and variables can use compound assignment in that 
> case)". That holds for final local variables and for final fields reached 
> from outside their class. It does not hold for final parameters, or for final 
> fields used inside their own class:
> {code:groovy}
> @CompileStatic
> class Acc {
>     int total
>     void plusAssign(int v) { total += v }
> }
> @CompileStatic
> class H {
>     final Acc acc = new Acc()
>     int viaField() { acc += 1; acc.total }          // error: cannot modify 
> final field 'acc' outside of constructor.
>     int viaThis() { this.acc += 1; acc.total }      // error: cannot modify 
> final field 'acc' outside of constructor.
>     static int viaParam(final Acc a) { a += 1; a.total }  // error: Cannot 
> assign a value to final variable 'a'
>     static int viaLocal(Acc x) { final Acc a = x; a += 1; a.total }  // 
> compiles and runs: 1
> }
> @CompileStatic
> int outside() { def h = new H(); h.acc += 1; h.acc.total }  // compiles and 
> runs: 1
> {code}
> Results on 6.0.0:
> ||Target of {{+= 1}}||@CompileStatic||@TypeChecked||dynamic||
> |final local variable|compiles, runs|compiles, runs|refused (expected)|
> |final field from outside ({{h.acc}})|compiles, runs|compiles, runs|n/a|
> |final field inside its class ({{acc}} or 
> {{this.acc}})|*refused*|*refused*|refused (expected)|
> |final parameter|*refused*|*refused*|refused (expected)|
> The dynamic rows are expected. The documentation says the final check cannot 
> be relaxed there, because the compiler doesn't know whether a {{*Assign}} 
> method will respond at runtime. The {{CompoundAssignmentTest}} cases cover 
> the final local and the outside-field forms, but not these two.
> h2. Cause
> Two checks reject the assignment without considering the {{*Assign}} target 
> that static type checking records in 
> {{StaticTypesMarker.COMPOUND_ASSIGN_TARGET}}:
> * *Final parameters:* {{VariableScopeVisitor.checkFinalFieldAccess}} reports 
> "Cannot assign a value to final variable" for any assignment operator whose 
> target is a final {{Parameter}}. It runs during semantic analysis, before 
> type checking, so it cannot know whether a {{*Assign}} method will be found. 
> The later check in {{Verifier}} (the {{FinalVariableAnalyzer}} callback) 
> already skips expressions carrying {{COMPOUND_ASSIGN_TARGET}}, for parameters 
> as well as locals, but is never reached.
> * *Final fields:* {{ClassCompletionVerifier.checkFinalFieldAccess}} reports 
> "cannot modify final field ... outside of constructor" for any assignment 
> operator whose target is a final field named directly or through {{this}}. It 
> runs after type checking, so the marker is available, but it is not 
> consulted. A field reached through another object ({{h.acc}}) passes only 
> because this check ignores properties on anything other than {{this}}.
> h2. Proposed fix
> * In {{VariableScopeVisitor}}, report final parameters only for plain 
> assignment ({{=}}). Leave compound operators on final parameters to the 
> {{FinalVariableAnalyzer}} check in {{Verifier}}, which already reports "The 
> parameter \[a\] is declared final but is reassigned" when no {{*Assign}} 
> target was resolved, in dynamic code or when the type has no such method. The 
> error is still reported in those cases, with that message instead of the 
> current one.
> * In {{ClassCompletionVerifier}}, skip the final-field error when the 
> assignment's {{BinaryExpression}} carries {{COMPOUND_ASSIGN_TARGET}}. The 
> check currently receives only the left-hand expression, so it needs the 
> binary expression passed in as well.
> * Confirm that code generation emits no field store or local store for these 
> cases, in both static code generation and the classic code generation used by 
> {{@TypeChecked}}. A store to a final field outside a constructor would fail 
> bytecode verification. The final-local and outside-field cases show the 
> call-only path already works.
> h2. Tests
> Extend {{CompoundAssignmentTest}}:
> * Final parameter with {{plusAssign}}, under {{@CompileStatic}} and 
> {{@TypeChecked}}: compiles, mutates the argument in place, and does not 
> rebind the parameter.
> * Final instance field and final static field, used by simple name and 
> through {{this}} inside their own class: compiles and mutates in place.
> * {{leftShiftAssign}} and an {{@OperatorRename}}-renamed {{*Assign}} method, 
> for the same targets.
> * Still refused: the same forms in dynamic code; a type with only {{plus}} 
> and no {{plusAssign}}; plain {{=}} to a final parameter or field outside a 
> constructor.
> * Still allowed: assignment to a final field inside a constructor.
> h2. Related
> Found while checking PurityChecker against GEP-15 operators. That is a 
> separate ticket: PurityChecker does not treat {{a += v}} that resolves to 
> {{plusAssign}} as a mutation of {{a}}.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to