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)