[SI-5654] compiler chokes on case classes with parameters of type Array[_] Created: 10/Apr/12  Updated: 04/Jan/13  Resolved: 11/May/12

Status: CLOSED
Project: Scala Programming Language
Component/s: Compiler (Misc)
Affects Version/s: Scala 2.8.0, Scala 2.9.0, Scala 2.9.1, Scala 2.9.2, Scala 2.10.0
Fix Version/s: Scala 2.10.0-M3

Type: Bug Priority: Major
Reporter: Rob Dickens Assignee: Lukas Rytz
Resolution: Fixed Votes: 0
Labels: compiler-crash, minimized
Environment:

Mac OS 10.7.3



 Description   

case class Bomb(a: Array[_])
case class Bomb2(a: Array[T] forSome

{ type T }

)
class Okay1(a: Array[_])
case class Okay2(s: Seq[_])

[error]

{file:/.../}

default-7541a3/compile:compile: scala.tools.nsc.symtab.Types$TypeError: type mismatch;
[error] found : java.lang.Object
[error] required: Array[java.lang.Object]

most recent version tested: 2.9.2-RC3



 Comments   
Comment by Eugene Burmako [ 08/May/12 ]

error: 
     while compiling:  t5654.scala
       current phase:  constructors
     library version:  version 2.10.0-20120505-103711-7cac6334d4
    compiler version:  version 2.10.0-20120505-103711-7cac6334d4
  reconstructed args:  -Ymacro-debug-lite -deprecation -language:experimental.macros -Yshow-trees-stringified -Yoverride-vars -Xexperimental -Yshow-trees-compact -Yoverride-objects -unchecked -Yinfer-argument-types
 
uncaught exception during compilation: scala.reflect.internal.Types$TypeError
error: scala.reflect.internal.Types$TypeError: type mismatch;
 found   : Object
 required: Array[Object]
  at scala.tools.nsc.typechecker.Contexts$Context.issueCommon(Contexts.scala:363)
  at scala.tools.nsc.typechecker.Contexts$Context.issue(Contexts.scala:367)
  at scala.tools.nsc.typechecker.ContextErrors$ErrorUtils$.issueTypeError(ContextErrors.scala:78)
  at scala.tools.nsc.typechecker.ContextErrors$ErrorUtils$.issueNormalTypeError(ContextErrors.scala:63)
  at scala.tools.nsc.typechecker.ContextErrors$TyperContextErrors$TyperErrorGen$.AdaptTypeError(ContextErrors.scala:147)
  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1188)
  at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5014)
  at scala.tools.nsc.typechecker.Typers$Typer.typedAssign$1(Typers.scala:3819)
  at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:4718)
  at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5005)
  at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5063)
  at scala.tools.nsc.typechecker.Typers$Typer.typedPos(Typers.scala:5067)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer.mkAssign$1(Constructors.scala:121)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer.copyParam$1(Constructors.scala:128)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer$$anonfun$12.apply(Constructors.scala:267)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer$$anonfun$12.apply(Constructors.scala:258)
  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:237)
  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:237)
  at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
  at scala.collection.immutable.List.foreach(List.scala:77)
  at scala.collection.TraversableLike$class.map(TraversableLike.scala:237)
  at scala.collection.AbstractTraversable.map(Traversable.scala:105)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer.transformClassTemplate(Constructors.scala:258)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer$$anonfun$transform$1.apply(Constructors.scala:572)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer$$anonfun$transform$1.apply(Constructors.scala:572)
  at scala.reflect.api.Trees$class.deriveClassDef(Trees.scala:897)
  at scala.reflect.api.Universe.deriveClassDef(Universe.scala:6)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer.transform(Constructors.scala:572)
  at scala.reflect.api.Trees$Transformer$$anonfun$transformStats$2.apply(Trees.scala:1567)
  at scala.reflect.api.Trees$Transformer$$anonfun$transformStats$2.apply(Trees.scala:1565)
  at scala.collection.immutable.List.loop$1(List.scala:163)
  at scala.collection.immutable.List.mapConserve(List.scala:179)
  at scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:1565)
  at scala.reflect.api.Trees$Transformer$$anonfun$transform$1.apply(Trees.scala:1439)
  at scala.reflect.api.Trees$Transformer$$anonfun$transform$1.apply(Trees.scala:1439)
  at scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:1574)
  at scala.reflect.api.Trees$Transformer.transform(Trees.scala:1438)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer.transform(Constructors.scala:574)
  at scala.tools.nsc.ast.Trees$Transformer.transformUnit(Trees.scala:228)
  at scala.tools.nsc.transform.Transform$Phase.apply(Transform.scala:30)
  at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:430)
  at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:396)
  at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:390)
  at scala.collection.Iterator$class.foreach(Iterator.scala:724)
  at scala.collection.AbstractIterator.foreach(Iterator.scala:1151)
  at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:390)
  at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1344)
  at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1317)
  at scala.tools.nsc.Global$Run.compileSources(Global.scala:1311)
  at scala.tools.nsc.Global$Run.compile(Global.scala:1444)
  at scala.tools.nsc.Driver.doCompile(Driver.scala:31)
  at scala.tools.nsc.Main$.doCompile(Main.scala:81)
  at scala.tools.nsc.Driver.process(Driver.scala:52)
  at scala.tools.nsc.Driver.main(Driver.scala:65)
  at scala.tools.nsc.Main.main(Main.scala)
 
