[
https://issues.apache.org/jira/browse/GROOVY-12469?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18131664#comment-18131664
]
ASF GitHub Bot commented on GROOVY-12469:
-----------------------------------------
paulk-asert commented on PR #2999:
URL: https://github.com/apache/groovy/pull/2999#issuecomment-6393598605
Thanks Daniel.
1, 4. Agreed.
2. Copilot flagged the same helper. I've switched it to
StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf, which the
method-reference half of this PR already uses, so both halves share one subtype
rule.
3. Right. Field, property and array stores target the declared type, so they
don't have the problem. A polluted List<String> stored into a CharSequence
field keeps the StringBuilder both before and after this change.
5. Yes, deliberately: a cast where the narrower type is actually needed, as
javac does.
One thing worth recording: before this change, a value that wasn't of the
narrowed type usually didn't throw. It was silently converted (a StringBuilder
became its toString(), an Integer[] became a String[]), so this fixes wrong
values as well as cast failures. Two shapes still convert, as they did before:
a reassignment after a declaration whose own value was narrow (CharSequence cs
= 'x'; cs = list.get(0)), and an uninitialised declaration followed by an
assignment. There the variable's slot takes the narrow type that flow typing
infers across all the assignments. Fixing that means typing the slot with the
declared type everywhere, which is a broader codegen change, so I've raised
GROOVY-12494 for it rather than grow this PR.
> SC: static compilation inserts wrong cast, derived from generic return type
> when assigned to a variable
> -------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12469
> URL: https://issues.apache.org/jira/browse/GROOVY-12469
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 2.5.23, 3.0.25, 5.0.3, 4.0.33, 5.1.3, 6.0.0
> Reporter: Björn Kautler
> Priority: Major
>
> Given the following snippet:
> {code:groovy}
> import java.lang.annotation.Annotation
> import java.lang.annotation.Retention
> import java.lang.annotation.Target
> import groovy.transform.CompileStatic
> @CompileStatic
> <T extends Annotation> T getRetention(Class<T> clazz) {
> Target.getAnnotation(Target)
> }
> @CompileStatic
> def foo() {
> Annotation x = getRetention(Retention) /*as Annotation*/
> }
> foo().toString()
> {code}
> This compiles fine under all versions, but fails with a
> {{GroovyCastException}} in all versions.
>
> The generated byte-code under SC has a cast on {{Retention}} in this, even
> though the variable is of type {{Annotation}} explicitly.
> Commenting in the {{as Annotation}} cast makes it work.
> Removing the {{Annotation x =}} also makes it work.
> Removing the {{@CompileStatic}} or replacing it by {{@TypeChecked}} of course
> also makes it work.
>
> I'd say static-compilation should here not insert an unnecessary cast to
> {{{}Retention{}}}, but at most a cast to {{Annotation}} as that is, what the
> variable needs and which should be consistent with JVM type-erasure, and also
> with the variant without the variable. Even with the method returning
> {{Annotation}} instead of {{def}} it works just fine. Just if the method
> declares to return {{Retention}} explicitly, the cast exception comes, but
> then rightfully.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)