[ 
https://issues.apache.org/jira/browse/GROOVY-12513?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Scott Murphy Heiberg updated GROOVY-12513:
------------------------------------------
    Description: 
When a variable is declared with a class that has a private field, and the 
variable is assigned an instance of a subclass, the type checker uses the 
narrowed type for the field and rejects it, although the declared type has the 
field. A private method of the same class is accepted through the same variable:

{code:groovy}
@groovy.transform.CompileStatic
class Outer {
    static class Box {
        private String f = 'f'
        private String im() { 'im' }
    }
    static class Sub extends Box { }
    static test() {
        Box b = new Sub()
        b.im() + b.f
    }
}
Outer.test()
{code}

{code}
[Static type checking] - No such property: f for class: Outer$Sub
{code}

Through a parameter declared as {{Box}}, the same {{b.f}} compiles under 
{{@CompileStatic}} and returns {{f}} for a {{Sub}}. javac accepts {{Box b = new 
Sub(); b.f}} (the static type of {{b}} is {{Box}}, which declares {{f}}), and 
also a write to it.

The same happens under {{@TypeChecked}}, for a write ({{b.f = 'w'}}), a 
compound assignment ({{b.f += 'x'}}), a private getter used as a property 
({{b.x}} with {{private String getX()}}: "No such property: x for class: 
Outer$Sub"), attribute access ({{b.@f}}: "Cannot access field: f of class: 
Outer$Box"), inside a closure or lambda, and when a {{Box}} parameter is 
narrowed by {{if (b instanceof Sub)}}. Seen in 5.0.8, 6.0.0 and master.

Dynamic Groovy throws {{MissingPropertyException}} for {{b.f}} whenever the 
run-time class is {{Sub}}, also for the parameter, because it looks at the 
run-time class; {{@TypeChecked}} dispatches the property access dynamically and 
therefore does the same at run time once it compiles.

Expected: like a private method, a private field or accessor of the variable's 
declared type is accessible through the variable, from every class that may 
access the member, even when flow typing narrows the variable to a subclass. A 
receiver whose type is only the subclass ({{new Sub().f}}, or a {{def}} 
variable) stays rejected, because a private member is not inherited.

PR: https://github.com/apache/groovy/pull/3044

  was:
When a variable is declared with a class that has a private field, and the 
variable is assigned an instance of a subclass, the type checker uses the 
narrowed type for the field and rejects it, although the declared type has the 
field. A private method of the same class is accepted through the same variable:

{code:groovy}
@groovy.transform.CompileStatic
class Outer {
    static class Box {
        private String f = 'f'
        private String im() { 'im' }
    }
    static class Sub extends Box { }
    static test() {
        Box b = new Sub()
        b.im() + b.f
    }
}
Outer.test()
{code}

{code}
[Static type checking] - No such property: f for class: Outer$Sub
{code}

Through a parameter declared as {{Box}}, the same {{b.f}} compiles under 
{{@CompileStatic}} and returns {{f}} for a {{Sub}}. javac accepts {{Box b = new 
Sub(); b.f}} (the static type of {{b}} is {{Box}}, which declares {{f}}), and 
also a write to it.

The same happens under {{@TypeChecked}}, for a write ({{b.f = 'w'}}), a 
compound assignment ({{b.f += 'x'}}), a private getter used as a property 
({{b.x}} with {{private String getX()}}: "No such property: x for class: 
Outer$Sub"), attribute access ({{b.@f}}: "Cannot access field: f of class: 
Outer$Box"), inside a closure or lambda, and when a {{Box}} parameter is 
narrowed by {{if (b instanceof Sub)}}. Seen in 5.0.8, 6.0.0 and master.

Dynamic Groovy throws {{MissingPropertyException}} for {{b.f}} whenever the 
run-time class is {{Sub}}, also for the parameter, because it looks at the 
run-time class; {{@TypeChecked}} dispatches the property access dynamically and 
therefore does the same at run time once it compiles.

Expected: like a private method, a private field or accessor of the variable's 
declared type is accessible through the variable, from every class that may 
access the member, even when flow typing narrows the variable to a subclass. A 
receiver whose type is only the subclass ({{new Sub().f}}, or a {{def}} 
variable) stays rejected, because a private member is not inherited.


> STC: private field of a variable's declared type is not accessible when flow 
> typing narrows the variable to a subclass
> ----------------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12513
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12513
>             Project: Groovy
>          Issue Type: Bug
>          Components: Static Type Checker
>    Affects Versions: 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> When a variable is declared with a class that has a private field, and the 
> variable is assigned an instance of a subclass, the type checker uses the 
> narrowed type for the field and rejects it, although the declared type has 
> the field. A private method of the same class is accepted through the same 
> variable:
> {code:groovy}
> @groovy.transform.CompileStatic
> class Outer {
>     static class Box {
>         private String f = 'f'
>         private String im() { 'im' }
>     }
>     static class Sub extends Box { }
>     static test() {
>         Box b = new Sub()
>         b.im() + b.f
>     }
> }
> Outer.test()
> {code}
> {code}
> [Static type checking] - No such property: f for class: Outer$Sub
> {code}
> Through a parameter declared as {{Box}}, the same {{b.f}} compiles under 
> {{@CompileStatic}} and returns {{f}} for a {{Sub}}. javac accepts {{Box b = 
> new Sub(); b.f}} (the static type of {{b}} is {{Box}}, which declares {{f}}), 
> and also a write to it.
> The same happens under {{@TypeChecked}}, for a write ({{b.f = 'w'}}), a 
> compound assignment ({{b.f += 'x'}}), a private getter used as a property 
> ({{b.x}} with {{private String getX()}}: "No such property: x for class: 
> Outer$Sub"), attribute access ({{b.@f}}: "Cannot access field: f of class: 
> Outer$Box"), inside a closure or lambda, and when a {{Box}} parameter is 
> narrowed by {{if (b instanceof Sub)}}. Seen in 5.0.8, 6.0.0 and master.
> Dynamic Groovy throws {{MissingPropertyException}} for {{b.f}} whenever the 
> run-time class is {{Sub}}, also for the parameter, because it looks at the 
> run-time class; {{@TypeChecked}} dispatches the property access dynamically 
> and therefore does the same at run time once it compiles.
> Expected: like a private method, a private field or accessor of the 
> variable's declared type is accessible through the variable, from every class 
> that may access the member, even when flow typing narrows the variable to a 
> subclass. A receiver whose type is only the subclass ({{new Sub().f}}, or a 
> {{def}} variable) stays rejected, because a private member is not inherited.
> PR: https://github.com/apache/groovy/pull/3044



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

Reply via email to