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

Ordering of files passed to compiler affects whether some (invalid) generics errors get reported

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Blocker
    • Resolution: Fixed
    • None
    • 1.6.5, 1.7-beta-2
    • Compiler
    • None
    • Windows 7

    Description

      I have two files:

      — A.groovy

      package p;
      
      public class A<T> {
      }
      

      — B.groovy

      package p;
      
      class B extends A<String> {
      }
      

      Depending on the order in which they are passed to groovyc, I may get an error:

      > groovyc A.groovy B.groovy

      works fine.

      > groovyc B.groovy A.groovy

      org.codehaus.groovy.control.MultipleCompilationErrorsException: startup
      failed, B.groovy: 3: The type String is not a valid substitute for the
      bounded parameter <T>
      @ line 3, column 17.
      class B extends A<String> {
      ^
      1 error

      This happens because the generics checking is done as part of the resolution phase. From CompilationUnit:

      private final SourceUnitOperation resolve = new SourceUnitOperation() {
              public void call(SourceUnit source) throws CompilationFailedException {
                  List classes = source.ast.getClasses();
                  for (Iterator it = classes.iterator(); it.hasNext();) {
                      ClassNode node = (ClassNode) it.next();
      
                      VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
                      scopeVisitor.visitClass(node);
      
                      resolveVisitor.startResolving(node, source);
      
                      GenericsVisitor genericsVisitor = new GenericsVisitor(source);
                      genericsVisitor.visitClass(node);
                  }
      
              }
          };
      

      if the generics check is performed before the types involved (like A) are resolved, you get this problem. The solution is to break that into two phases: resolution and then generics checking (take the last two lines from the resolution phase and move them into a new phase, done after resolution):

          /**
           * Check generics usage
           */
          private final SourceUnitOperation checkGenerics = new SourceUnitOperation() {
              public void call(SourceUnit source) throws CompilationFailedException {
                  List classes = source.ast.getClasses();
                  for (Iterator it = classes.iterator(); it.hasNext();) {
                      ClassNode node = (ClassNode) it.next();
      
                      GenericsVisitor genericsVisitor = new GenericsVisitor(source);
                      genericsVisitor.visitClass(node);
                  }
      
              }
          };
      

      then the order doesn't matter.

      Attachments

        Activity

          People

            blackdrag Jochen Theodorou
            andy.clement Andy Clement
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: