Skip to content

Commit

Permalink
Fix needsOuterIfReferenced
Browse files Browse the repository at this point in the history
scala#17135 shows that traits also need an outer accessor if they are in a toplevel
method (or lazy val).

Fixes scala#17135
  • Loading branch information
odersky committed Mar 28, 2023
1 parent 6e5be23 commit d1255f3
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 4 deletions.
10 changes: 6 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,9 @@ object ExplicitOuter {

/** Class needs an outer pointer, provided there is a reference to an outer this in it. */
def needsOuterIfReferenced(cls: ClassSymbol)(using Context): Boolean =
!(cls.isStatic ||
cls.owner.enclosingClass.isStaticOwner ||
cls.is(PureInterface)
!(cls.isStatic
|| cls.effectiveOwner.isStaticOwner
|| cls.is(PureInterface)
)

/** Class unconditionally needs an outer pointer. This is the case if
Expand All @@ -226,7 +226,9 @@ object ExplicitOuter {

/** The outer parameter accessor of cass `cls` */
private def outerParamAccessor(cls: ClassSymbol)(using Context): TermSymbol =
cls.info.decl(nme.OUTER).symbol.asTerm
val outer = cls.info.decl(nme.OUTER).symbol
assert(outer.isTerm, i"missing outer accessor in $cls")
outer.asTerm

/** The outer accessor of class `cls`. To find it is a bit tricky. The
* class might have been moved with new owners between ExplicitOuter and Erasure,
Expand Down
53 changes: 53 additions & 0 deletions tests/pos/i17135.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package doobie

// original example
def someFunction(param: Int): Int = {
sealed trait Foo {
def asString: String = this match {
case Foo.CaseC => "C"
}
}
object Foo {
// Having an object here crashes the compiler.
object CaseC extends Foo
}

???
}

// minimization
def foo =
class Bar {
// Having an object here crashes the compiler.
lazy val CaseC =
class Baz extends Foo
new Baz()
}
val Bar: Bar = new Bar()
trait Foo {
def asString = Bar.CaseC
}

// variant: outer is lazy val
lazy val lazyfoo =
class Bar {
// Having an object here crashes the compiler.
lazy val CaseC =
class Baz extends Foo
new Baz()
}
val Bar: Bar = new Bar()
trait Foo {
def asString = Bar.CaseC
}

// other example
def bar =
sealed trait GADT2[A] extends Product with Serializable

object GADT2 {
case class IsDir(path: String) extends GADT2[_root_.scala.Boolean]
case class Exists(path: String) extends GADT2[_root_.scala.Boolean]
case class ReadBytes(path: String) extends GADT2[_root_.scala.Array[_root_.scala.Byte]]
case class CopyOver(src: Seq[_root_.scala.Byte], path: String) extends GADT2[Int]
}

0 comments on commit d1255f3

Please sign in to comment.