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 chokes on case classes with parameters of type Array[_] #5654

Closed
scabug opened this issue Apr 10, 2012 · 7 comments
Closed

compiler chokes on case classes with parameters of type Array[_] #5654

scabug opened this issue Apr 10, 2012 · 7 comments

Comments

@scabug
Copy link

scabug commented Apr 10, 2012

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

@scabug
Copy link
Author

scabug commented Apr 10, 2012

Imported From: https://issues.scala-lang.org/browse/SI-5654?orig=1
Reporter: Rob Dickens (robcd)
Affected Versions: 2.8.0, 2.9.0, 2.9.1, 2.9.2, 2.10.0

@scabug
Copy link
Author

scabug commented May 7, 2012

@xeno-by said:

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)

@scabug
Copy link
Author

scabug commented May 8, 2012

@paulp said:
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[_])
}

@scabug
Copy link
Author

scabug commented May 9, 2012

@lrytz said:
minimized

class T(val a: Array[_])

@scabug
Copy link
Author

scabug commented May 10, 2012

@lrytz said (edited on May 10, 2012 12:24:10 PM UTC):
Story about fixing this one (scala/scala@23afe3c)

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 looks 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>.

@scabug
Copy link
Author

scabug commented May 10, 2012

@paulp said:
That's awesome.

@scabug
Copy link
Author

scabug commented May 10, 2012

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

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