Scala Programming Language
  1. Scala Programming Language
  2. SI-7343

Specialization missing an opportunity to rewire parent from AbstractFunction1[Int, Unit] to AbstractFunction1$mcVI$sp

    Details

      Description

      $ cat spec-test.scala 
      class Test[T](array: Array[T]) {
       
        def spec_mapper[@specialized(Int) U](array: Array[U]) {
          for(i <- 0 to 10) {
            array(i) = array(array.length - i - 1)
          }
        }
      }
      
      $ ../build/quick/bin/scalac -Xprint:specialize spec-test.scala
      [[syntax trees at end of                specialize]] // spec-test.scala
      package <empty> {
        class Test[T >: Nothing <: Any] extends Object {
          ...
      
          // generic spec_mapper:
          def spec_mapper[@specialized(scala.Int) U >: Nothing <: Any](array: Array[U]): Unit = scala.this.Predef.intWrapper(0).to(10).foreach$mVc$sp({
            // parent rewired correctly to AbstractFunction1$mcVI$sp
            @SerialVersionUID(0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction1$mcVI$sp with Serializable {
              ...
            };
            (new anonymous class $anonfun(): Int => Unit)
          });
      
          // specialized spec_mapper for Int:
          <specialized> def spec_mapper$mIc$sp(array: Array[Int]): Unit = scala.this.Predef.intWrapper(0).to(10).foreach$mVc$sp({
            // parent not rewired: AbstractFunction1[Int, Unit] => Int boxed!
            final <synthetic> class $anonfun extends scala.runtime.AbstractFunction1[Int,Unit] with Serializable {
              ...
            };
            (new anonymous class $anonfun(): Int => Unit)
          })
        }
      }
      

      This bit us while working on https://github.com/nicolasstucki/specialized/

        Activity

        Hide
        Vlad Ureche added a comment -

        A very simple test that doesn't fail is this:

        class Target[@specialized(Int) T]{ def foo = 1 }
        
        object Test {
          def spec_mapper[@specialized(Int) T](t: T) =
            new Target[T]().foo
        }
        

        I checked with and without separate compilation and it always works.
        I will leave it for now, that's a pretty big time sink.

        Show
        Vlad Ureche added a comment - A very simple test that doesn't fail is this: class Target[@specialized(Int) T]{ def foo = 1 } object Test { def spec_mapper[@specialized(Int) T](t: T) = new Target[T]().foo } I checked with and without separate compilation and it always works. I will leave it for now, that's a pretty big time sink.
        Hide
        Vlad Ureche added a comment -

        This is a better reproduction:

        class Target[@specialized(Int) T]{ def foo = 1 }
        
        object Test {
        
          def spec_mapper[@specialized(Int) T](t: T) = {
            class X extends Target[T]() // <== never gets its parents updated
            (new X).foo
          }
        }
        
        Show
        Vlad Ureche added a comment - This is a better reproduction: class Target[@specialized(Int) T]{ def foo = 1 } object Test { def spec_mapper[@specialized(Int) T](t: T) = { class X extends Target[T]() // <== never gets its parents updated (new X).foo } }
        Hide
        Vlad Ureche added a comment - - edited

        Okay, found it. Explanation:
        1. Specialization relies on two steps:

        • info (type) transformation, which is triggered for all symbols coming from previous phases
        • tree transformation, which relies on the info transformation

        2. When duplicating class X above, the duplicate symbol is created during specialization, so it never has the chance to go through the info transformation. A beforeSpecialize() should fix this, but where to introduce it?

        Show
        Vlad Ureche added a comment - - edited Okay, found it. Explanation: 1. Specialization relies on two steps: info (type) transformation, which is triggered for all symbols coming from previous phases tree transformation, which relies on the info transformation 2. When duplicating class X above, the duplicate symbol is created during specialization, so it never has the chance to go through the info transformation. A beforeSpecialize() should fix this, but where to introduce it?
        Hide
        Vlad Ureche added a comment -

        The patch I have still fails two tests. I'll have to dig deeper into it...

        Show
        Vlad Ureche added a comment - The patch I have still fails two tests. I'll have to dig deeper into it...
        Show
        Vlad Ureche added a comment - https://github.com/scala/scala/pull/2651

          People

          • Assignee:
            Vlad Ureche
            Reporter:
            Vlad Ureche
          • Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development