Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-44280

CPS-transformed overloaded methods don't route properly

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Major Major
    • workflow-cps-plugin
    • None

      (opened in workflow-cps-plugin component since there isn't one for groovy-cps)

      If you have two overloaded methods where the parameter for one is a superclass of the other, with the child class overloaded method casting to the superclass and calling the superclass overloaded method, and then you call the overloaded method with an instance of the child class as the parameter, you end up in a StackOverflowError, with the child class overloaded method called over and over.

      i.e.,

      public String bar(List<String> l) {
          return bar((Iterable)l)
      }
      
      public String bar(Iterable<String> l) {
          return "iterable"
      }
       
      List<String> s = ["a", "b"]
      
      bar(s) == "iterable"
      

      will never complete. Adding the @NonCPS annotation to the bar methods makes it work.

          [JENKINS-44280] CPS-transformed overloaded methods don't route properly

          Andrew Bayer added a comment -

          So the core problem here is that Builder.cast(int,Block,Class,boolean) doesn't actually do anything useful, so far as I can tell. We don't seem to keep track of return type information at all! Ow.

          Andrew Bayer added a comment - So the core problem here is that Builder.cast(int,Block,Class,boolean) doesn't actually do anything useful, so far as I can tell. We don't seem to keep track of return type information at all! Ow.

          Andrew Bayer added a comment -

          Some more details on that - Iterable i = (Iterable) l will result in type information being stored for i as an Iterable, but then if you pass i to a function, its actual type gets used. So theoretically we would need to somehow track the type it should be and cast it in FunctionCallBlock.ContinuationImpl.fixArg(Object) maybe? I have no idea.

          Andrew Bayer added a comment - Some more details on that - Iterable i = (Iterable) l will result in type information being stored for i as an Iterable , but then if you pass i to a function, its actual type gets used. So theoretically we would need to somehow track the type it should be and cast it in FunctionCallBlock.ContinuationImpl.fixArg(Object) maybe? I have no idea.

          Andrew Bayer added a comment -

          Sooooo my conclusion is This Is Hard. Because we're passing Object around in places like FunctionCallBlock.ContinuationImpl.fixArg(Object), we don't have any way of telling the desired type of a parameter, just its actual class. We'd have to be passing a new class of some sort that wrapped both the actual object and the desired type, I think, and that would be a pretty drastic change. So? I don't think this is going anywhere any time soon.

          Andrew Bayer added a comment - Sooooo my conclusion is This Is Hard. Because we're passing Object around in places like FunctionCallBlock.ContinuationImpl.fixArg(Object) , we don't have any way of telling the desired type of a parameter, just its actual class. We'd have to be passing a new class of some sort that wrapped both the actual object and the desired type, I think, and that would be a pretty drastic change. So? I don't think this is going anywhere any time soon.

          Jesse Glick added a comment -

          I also looked at this briefly and concluded it was impossible to support. AFAICT Groovy only handles this to the extent that if a Groovy class is compiled with a cast, the generated bytecode will resolve to the correct overload, just like in Java (though in fewer situations than in Java); and when in CPS mode we are routing everything through runtime checks, there is no way that can work.

          Jesse Glick added a comment - I also looked at this briefly and concluded it was impossible to support. AFAICT Groovy only handles this to the extent that if a Groovy class is compiled with a cast, the generated bytecode will resolve to the correct overload, just like in Java (though in fewer situations than in Java); and when in CPS mode we are routing everything through runtime checks, there is no way that can work.

            Unassigned Unassigned
            abayer Andrew Bayer
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: