Paul King created GROOVY-12648:
----------------------------------
Summary: STC: int converts to char without a range check, while
Integer, byte and short do not convert at all
Key: GROOVY-12648
URL: https://issues.apache.org/jira/browse/GROOVY-12648
Project: Groovy
Issue Type: Improvement
Components: Static Type Checker
Reporter: Paul King
Description:
Under {{@TypeChecked}} and {{@CompileStatic}}, a value can be assigned or
returned to {{char}} or {{Character}} if it is a {{char}}, a {{Character}}, an
{{int}} or a one-character string constant
({{StaticTypeCheckingSupport.checkCompatibleAssignmentTypes}}; limited to these
by GROOVY-10359). The {{int}} case has no loss-of-precision check, unlike every
other narrowing, and {{Integer}}, {{byte}} and {{short}} are rejected. With
GROOVY-12616/12617/12623 (PR #3164), closures, lambdas, method references and
method pointers that return to a {{char}} functional interface method follow
the same rule.
Java (JLS 5.2) converts an {{int}} to {{char}} implicitly only for a constant
that fits (0 to 65535); anything else needs an explicit {{(char)}} cast, which
truncates.
Behaviour on master with PR #3164 (6.0.0 is the same, except that the lambda
and method reference forms were rejected or failed there):
|| Code || {{@TypeChecked}} / {{@CompileStatic}} || Java ||
| {{int i = 65; char c = i}} | 'A' | error |
| {{char c = 70000}} | char 4464, no warning | error |
| {{char m() \{ -1 \}}} | char 65535, no warning | error |
| {{short s = 70000}} | Possible loss of precision | error |
| {{Integer i = 65; char c = i}} | Cannot assign value of type
java.lang.Integer | error |
| {{short s = 65; char c = s}} | Cannot assign value of type short | error |
| {{interface ToChar \{ char get() \}}}, {{ToChar t = () -> 70000}} | char 4464
| error |
| {{int big = 65; ToChar t = () -> big}} | Cannot return value of type
java.lang.Integer (the captured local is seen as Integer) | error |
| {{static int v()}}, {{ToChar t = P::v}} | 'A' | error |
| {{interface CharFn<T> \{ char apply(T t) \}}}, {{CharFn<Integer> f = P::id}}
with {{static <T> T id(T t)}} | error (type argument Integer) | error |
Dynamic code converts all of these at run time.
Options:
*1. Status quo.* No change. These inconsistencies remain:
* {{int}} to {{char}} is the only narrowing without a precision check: {{char c
= 70000}} compiles and gives 4464, while {{short s = 70000}} is "Possible loss
of precision".
* {{int}} is accepted but {{Integer}} is not, although boxing is ignored for
every other primitive ({{Integer}} to {{int}}, {{Short}} to {{short}}).
* {{byte}} and {{short}} are rejected although {{int}}, a wider type, is
accepted.
* A lambda may return {{70000}} for {{char}}, but not a captured local {{int}}
holding {{65}}.
* A method reference to a method returning {{int}} works for {{char}}, but one
to a generic method whose type argument is {{Integer}} does not.
* It conflicts with GROOVY-12620 (PR #3146), which accepts only an {{int}}
constant that fits for a {{char}} closure or lambda return and keeps {{() ->
-1}} rejected. PR #3164 already accepts that case through the rule above.
*2. Loosen.* Also accept {{Integer}} (and possibly {{byte}}, {{short}} and
their wrappers) wherever {{int}} is accepted. Nothing that compiles today
breaks, and the {{int}}/{{Integer}} and captured-local cases agree. The
unchecked truncation remains, and {{char c = (Integer) null}}, which
GROOVY-10359 made an error, would compile again.
*3. Tighten (as Java).* Accept an {{int}} only as a constant that fits, and
report anything else as "Possible loss of precision", as {{int}} to {{short}}
already is. {{Integer}} and a captured local then follow automatically (neither
is a constant), and this matches GROOVY-12620. Code that compiles today, such
as {{char m(int i) \{ i \}}} or {{ToChar t = P::v}}, would need an explicit
{{(char)}} cast, so it is a breaking change and would need a COMPATIBILITY.md
entry. Dynamic code is unaffected, and nothing that still compiles changes its
value. In-tree uses have not been surveyed.
Related: GROOVY-10359, GROOVY-10079, GROOVY-12620 (PR #3146),
GROOVY-12616/12617/12623 (PR #3164).
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)