Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Boom! you stepped on a bug with specialization and companion objects #5284

Closed
scabug opened this issue Dec 6, 2011 · 9 comments
Closed

Boom! you stepped on a bug with specialization and companion objects #5284

scabug opened this issue Dec 6, 2011 · 9 comments

Comments

@scabug
Copy link

scabug commented Dec 6, 2011

I came across the following situation.

object Run {
 def main(args:Array[String]) {
  val a = Blarg(Array(1,2,3))
  println(a.m((x:Int) => x+1))
 }
}

object Blarg {
  def apply[T:Manifest](a:Array[T]) = new Blarg(a)
}
class Blarg [@specialized T:Manifest](val a:Array[T]) {
  def m[@specialized W>:T,@specialized S](f:W=>S) = f(a(0))
}

When run, this throws the runtime exception
java.lang.RuntimeException: boom! you stepped on a bug. This method should never be called.

However, when we specialize the apply method as follows,

object Blarg {
  def apply[@specialized T:Manifest](a:Array[T]) = new Blarg(a)
}

everything goes through as it should.

The type parameters used in m are a workaround for the lack
of specialization on result type I submitted earlier.

@scabug
Copy link
Author

scabug commented Dec 6, 2011

Imported From: https://issues.scala-lang.org/browse/SI-5284?orig=1
Reporter: Marc Millstone (splittingfield)
Affected Versions: 2.9.1

@scabug
Copy link
Author

scabug commented Dec 6, 2011

Marc Millstone (splittingfield) said:
I should add that this is dependent on the specialization of the method m, if we remove that
everything goes through as it should.

@scabug
Copy link
Author

scabug commented Dec 6, 2011

@paulp said:
With a small variation I made my way to a NoSuchMethodError instead. Noting for future fixer.

object Run {
  def main(args:Array[String]) {
    println( Blarg(Array(1)) m ((x: Int) => x + 1) )
  }
}

object Blarg {
  def apply[T: Manifest](a: Array[T]) = new Blarg(a)
}
class Blarg[T](val a:Array[T]) {
  // java.lang.NoSuchMethodError: Blarg.m$mIIc$sp(Lscala/Function1;)I
  //  at Run$.main(a.scala:6)
  //  at Run.main(a.scala)
  def m[@specialized W >: T, @specialized S](f: W => S) = f(a(0))
}

@scabug
Copy link
Author

scabug commented Dec 6, 2011

Marc Millstone (splittingfield) said:
Great.

Thanks Paul. I am really deep into specialization and please let me know
how else I can help.

@scabug
Copy link
Author

scabug commented Dec 6, 2011

@paulp said:
As you have clearly discovered, specialization leaks like a sieve as soon as you get away from simple, non-compositional uses. I wish I could propose a realistic form of assistance you could provide, but unless you're interested in learning the compiler well enough to tackle the implementation (and it's not exactly the easiest part of the compiler) then for the moment we're both waiting for a white knight: although I would love to work on specialization, it's of necessity way down on my list of priorities.

@scabug
Copy link
Author

scabug commented Dec 21, 2011

@axel22 said:
In the example where T on Blarg is not specialized, the compiler issues a warning about the lower bound of W.
I believe it should issue an error instead - the specialized method cannot be generated with T as a lower bound.

I'm experimenting on what would happen if a method with a T as a lower bound really got specialized.

@scabug
Copy link
Author

scabug commented Dec 21, 2011

Marc Millstone (splittingfield) said:
I did not see this warning with 2.9.1-final.

The only reason this code exists is due to issue #5281
Where it seems that if class[@specialized T] A { def f@specialized W:W}

is not specializing across the cross product of T and W. This was a workaround to force
specialization across the input and output.

@scabug
Copy link
Author

scabug commented Dec 22, 2011

@axel22 said:
In the case where T is specialized:
I think the issue can be solved when by generating the normalized method m$mIIc$sp of m.
Instead of throwing an exception in the implementation of m$mIIc$sp, the implementation of m should be copied so that all occurrences of expressions of type T are cast to Int. Generally, it would mean that all expressions of type equal to the lower bound of some specialized type parameter are cast to the specialized type of that type parameter.
This is still type-safe because the method m above can only be called if W = Int >: T, therefore, it's only callable with such a W if the enclosing class is instantiated at T = Int. Otherwise, the cast in the normalized method would be invalid, but the method itself wouldn't be callable anyway.
This would require modifying the Duplicators to provide them with a castMap which essentially says for which types certain expressions of that type have to be cast, and then insert a cast at these locations.

Iulian, can you comment on this? Do you agree?

@scabug scabug closed this as completed Jun 21, 2012
@scabug
Copy link
Author

scabug commented Jun 21, 2012

@axel22 said:
In: scala/scala#755

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants