Skip to content

Compiler crash with scala.MatchError: trait mixed into object "_setter_" (dotty.tools.dotc.core.Names$DerivedName) - vals from tuple desugaring #10285

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

Closed
Sciss opened this issue Nov 11, 2020 · 4 comments · Fixed by #10584

Comments

@Sciss
Copy link
Contributor

Sciss commented Nov 11, 2020

Minimized code

trait Companion {
  trait AbstractFoo {
    val (a, b) = {
      val av  = 1
      val bv  = 2
      (av, bv)
    }
  }
}

object Bar extends Companion {
  class FooImpl extends AbstractFoo
}

Output

[error] scala.MatchError: Companion$AbstractFoo$_setter_$Companion$AbstractFoo$$_=$1 (of class dotty.tools.dotc.core.Names$DerivedName)
[error] 	at dotty.tools.dotc.core.NameOps$.extension_fieldName(NameOps.scala:335)
[error] 	at dotty.tools.dotc.transform.SymUtils$.extension_field(SymUtils.scala:163)
[error] 	at dotty.tools.dotc.transform.Memoize.transformDefDef(Memoize.scala:145)
[error] 	at dotty.tools.dotc.transform.MegaPhase.goDefDef(MegaPhase.scala:974)
[error] 	at dotty.tools.dotc.transform.MegaPhase.goDefDef(MegaPhase.scala:975)
[error] 	at dotty.tools.dotc.transform.MegaPhase.goNamed$1(MegaPhase.scala:165)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformNode(MegaPhase.scala:211)
[error] 	at dotty.tools.dotc.transform.MegaPhase$MiniPhase.transformFollowing(MegaPhase.scala:127)
[error] 	at dotty.tools.dotc.transform.Mixin.setters$1$$anonfun$1(Mixin.scala:277)
[error] 	at scala.collection.immutable.List.map(List.scala:246)
[error] 	at dotty.tools.dotc.transform.Mixin.setters$2(Mixin.scala:277)
[error] 	at dotty.tools.dotc.transform.Mixin.$anonfun$5(Mixin.scala:301)
[error] 	at scala.collection.immutable.List.flatMap(List.scala:293)
[error] 	at dotty.tools.dotc.transform.Mixin.transformTemplate(Mixin.scala:302)
[error] 	at dotty.tools.dotc.transform.Mixin.transformTemplate(Mixin.scala:177)
[error] 	at dotty.tools.dotc.transform.MegaPhase.goTemplate(MegaPhase.scala:1004)
[error] 	at dotty.tools.dotc.transform.MegaPhase.goTemplate(MegaPhase.scala:1005)
[error] 	at dotty.tools.dotc.transform.MegaPhase.goTemplate(MegaPhase.scala:1005)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:363)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:429)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:256)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:427)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformStat$2(MegaPhase.scala:437)
[error] 	at dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] 	at dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:1061)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:442)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:362)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:429)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:256)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:427)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformStat$2(MegaPhase.scala:437)
[error] 	at dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] 	at dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:1061)
[error] 	at dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:1061)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:442)
[error] 	at dotty.tools.dotc.transform.MegaPhase.mapPackage$1(MegaPhase.scala:382)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:385)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:429)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformUnit(MegaPhase.scala:448)
[error] 	at dotty.tools.dotc.transform.MegaPhase.run(MegaPhase.scala:460)
[error] 	at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:296)
[error] 	at scala.collection.immutable.List.map(List.scala:246)
[error] 	at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:297)
[error] 	at dotty.tools.dotc.Run.runPhases$4$$anonfun$4(Run.scala:185)
[error] 	at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] 	at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] 	at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
[error] 	at dotty.tools.dotc.Run.runPhases$5(Run.scala:195)
[error] 	at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:203)
[error] 	at dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error] 	at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:67)
[error] 	at dotty.tools.dotc.Run.compileUnits(Run.scala:210)
[error] 	at dotty.tools.dotc.Run.compileSources(Run.scala:147)
[error] 	at dotty.tools.dotc.Run.compile(Run.scala:129)
[error] 	at dotty.tools.dotc.Driver.doCompile(Driver.scala:38)
[error] 	at dotty.tools.dotc.Driver.process(Driver.scala:194)
[error] 	at dotty.tools.dotc.Main.process(Main.scala)
[error] 	at xsbt.CachedCompilerImpl.run(CachedCompilerImpl.java:69)
@Sciss Sciss changed the title Compiler crash with scala.MatchError: trait mixed into object "_setter_" (dotty.tools.dotc.core.Names$DerivedName) Compiler crash with scala.MatchError: trait mixed into object "_setter_" (dotty.tools.dotc.core.Names$DerivedName) - vals from tuple desugaring Nov 11, 2020
@griggt
Copy link
Contributor

griggt commented Nov 11, 2020

Minimized further:

trait Foo:
  val (a, b) = (1, 2)

class FooImpl extends Foo
scala.MatchError: Foo$_setter_$Foo$$_=$1 (of class dotty.tools.dotc.core.Names$DerivedName) while compiling /src/dotty-issues/versions/src/main/scala/Main.scala
[error] ## Exception when compiling 1 sources to /src/dotty-issues/versions/target/scala-3.0.0-M1/classes
[error] scala.MatchError: Foo$_setter_$Foo$$_=$1 (of class dotty.tools.dotc.core.Names$DerivedName)
[error] dotty.tools.dotc.core.NameOps$.extension_fieldName(NameOps.scala:335)
[error] dotty.tools.dotc.transform.SymUtils$.extension_field(SymUtils.scala:163)
[error] dotty.tools.dotc.transform.Memoize.transformDefDef(Memoize.scala:145)

Looks to have been broken since 0.26.0-RC1 (#8652).

@smarter
Copy link
Member

smarter commented Nov 11, 2020

A val in a trait is iimplemented as a setter that is called in the class that implements the trait. Here there's actually three vals involved because of the val pattern which desugars to:

val $1$ =  (1, 2)
val a = $1$._1
val b = $1$._2

The problem is linked to this compiler-generated $1$ (implemented using UniqueName to get a fresh name each time), when generating a setter name corresponding to it we end up with:

Foo$_setter_$Foo$$_=$1

Semantically this is:

Foo[Qualified $_setter_$ Foo$$_=][Unique $ 1]

The weird part is that the name doesn't end with _= . What happens in detail is that in traitSetterName we go from:

Foo[Qualified $$ ][Unique $ 1]

to:

Foo[Qualified $_setter_$ Foo$$][Unique $ 1]

when calling expandedName(decl.owner, TraitSetterName), then we go to:

Foo[Qualified $_setter_$ Foo$$_=][Unique $ 1]

when calling setterName, even if we fixed fieldName to handle this sort of things, we would still be in trouble for Scala 2 compatibility (since Scala 2 classes can extend Scala 3 traits), so we need to ensure that the setter part of the name always gets added at the end, even if we have a semantic name with multiple parts. Do you think you could take a look at that @odersky ?

@smarter
Copy link
Member

smarter commented Nov 11, 2020

For comparison scalac generates:

val x$1 = (1, 2)
val a = $1$._1
val b = $1$._2

and ends up with these three setters in the trait:

def x$1_=(x: (Int, Int)): Unit
def Foo$_setter_$a_=(x: Int): Unit
def Foo$_setter_$b_=(x$1: Int): Unit

For some reason the setter for the freshly generated x$1 doesn't get an expanded name, is that something we need to imitate for binary compatibility ? /cc @sjrd

@smarter
Copy link
Member

smarter commented Nov 11, 2020

For some reason the setter for the freshly generated x$1 doesn't get an expanded name

... looks like this is just a pretty-printing bug in scalac, if I look in the bytecode I do see:

void Foo$_setter_$Foo$$x$1_$eq(Tuple2 var1)

@odersky odersky self-assigned this Nov 23, 2020
@anatoliykmetyuk anatoliykmetyuk assigned odersky and unassigned sjrd and odersky Nov 23, 2020
odersky added a commit to dotty-staging/dotty that referenced this issue Dec 1, 2020
@odersky odersky linked a pull request Dec 1, 2020 that will close this issue
@odersky odersky assigned sjrd and unassigned odersky Dec 1, 2020
odersky added a commit to dotty-staging/dotty that referenced this issue Dec 1, 2020
…ived names

Adding "_=" to the last part of a name does not work if that name is a unique name
or other derived name, since the resulting name would print like `x_=$1` instead
of `x$1_=`. Use a new semantic name for synthetic setter suffix instead.
odersky added a commit that referenced this issue Dec 2, 2020
Fix #10285: Fix scheme for handling setter names
@Kordyjan Kordyjan modified the milestones: 3.0.0-M3, 3.0.0 Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants