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

Compile error when using generic types with upper bounds

Attach filesAttach ScreenshotVotersWatch issueWatchersCreate sub-taskLinkCloneUpdate Comment AuthorReplace String in CommentUpdate Comment VisibilityDelete Comments
    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

        Activity

          This comment will be Viewable by All Users Viewable by All Users
          Cancel

          People

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

            Dates

              Created:
              Updated:
              Resolved:

              Slack

                Issue deployment