Exception in thread "main" scala.reflect.internal.Types$TypeError: type mismatch;
 found   : Object
 required: Array[Object]
  at scala.tools.nsc.typechecker.Contexts$Context.issueCommon(Contexts.scala:363)
  at scala.tools.nsc.typechecker.Contexts$Context.issue(Contexts.scala:367)
  at scala.tools.nsc.typechecker.ContextErrors$ErrorUtils$.issueTypeError(ContextErrors.scala:78)
  at scala.tools.nsc.typechecker.ContextErrors$ErrorUtils$.issueNormalTypeError(ContextErrors.scala:63)
  at scala.tools.nsc.typechecker.ContextErrors$TyperContextErrors$TyperErrorGen$.AdaptTypeError(ContextErrors.scala:147)
  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1188)
  at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5014)
  at scala.tools.nsc.typechecker.Typers$Typer.typedAssign$1(Typers.scala:3819)
  at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:4718)
  at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5005)
  at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5063)
  at scala.tools.nsc.typechecker.Typers$Typer.typedPos(Typers.scala:5067)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer.mkAssign$1(Constructors.scala:121)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer.copyParam$1(Constructors.scala:128)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer$$anonfun$12.apply(Constructors.scala:267)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer$$anonfun$12.apply(Constructors.scala:258)
  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:237)
  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:237)
  at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
  at scala.collection.immutable.List.foreach(List.scala:77)
  at scala.collection.TraversableLike$class.map(TraversableLike.scala:237)
  at scala.collection.AbstractTraversable.map(Traversable.scala:105)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer.transformClassTemplate(Constructors.scala:258)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer$$anonfun$transform$1.apply(Constructors.scala:572)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer$$anonfun$transform$1.apply(Constructors.scala:572)
  at scala.reflect.api.Trees$class.deriveClassDef(Trees.scala:897)
  at scala.reflect.api.Universe.deriveClassDef(Universe.scala:6)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer.transform(Constructors.scala:572)
  at scala.reflect.api.Trees$Transformer$$anonfun$transformStats$2.apply(Trees.scala:1567)
  at scala.reflect.api.Trees$Transformer$$anonfun$transformStats$2.apply(Trees.scala:1565)
  at scala.collection.immutable.List.loop$1(List.scala:163)
  at scala.collection.immutable.List.mapConserve(List.scala:179)
  at scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:1565)
  at scala.reflect.api.Trees$Transformer$$anonfun$transform$1.apply(Trees.scala:1439)
  at scala.reflect.api.Trees$Transformer$$anonfun$transform$1.apply(Trees.scala:1439)
  at scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:1574)
  at scala.reflect.api.Trees$Transformer.transform(Trees.scala:1438)
  at scala.tools.nsc.transform.Constructors$ConstructorTransformer.transform(Constructors.scala:574)
  at scala.tools.nsc.ast.Trees$Transformer.transformUnit(Trees.scala:228)
  at scala.tools.nsc.transform.Transform$Phase.apply(Transform.scala:30)
  at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:430)
  at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:396)
  at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:390)
  at scala.collection.Iterator$class.foreach(Iterator.scala:724)
  at scala.collection.AbstractIterator.foreach(Iterator.scala:1151)
  at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:390)
  at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1344)
  at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1317)
  at scala.tools.nsc.Global$Run.compileSources(Global.scala:1311)
  at scala.tools.nsc.Global$Run.compile(Global.scala:1444)
  at scala.tools.nsc.Driver.doCompile(Driver.scala:31)
  at scala.tools.nsc.Main$.doCompile(Main.scala:81)
  at scala.tools.nsc.Driver.process(Driver.scala:52)
  at scala.tools.nsc.Driver.main(Driver.scala:65)
  at scala.tools.nsc.Main.main(Main.scala)

