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

Compiler crash when invoking on tagged Array containing Primitive type #7088

Closed
scabug opened this issue Feb 6, 2013 · 8 comments
Closed

Comments

@scabug
Copy link

scabug commented Feb 6, 2013

The following code crashes the compiler:

object Example extends App {
  type Tag[X] = {type Tag = X}
  type TaggedArray[T] = Array[T] with Tag[Any]

  def method[T: reflect.ClassTag](a: TaggedArray[T], value: T) {a.update(0, value)}

  method(Array(1, 2).asInstanceOf[TaggedArray[Int]], 1)
}

Sympton:
[error] uncaught exception during compilation: RuntimeException("scala.Array.update : Object, Object, Any") @ scala.sys.
package$.error(package.scala:27)
java.lang.RuntimeException: scala.Array.update : Object, Object, Any
at scala.sys.package$.error(package.scala:27)
at scala.tools.nsc.backend.ScalaPrimitives$$anonfun$elementType$1$1$$anonfun$apply$1.apply(ScalaPrimitives.scala
:571)
at scala.tools.nsc.backend.ScalaPrimitives$$anonfun$elementType$1$1.apply(ScalaPrimitives.scala:571)
at scala.tools.nsc.backend.ScalaPrimitives$$anonfun$elementType$1$1.apply(ScalaPrimitives.scala:567)
at scala.reflect.internal.SymbolTable.enteringPhase(SymbolTable.scala:203)
at scala.tools.nsc.backend.ScalaPrimitives.elementType$1(ScalaPrimitives.scala:567)
at scala.tools.nsc.backend.ScalaPrimitives.getPrimitive(ScalaPrimitives.scala:592)
at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genPrimitiveOp(GenICode.scala:421)
at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadApply6$1(GenICode.scala:751)

My theory is that the presence of the "with Tag" on the Array type disrupts the usual process of resolving the correct primitive type when generating operations on the Array.

Note this is the (greatly simplified) cause of #6975, which I reported. I will close the other issue now.

@scabug
Copy link
Author

scabug commented Feb 6, 2013

Imported From: https://issues.scala-lang.org/browse/SI-7088?orig=1
Reporter: Ben Hutchison (ben_hutchison)
Affected Versions: 2.10.0
See #6975

@scabug
Copy link
Author

scabug commented May 10, 2013

Dave Whittaker (davewhittaker) said:
I just came across the same error, but without the complex typing. The gist of it is that if you have a java library like hibernate which returns an untyped java.util.List, then you use scala.collection.JavaConverters to make that a Buffer, and then you try to pattern match on the contents of the buffer, which is an Array[_], trying to access any of the elements in the array will lead to the compiler crashing and the stack trace above. Here's a test case to reproduce: https://github.com/davewhittaker/arraycrash

@scabug
Copy link
Author

scabug commented May 24, 2013

@paulp said:
scala/scala#2592

@scabug
Copy link
Author

scabug commented May 24, 2013

@paulp said:
FYI if the point of all this is that the array not wind up boxed, it's unlikely to happen. To the compiler that abstract type looks like a bundle of mysteries and it's going to be conservative and erase to Object, which means all array traffic will take the slow path.

@scabug
Copy link
Author

scabug commented Jul 2, 2013

Ben Hutchison (ben_hutchison) said (edited on Jul 2, 2013 4:07:18 PM UTC):
Actually, measurements on 2.11-SNAPSHOT suggest that neither tagged primitive arrays (Array[Int] with Tag), nor arrays of tagged primitives (eg Array[Int with Tag]), are boxed :)

(The -optimise flag is required to Scalac).

object TaggedArray {
val tagary: Array[Int] with Tag = Array(1).asInstanceOf[Array[Int] with Tag]
tagary.update(0, 7)
println(tagary(0))
}
{code}
scala> :javap -cp test.TaggedArray$
Compiled from "Primitive.scala"
public final class test.TaggedArray$ {
public static final test.TaggedArray$ MODULE$;

private final int[] tagary;
[..snip..]
private test.TaggedArray$();
Code:
0: aload_0
1: invokespecial #19 // Method java/lang/Object."":()V
4: aload_0
5: putstatic #21 // Field MODULE$:Ltest/TaggedArray$;
8: aload_0
9: iconst_1
10: newarray int
12: dup
13: iconst_0
14: iconst_1
15: iastore
16: putfield #17 // Field tagary:[I
19: aload_0
20: invokevirtual #23 // Method tagary:()[I
23: iconst_0
24: bipush 7
26: iastore
27: getstatic #28 // Field scala/Predef$.MODULE$:Lscala/Predef$;
30: aload_0
31: invokevirtual #23 // Method tagary:()[I
34: iconst_0
35: iaload
36: invokestatic #34 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
39: invokevirtual #38 // Method scala/Predef$.println:(Ljava/lang/Object;)V
42: return
}}}

@scabug
Copy link
Author

scabug commented Jul 2, 2013

@paulp said:
Yes, that's a bug that it doesn't box. The logic in intersectionDominator is completely wrong, especially where Arrays and abstract types are involved; it picks the Array for the erased type even when it is intersected with abstract types which cannot share that storage. I had a patch for that but it is unlikely to surface given the time I have remaining.

So enjoy the unboxed view while it lasts!

@scabug
Copy link
Author

scabug commented May 1, 2016

@benhutchison said:
Is this fixed now?

Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_51).
Type in expressions to have them evaluated.
scala> object Example extends App {
| type Tag[X] = {type Tag = X}
| type TaggedArray[T] = Array[T] with Tag[Any]
|
| def method[T: reflect.ClassTag](a: TaggedArray[T], value: T) {a.update(0, value)}
|
| method(Array(1, 2).asInstanceOf[TaggedArray[Int]], 1)
| }
defined object Example

@scabug
Copy link
Author

scabug commented May 19, 2016

@lrytz said:
test case in scala/scala#5144

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

1 participant