Groovy
  1. Groovy
  2. GROOVY-3578

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

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Blocker Blocker
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 1.6.5, 1.7-beta-2
    • Component/s: Compiler
    • Labels:
      None
    • Environment:
      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.

        Activity

        Andy Clement created issue -
        Jochen Theodorou made changes -
        Field Original Value New Value
        Fix Version/s 1.7-beta-1 [ 14014 ]
        Priority Major [ 3 ] Blocker [ 1 ]
        Fix Version/s 1.6.4 [ 15291 ]
        Hide
        Peter Niederwieser added a comment -

        formatting

        Show
        Peter Niederwieser added a comment - formatting
        Peter Niederwieser made changes -
        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.
        I have two files:

        --- A.groovy
        {code}
        package p;

        public class A<T> {
        }
        {code}
        ---

        --- B.groovy
        {code}
        package p;

        class B extends A<String> {
        }
        {code}
        ---

        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:

        {code}
        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);
                    }

                }
            };
        {code}

        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):

        {code}
            /**
             * 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);
                    }

                }
            };
        {code}

        then the order doesn't matter.
        Guillaume Delcroix made changes -
        Fix Version/s 1.6.x [ 15537 ]
        Fix Version/s 1.6.4 [ 15291 ]
        Jochen Theodorou made changes -
        Fix Version/s 1.7-beta-x [ 15538 ]
        Fix Version/s 1.7-beta-1 [ 14014 ]
        Hide
        Jochen Theodorou added a comment -

        Because of a different issue we decided to move the GenericsVisitor into the same phase as Verifier, the visitor does only checks anyway (which fits what Verifier does). With that move (that Roshan did, thx) this issue is resolved too

        Show
        Jochen Theodorou added a comment - Because of a different issue we decided to move the GenericsVisitor into the same phase as Verifier, the visitor does only checks anyway (which fits what Verifier does). With that move (that Roshan did, thx) this issue is resolved too
        Jochen Theodorou made changes -
        Resolution Fixed [ 1 ]
        Status Open [ 1 ] Closed [ 6 ]
        Assignee Jochen Theodorou [ blackdrag ]
        Fix Version/s 1.6.x [ 15537 ]
        Fix Version/s 1.7-beta-2 [ 15540 ]
        Fix Version/s 1.7-beta-x [ 15538 ]
        Fix Version/s 1.6.5 [ 15539 ]
        Hide
        Roshan Dawrani added a comment -

        The change was done against GROOVY-3762, in case it makes sense to link the issues,

        Show
        Roshan Dawrani added a comment - The change was done against GROOVY-3762 , in case it makes sense to link the issues,
        Mark Thomas made changes -
        Project Import Sun Apr 05 13:32:57 UTC 2015 [ 1428240777691 ]
        Mark Thomas made changes -
        Workflow jira [ 12732567 ] Default workflow, editable Closed status [ 12744400 ]
        Mark Thomas made changes -
        Project Import Mon Apr 06 02:11:23 UTC 2015 [ 1428286283443 ]
        Mark Thomas made changes -
        Workflow jira [ 12970356 ] Default workflow, editable Closed status [ 12978133 ]
        Transition Time In Source Status Execution Times Last Executer Last Execution Date
        Open Open Closed Closed
        110d 21h 56m 1 Jochen Theodorou 30/Sep/09 11:00

          People

          • Assignee:
            Jochen Theodorou
            Reporter:
            Andy Clement
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development