Comment by Paul Phillips [ 08/May/12 ]

For an interesting change of pace, this works nicely in the repl despite crashing scalac. The repl doesn't actually get the credit though, it's a product of nesting. This compiles.

object Foo {
  case class Bomb(a: Array[_])
  case class Bomb2(a: Array[T] forSome { type T })
  class Okay1(a: Array[_])
  case class Okay2(s: Seq[_])
}

Comment by Lukas Rytz [ 09/May/12 ]

minimized

class T(val a: Array[_])

Comment by Lukas Rytz [ 10/May/12 ]

Story about fixing this one (https://github.com/scala/scala/commit/23afe3c9b9ff6f1c9d31cea678909003ca8f943b)

The class

class T(val a: Array[_$1] forSome { type _$1 })

is de-sugared into

class T {
  val a: Array[_$1] forSome { type _$1 }
 
  def <init>(a:  Array[_$1] forSome { type _$1 }): T = {
    T.this.a = a;
    // ...
  }
}

Constructors phase generates the field initialization assignment, type-checking it crashed. The reason:

  • the type of field a was erased to Array[Object] (that's wrong)
  • the type of parameter a was erased to Object (correct)

Why was field a erased wrong? Java interop: A Java Array<T> is erased to Array[Object] (T can only be a reference type), where as a Scala Array[T] is erased to Object.

This logic in erasure was wrong about judging what is a Java array: it loks at the type argument T and checks if its owner is defined in a Java class. The problem is that for existential members such as T in (Array[T] forSome

{type T}

), the owner of T can be anything (e.g. when computing a lub, the compiler often uses <root> as owner of existential symbols).

In the example, the owner happened to be the enclosing package class, and every package class always has the JAVA flag set.

Why is it the enclosing package class? Because <paramaccessor> fields are type-checked in a context outside the class (createPrimaryConstructorParameterNamer). This is necessary:

class C { class D(val x: C) { class C } }

The parameter type C should refer to the outer class C, not to the nested one.

In our initial example, because the field definition is type-checked in a context outside class T, the owner of the existential symbol _$1 is the enclosing package <empty>.

Comment by Paul Phillips [ 10/May/12 ]

That's awesome.

Comment by Rob Dickens [ 10/May/12 ]

Well done. And thanks for the explanation. (I don't totally get it myself, but don't worry!)

Generated at Fri Oct 19 10:55:48 CEST 2018 using JIRA 7.9.1#79001-sha1:60970b42586a2ec2760ed6cfe825b26961e62b9e.