[ 
https://issues.apache.org/jira/browse/GROOVY-12319?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Daniel Sun updated GROOVY-12319:
--------------------------------
    Description: 
Groovy already accepts most Java generics. Three Java forms still fail: two in 
the parser, one in {{GenericsVisitor}}. Each has a local workaround.

Method type arguments such as {{Helper.<String>identity( x )}} already work and 
are not part of this request.

h3. 1. Diamond {{<>}} on an anonymous class

Java 9+ (JEP 213, JLS 15.9.5) allows diamond when creating an anonymous class, 
if the target type supplies the type arguments:

{code:java}
Processor<String> p = new Processor<>() {
    public String process(String val) { return val.toUpperCase(); }
};
{code}

This should work in assignment, as a method argument, and under 
{{@TypeChecked}} / {{@CompileStatic}}, for both interfaces and abstract classes.

*Actual:* Groovy rejects it with {{Cannot use diamond <> with anonymous inner 
classes}}.

*Workaround:* write the type arguments explicitly:

{code:java}
Processor<String> p = new Processor<String>() {
    public String process(String val) { return val.toUpperCase(); }
};
{code}

GROOVY-6730 and GROOVY-7159 were false-positive STC errors when diamond was 
_not_ used. They did not add this form.

h3. 2. Qualified parameterized inner types ("rare" types)

Java allows an inner type to keep the enclosing type's arguments (JLS 4.5):

{code:java}
class Outer<T> {
    class Inner<U> {}
}
Outer<String>.Inner<Integer> x = new Outer<String>().new Inner<Integer>("v", 1);
{code}

The same qualification appears as a field or method type, nested in another 
type argument ({{List<Outer<String>.Inner<Integer>>}}), on {{implements}}, and 
in {{new Outer<T>.Inner<U>(...)}} inside the outer class.

*Actual:* Groovy fails to parse {{Outer<String>.Inner}} ({{Unexpected input}}).

*Workaround:* a factory that returns {{Inner}} without naming 
{{Outer<T>.Inner}}.

h3. 3. Explicit type arguments on constructors, {{this()}} and {{super()}}

Java allows constructor type arguments independently of the class type 
arguments (JLS 15.9 / 8.8.7.1):

{code:java}
class Box {
    <T> Box(T t) {}
    Box() { <String>this("x"); }
}
class Derived extends Box {
    Derived() { <String>super("y"); }
}
class Outer {
    class Inner {
        <T> Inner(T t) {}
    }
}

new <String>Box("x");
new Outer().new <String>Inner("z");
{code}

*Actual:* Groovy fails at {{new <}} with {{Unexpected input: '<'}}.

*Workaround:* inference, e.g. {{new Box("x")}}.

Constructor type arguments are already tracked by GROOVY-10501. The {{this()}} 
/ {{super()}} / inner-{{new}} forms are the same JLS production and should be 
handled together.

h3. Expected

All three forms compile in dynamic Groovy and under {{@TypeChecked}} / 
{{@CompileStatic}}, matching javac on well-formed programs.

The same well-formedness rules as javac still apply. These remain compile 
errors:

{code:java}
new Object<>() {}                 // diamond on a non-generic type
class C extends ArrayList<> {}    // diamond on a class declaration
List<> list;                      // diamond on a field
new <String>Box<>("x")            // diamond combined with constructor type 
arguments
Outer<String, Integer>.Inner x;   // wrong arity
x instanceof Outer<String>.Inner  // parameterized type is not reifiable
new Outer<String>.Inner[1]        // generic array creation
{code}




  was:
Groovy already accepts most Java generics. Three Java forms still fail — two in 
the parser, one in {{GenericsVisitor}}. Each has a local workaround. Method 
type arguments such as {{Helper.<String>identity(x\)}} already work and are not 
part of this request.

h3. 1. Diamond {{<>}} on an anonymous class

Java 9+ (JEP 213) allows:
{code:java}
Processor<String> p = new Processor<>() {
    public String process(String val) { return val; }
};
{code}

Groovy rejects this with {{Cannot use diamond <> with anonymous inner 
classes}}. Writing  new Processor<String>() \{ ... \}  compiles.

GROOVY-6730 and GROOVY-7159 were false-positive STC errors when diamond was 
_not_ used; they did not add this form.

h3. 2. Qualified parameterized inner types ("rare" types)

Java allows an inner type to keep the outer's type arguments:
{code:java}
class Outer<T> {
    class Inner<U> {}
}
Outer<String>.Inner<Integer> x;
{code}

Groovy fails to parse {{Outer<String>.Inner}} ({{Unexpected input}}). A factory 
that returns {{Inner}} without naming {{Outer<T>.Inner}} is a workaround. The 
same qualification appears in {{o.new Inner<Integer>(42)}}.

h3. 3. Explicit type arguments on constructors, {{this()}} and {{super()}}

Java allows:
{code:java}
class Box {
    <T> Box(T t) {}
}
new <String>Box("x");
{code}

and, on generic constructors, {{<T>this()}}, {{<T>super()}}, 
{{recv.<T>super()}}, and {{outer.new <T>Inner(...)}}.

Groovy fails at {{new <}} with {{Unexpected input: '<'}}. Inference ({{new 
Box("x")}}) is the workaround.

Constructor type arguments are already tracked by GROOVY-10501. The {{this()}} 
/ {{super()}} / inner-{{new}} forms are the same JLS production (JLS 15.9) and 
should be handled together.

h3. Related

* GROOVY-10501 — constructor type arguments (open)
* GROOVY-6730, GROOVY-7159 — diamond + anonymous class, STC false positives 
(fixed)



> Java compatibility: remaining generic type syntax
> -------------------------------------------------
>
>                 Key: GROOVY-12319
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12319
>             Project: Groovy
>          Issue Type: Improvement
>            Reporter: Daniel Sun
>            Priority: Major
>
> Groovy already accepts most Java generics. Three Java forms still fail: two 
> in the parser, one in {{GenericsVisitor}}. Each has a local workaround.
> Method type arguments such as {{Helper.<String>identity( x )}} already work 
> and are not part of this request.
> h3. 1. Diamond {{<>}} on an anonymous class
> Java 9+ (JEP 213, JLS 15.9.5) allows diamond when creating an anonymous 
> class, if the target type supplies the type arguments:
> {code:java}
> Processor<String> p = new Processor<>() {
>     public String process(String val) { return val.toUpperCase(); }
> };
> {code}
> This should work in assignment, as a method argument, and under 
> {{@TypeChecked}} / {{@CompileStatic}}, for both interfaces and abstract 
> classes.
> *Actual:* Groovy rejects it with {{Cannot use diamond <> with anonymous inner 
> classes}}.
> *Workaround:* write the type arguments explicitly:
> {code:java}
> Processor<String> p = new Processor<String>() {
>     public String process(String val) { return val.toUpperCase(); }
> };
> {code}
> GROOVY-6730 and GROOVY-7159 were false-positive STC errors when diamond was 
> _not_ used. They did not add this form.
> h3. 2. Qualified parameterized inner types ("rare" types)
> Java allows an inner type to keep the enclosing type's arguments (JLS 4.5):
> {code:java}
> class Outer<T> {
>     class Inner<U> {}
> }
> Outer<String>.Inner<Integer> x = new Outer<String>().new Inner<Integer>("v", 
> 1);
> {code}
> The same qualification appears as a field or method type, nested in another 
> type argument ({{List<Outer<String>.Inner<Integer>>}}), on {{implements}}, 
> and in {{new Outer<T>.Inner<U>(...)}} inside the outer class.
> *Actual:* Groovy fails to parse {{Outer<String>.Inner}} ({{Unexpected 
> input}}).
> *Workaround:* a factory that returns {{Inner}} without naming 
> {{Outer<T>.Inner}}.
> h3. 3. Explicit type arguments on constructors, {{this()}} and {{super()}}
> Java allows constructor type arguments independently of the class type 
> arguments (JLS 15.9 / 8.8.7.1):
> {code:java}
> class Box {
>     <T> Box(T t) {}
>     Box() { <String>this("x"); }
> }
> class Derived extends Box {
>     Derived() { <String>super("y"); }
> }
> class Outer {
>     class Inner {
>         <T> Inner(T t) {}
>     }
> }
> new <String>Box("x");
> new Outer().new <String>Inner("z");
> {code}
> *Actual:* Groovy fails at {{new <}} with {{Unexpected input: '<'}}.
> *Workaround:* inference, e.g. {{new Box("x")}}.
> Constructor type arguments are already tracked by GROOVY-10501. The 
> {{this()}} / {{super()}} / inner-{{new}} forms are the same JLS production 
> and should be handled together.
> h3. Expected
> All three forms compile in dynamic Groovy and under {{@TypeChecked}} / 
> {{@CompileStatic}}, matching javac on well-formed programs.
> The same well-formedness rules as javac still apply. These remain compile 
> errors:
> {code:java}
> new Object<>() {}                 // diamond on a non-generic type
> class C extends ArrayList<> {}    // diamond on a class declaration
> List<> list;                      // diamond on a field
> new <String>Box<>("x")            // diamond combined with constructor type 
> arguments
> Outer<String, Integer>.Inner x;   // wrong arity
> x instanceof Outer<String>.Inner  // parameterized type is not reifiable
> new Outer<String>.Inner[1]        // generic array creation
> {code}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to