Skip to content

Fix needsOuterIfReferenced #17159

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

Merged
merged 2 commits into from
Apr 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import core.Decorators._
import core.StdNames.nme
import core.Names._
import core.NameOps._
import core.NameKinds.SuperArgName
import SymUtils._
import dotty.tools.dotc.ast.tpd

Expand Down Expand Up @@ -197,11 +198,17 @@ object ExplicitOuter {
private def outerAccName(cls: ClassSymbol)(using Context): TermName =
nme.OUTER.expandedName(cls)

private def outerOwner(sym: Symbol)(using Context): Symbol =
val owner = sym.effectiveOwner
if owner.name.is(SuperArgName) || owner.isLocalDummy
then owner.enclosingClass
else owner

/** 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
|| outerOwner(cls).isStaticOwner
|| cls.is(PureInterface)
)

/** Class unconditionally needs an outer pointer. This is the case if
Expand All @@ -226,7 +233,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]
}
3 changes: 3 additions & 0 deletions tests/pos/t0049.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
class C1(x: AnyRef) {};

class C2 extends C1({ class A extends AnyRef {}; (new A) : AnyRef }) {};

class Outer:
class C2 extends C1({ class A extends AnyRef {}; (new A) : AnyRef }) {};