Scott Murphy Heiberg created GROOVY-12513:
---------------------------------------------

             Summary: 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


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.



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

Reply via email to