[
https://issues.apache.org/jira/browse/GROOVY-12535?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18135736#comment-18135736
]
ASF GitHub Bot commented on GROOVY-12535:
-----------------------------------------
paulk-asert opened a new pull request, #3154:
URL: https://github.com/apache/groovy/pull/3154
A property or subscript write to a map stores the value through
Map.put(Object, Object). A value accepted for the map's value type but not of
it, such as a GString for String or an Integer for Long, was stored as it was,
so the map held values its declaration did not promise. Under static type
checking the compiler now supplies the value type to a putAt that converts the
value, as a @ClassTag token, in the way the checked withDefault is selected:
the write is a preemption, so the consent veto keeps the previous behaviour.
Dynamic code is unchanged.
A @ClassTag overload is now bound only when the call type checks with its
generics; a call that does not stays as written.
> STC: property-style assignment to a Map<String,String> accepts a GString
> value and stores it unconverted
> --------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12535
> URL: https://issues.apache.org/jira/browse/GROOVY-12535
> Project: Groovy
> Issue Type: Bug
> Reporter: Paul King
> Assignee: Daniel Sun
> Priority: Major
> Fix For: 7.0.0-alpha-1, 6.0.1
>
>
> Under static type checking, a {{GString}} can't be put into a
> {{Map<String,String>}} through {{put}} or the subscript operator; both are
> rejected. Assigning through property notation is accepted, though, and the
> {{GString}} is stored as is:
> {code:groovy}
> @groovy.transform.CompileStatic
> def go() {
> def n = 'ab'
> Map<String,String> m = [:]
> m.k = "$n"
> ((Map) m).values()*.getClass()*.simpleName
> }
> assert go() == ['GStringImpl'] // expected ['String']
> {code}
> ||Form||Result (4.0.29, 6.0.0, master)||
> |{{m.k = "$n"}}|compiles, stores a {{GStringImpl}}|
> |m.with { k = "$n" }|compiles, stores a {{GStringImpl}}|
> |{{m['k'] = "$n"}}|STC error: Cannot call ... putAt ...|
> |{{m.put('k', "$n")}}|STC error: Cannot call ... put(String, String) ...|
> Statically compiled code can't otherwise add a {{GString}} to a collection
> typed for Strings ({{<<}}, {{add}}, {{set}}, {{addAll}}, {{+=}}, {{putAt}}
> and {{put}} are all rejected), so this is the one hole on the write side.
> Later reads that expect a {{String}} can then fail. For example, Java code
> doing {{String s = m.get('k')}} throws {{ClassCastException}}, and
> {{m.get('k').equals('ab')}} is false.
> Expected: either convert the value to a {{String}} at the assignment, as
> Groovy does for {{String s = "$n"}}, or report the same error as {{put}} and
> {{putAt}}. Converting matches the general rule that a {{GString}} becomes a
> {{String}} where one is required, and wouldn't break existing code that
> compiles today.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)