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

Reflective structural call with array parameter crashes during pickling #11043

Open
griggt opened this issue Jan 9, 2021 · 6 comments
Open
Assignees
Labels
area:desugar Desugaring happens after parsing but before typing, see desugar.scala area:typer itype:bug itype:crash

Comments

@griggt
Copy link
Contributor

griggt commented Jan 9, 2021

Minimized code

import scala.reflect.Selectable.reflectiveSelectable

object Test {
  type Runner = { def run(args: Array[String]): Unit }

  def test(args: Array[String], runner: Runner): Unit =
    runner.run(args)

  def main(args: Array[String]): Unit = {
    test(Array("foo", "bar"), new {
      def run(args: Array[String]): Unit = args foreach println
    })
  }
}

Output (click arrow to expand)

scala.MatchError: JavaArrayType(TypeRef(ThisType(TypeRef(NoPrefix,module class lang)),class String)) (of class dotty.tools.dotc.core.Types$CachedJavaArrayType) while compiling rs-test-1.scala
Exception in thread "main" scala.MatchError: JavaArrayType(TypeRef(ThisType(TypeRef(NoPrefix,module class lang)),class String)) (of class dotty.tools.dotc.core.Types$CachedJavaArrayType)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleNewType(TreePickler.scala:302)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleType(TreePickler.scala:171)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleConstant(TreePickler.scala:153)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree(TreePickler.scala:453)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree$$anonfun$43$$anonfun$1(TreePickler.scala:518)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.immutable.List.foreach(List.scala:333)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree$$anonfun$17(TreePickler.scala:518)
	at dotty.tools.dotc.core.tasty.TreePickler.withLength(TreePickler.scala:69)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree(TreePickler.scala:518)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree$$anonfun$6(TreePickler.scala:468)
	at dotty.tools.dotc.core.tasty.TreePickler.withLength(TreePickler.scala:69)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree(TreePickler.scala:468)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree$$anonfun$38$$anonfun$1(TreePickler.scala:438)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.immutable.List.foreach(List.scala:333)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree$$anonfun$3(TreePickler.scala:438)
	at dotty.tools.dotc.core.tasty.TreePickler.withLength(TreePickler.scala:69)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree(TreePickler.scala:439)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree$$anonfun$3(TreePickler.scala:437)
	at dotty.tools.dotc.core.tasty.TreePickler.withLength(TreePickler.scala:69)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree(TreePickler.scala:439)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree(TreePickler.scala:427)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree$$anonfun$4(TreePickler.scala:444)
	at dotty.tools.dotc.core.tasty.TreePickler.withLength(TreePickler.scala:69)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree(TreePickler.scala:446)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTreeUnlessEmpty(TreePickler.scala:330)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleDef$$anonfun$1(TreePickler.scala:345)
	at dotty.tools.dotc.core.tasty.TreePickler.withLength(TreePickler.scala:69)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleDef(TreePickler.scala:347)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree(TreePickler.scala:562)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleStats$$anonfun$2(TreePickler.scala:371)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.immutable.List.foreach(List.scala:333)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleStats(TreePickler.scala:371)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree$$anonfun$26(TreePickler.scala:588)
	at dotty.tools.dotc.core.tasty.TreePickler.withLength(TreePickler.scala:69)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree(TreePickler.scala:589)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleDef$$anonfun$1(TreePickler.scala:342)
	at dotty.tools.dotc.core.tasty.TreePickler.withLength(TreePickler.scala:69)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleDef(TreePickler.scala:347)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree(TreePickler.scala:564)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleStats$$anonfun$2(TreePickler.scala:371)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.immutable.List.foreach(List.scala:333)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleStats(TreePickler.scala:371)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree$$anonfun$29(TreePickler.scala:604)
	at dotty.tools.dotc.core.tasty.TreePickler.withLength(TreePickler.scala:69)
	at dotty.tools.dotc.core.tasty.TreePickler.pickleTree(TreePickler.scala:604)
	at dotty.tools.dotc.core.tasty.TreePickler.pickle$$anonfun$1(TreePickler.scala:774)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.immutable.List.foreach(List.scala:333)
	at dotty.tools.dotc.core.tasty.TreePickler.pickle(TreePickler.scala:774)
	at dotty.tools.dotc.transform.Pickler.run$$anonfun$3$$anonfun$2(Pickler.scala:69)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.immutable.List.foreach(List.scala:333)
	at dotty.tools.dotc.transform.Pickler.run$$anonfun$1(Pickler.scala:106)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.immutable.List.foreach(List.scala:333)
	at dotty.tools.dotc.transform.Pickler.run(Pickler.scala:106)
	at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:296)
	at scala.collection.immutable.List.map(List.scala:246)
	at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:297)
	at dotty.tools.dotc.transform.Pickler.runOn(Pickler.scala:111)
	at dotty.tools.dotc.Run.runPhases$4$$anonfun$4(Run.scala:185)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
	at dotty.tools.dotc.Run.runPhases$5(Run.scala:195)
	at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:203)
	at scala.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
	at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:67)
	at dotty.tools.dotc.Run.compileUnits(Run.scala:210)
	at dotty.tools.dotc.Run.compileSources(Run.scala:146)
	at dotty.tools.dotc.Run.compile(Run.scala:130)
	at dotty.tools.dotc.Driver.doCompile(Driver.scala:39)
	at dotty.tools.dotc.Driver.process(Driver.scala:186)
	at dotty.tools.dotc.Driver.process(Driver.scala:155)
	at dotty.tools.dotc.Driver.process(Driver.scala:167)
	at dotty.tools.dotc.Driver.main(Driver.scala:194)
	at dotty.tools.dotc.Main.main(Main.scala)

Expectation

Successful compilation and when run prints:

foo
bar

Workaround

-   runner.run(args)
+   reflectiveSelectable(runner).applyDynamic("run", classOf[Array[String]])(args)

Notes

Works as expected in 3.0.0-M1 and 2.13.4. The regression appears to be caused by 574f741.

https://github.com/lampepfl/dotty/blob/574f74103397ed733b2ed30d88ada829ec2666af/compiler/src/dotty/tools/dotc/typer/Dynamic.scala#L221-L226

@nicolasstucki
Copy link
Contributor

nicolasstucki commented Apr 15, 2021

Minimized to

import scala.reflect.Selectable.reflectiveSelectable

type Runner = { def run(args: Array[String]): Unit }

def test(runner: Runner): Unit = runner.run(???)

@nicolasstucki
Copy link
Contributor

The issue is that now we generate a classOf[String[]] instead of classOf[Array[String]].

@sjrd, why did you use erased types in 574f741? Could we potentially use non erased types and let eraser take care of them?

@sjrd
Copy link
Member

sjrd commented Apr 15, 2021

Because I didn't know how to, in particular what to do when you need to conjure up a concrete type valid as call site when your definition site as T where T >: A <: B with more or less arbitrary bounds?

@smarter
Copy link
Member

smarter commented Apr 15, 2021

What are you looking for exactly? If you need an applied class type which is a supertype of some arbitrary myType, then try myType.baseType(myType.classSymbol).

@vmvazque
Copy link

Is there any update on this issue? I'm seeing the same problem with the 3.3.0 compiler and just wondering if I should use the workaround or wait for a fix.

@bishabosha bishabosha added area:typer area:desugar Desugaring happens after parsing but before typing, see desugar.scala labels Jun 28, 2023
@bishabosha
Copy link
Member

potential spree candidate? @mbovel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:desugar Desugaring happens after parsing but before typing, see desugar.scala area:typer itype:bug itype:crash
Projects
None yet
Development

No branches or pull requests

6 participants