Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-3011

Compile error when using generic types with upper bounds

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 1.5.6, 1.6-beta-1
    • 1.5.7, 1.6-beta-2
    • None
    • None
    • Groovy 1.5.6 (standalone or inside Grails 1.0.3), Groovy 1.6-beta-1, Sun Java SE 1.6.0_07 on 64bit Linux (OpenSUSE 11)

    Description

      I am experiencing the following problem with Groovy 1.5.6 and 1.6-beta-1:

      Groovy does not seem to accept subtypes of direct subtypes of SomeType in constructs like <T extends SomeType>.

      The exact constellation for reproducing the error is as follows:

      Directory structure

      .
      +- groovy
      |  +- foo
      |     +- bar
      |        +- BarMaping.groovy
      |        +- MyTypeMapping.groovy
      |        +- MySubTypeMapping.groovy
      +- java
         +- foo
            +- example
            |  +- MyType.java (interface extending Bar)
            |  +- MySubType.java (interface extending MyType)
            +- Bar.java
            +- Baz.java
      

      Bar.java

      package foo;
      
      public interface Bar {
      
          Baz getId();
      
          void setId(Baz id);
      }
      

      Baz.java is just a POJO

      MyType.java

      package foo.example;
      
      import foo.Bar;
      
      public interface MyType extends Bar {
      
          String getTitle();
      
          void setTitle(String title);
      }
      

      MySubType.java

      package foo.example;
      
      public interface MySubType extends MyType {
      }
      

      BarMapping.groovy

      package foo.bar
      
      import foo.Bar
      import foo.Baz
      
      abstract class BarMapping<T extends Bar> {
      
          Baz id
      
          BarMapping(T bar) {
              mapFrom(bar)
          }
      
          def mapFrom(T bar) {
              id = bar?.id
          }
      
          def mapTo(T bar) {
              
          }
      }
      

      MyTypeMapping.groovy

      package foo.bar
      
      import foo.example.MyType
      
      class MyTypeMapping extends BarMapping<MyType> {
      
          String title
      
          MyTypeMapping(MyType x) {
              super(x)
          }
      
          def mapFrom(MyType x) {
              super.mapFrom(x)
              title = x?.title
          }
      
          def mapTo(MyType x) {
              x.title = title
          }
      }
      

      MySubTypeMapping.groovy

      package foo.bar
      
      import foo.example.MySubType
      
      class MySubTypeMapping extends BarMapping<MySubType> {
      
          String title
      
          MySubTypeMapping(MySubType x) {
              super(x)
          }
      
          def mapFrom(MySubType x) {
              super.mapFrom(x)
              title = x?.title
          }
      
          def mapTo(MySubType x) {
              x.title = title
          }
      }
      

      Now, the following lines will produce the compiler error:

      > export CLASSPATH={absolute_path_to_this_dir}/java:{absolute_path_to_this_dir}/groovy
      > cd java
      > javac foo/*.java foo/example/*.java
      > cd ../groovy
      > groovyc foo/bar/*.groovy
      org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, foo/bar/MySubTypeMapping.groovy: 20: The type MySubType is not a valid substitute for the bounded parameter <T extends foo.Bar>
       @ line 20, column 32.
         class MySubTypeMapping extends BarMapping<MySubType> {
                                        ^
      
      1 error
      

      This means, MyTypeMapping.groovy compiles whereas MySubTypeMapping.groovy does not compile.

      An equivalent Java hierarchy compiles without problems.

      Inside a Grails application, the error message is:

      > grails compile
      
      Welcome to Grails 1.0.3 - http://grails.org/
      Licensed under Apache Standard License 2.0
      Grails home is set to: /martin/dev/grails-1.0.3
      
      Base Directory: /martin/dev/projects/generics
      Note: No plugin scripts found
      Running script /martin/dev/grails-1.0.3/scripts/Compile.groovy
      Environment set to development
          [mkdir] Created dir: /neofonie/home/gerlach/.grails/1.0.3/projects/generics/classes
        [groovyc] Compiling 13 source files to /neofonie/home/gerlach/.grails/1.0.3/projects/generics/classes
          [javac] Compiling 12 source files to /neofonie/home/gerlach/.grails/1.0.3/projects/generics/classes
      Compilation error: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, /martin/dev/projects/generics/src/groovy/foo/bar/MySubTypeMapping.groovy: 20: The type MySubType is not a valid substitute for the bounded parameter <T extends foo.Bar>
       @ line 20, column 32.
         class MySubTypeMapping extends BarMapping<MySubType> {
                                        ^
      
      1 error
      

      This is the error message with groovy 1.6-beta-1

      > groovyc foo/bar/*.groovy
      java.lang.reflect.InvocationTargetException
              at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
              at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
              at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
              at java.lang.reflect.Method.invoke(Method.java:597)
              at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:108)
              at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130)
      Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, foo/bar/MySubTypeMapping.groovy: 20: The type MySubType is not a valid substitute for the bounded parameter <T extends foo.Bar>
       @ line 20, column 32.
         class MySubTypeMapping extends BarMapping<MySubType> {
                                        ^
      
      1 error
      
              at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:296)
              at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:785)
              at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:435)
              at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:414)
              at org.codehaus.groovy.tools.FileSystemCompiler.compile(FileSystemCompiler.java:63)
              at org.codehaus.groovy.tools.FileSystemCompiler.main(FileSystemCompiler.java:246)
              ... 6 more
      

      Some more observations:

      • If I use BarMapping<T> instead of BarMapping<T extends Bar>, the code compiles without any problem - we only loose the possibility to check the generic type at compile time.
      • When using IntellijIDEA, everything seems fine even when using <T extends Bar>, I can even execute the unit tests included in the attached archive.

      Attachments

        1. example.tgz
          2 kB

        Activity

          People

            Unassigned Unassigned
            martin.gerlach Martin Gerlach
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: