Skip to content

Commit ccf38be

Browse files
authored
Fix needsOuterIfReferenced (#17159)
2 parents 8b635cc + 7296e72 commit ccf38be

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import core.Decorators._
1313
import core.StdNames.nme
1414
import core.Names._
1515
import core.NameOps._
16+
import core.NameKinds.SuperArgName
1617
import SymUtils._
1718
import dotty.tools.dotc.ast.tpd
1819

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

201+
private def outerOwner(sym: Symbol)(using Context): Symbol =
202+
val owner = sym.effectiveOwner
203+
if owner.name.is(SuperArgName) || owner.isLocalDummy
204+
then owner.enclosingClass
205+
else owner
206+
200207
/** Class needs an outer pointer, provided there is a reference to an outer this in it. */
201208
def needsOuterIfReferenced(cls: ClassSymbol)(using Context): Boolean =
202-
!(cls.isStatic ||
203-
cls.owner.enclosingClass.isStaticOwner ||
204-
cls.is(PureInterface)
209+
!(cls.isStatic
210+
|| outerOwner(cls).isStaticOwner
211+
|| cls.is(PureInterface)
205212
)
206213

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

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

231240
/** The outer accessor of class `cls`. To find it is a bit tricky. The
232241
* class might have been moved with new owners between ExplicitOuter and Erasure,

tests/pos/i17135.scala

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package doobie
2+
3+
// original example
4+
def someFunction(param: Int): Int = {
5+
sealed trait Foo {
6+
def asString: String = this match {
7+
case Foo.CaseC => "C"
8+
}
9+
}
10+
object Foo {
11+
// Having an object here crashes the compiler.
12+
object CaseC extends Foo
13+
}
14+
15+
???
16+
}
17+
18+
// minimization
19+
def foo =
20+
class Bar {
21+
// Having an object here crashes the compiler.
22+
lazy val CaseC =
23+
class Baz extends Foo
24+
new Baz()
25+
}
26+
val Bar: Bar = new Bar()
27+
trait Foo {
28+
def asString = Bar.CaseC
29+
}
30+
31+
// variant: outer is lazy val
32+
lazy val lazyfoo =
33+
class Bar {
34+
// Having an object here crashes the compiler.
35+
lazy val CaseC =
36+
class Baz extends Foo
37+
new Baz()
38+
}
39+
val Bar: Bar = new Bar()
40+
trait Foo {
41+
def asString = Bar.CaseC
42+
}
43+
44+
// other example
45+
def bar =
46+
sealed trait GADT2[A] extends Product with Serializable
47+
48+
object GADT2 {
49+
case class IsDir(path: String) extends GADT2[_root_.scala.Boolean]
50+
case class Exists(path: String) extends GADT2[_root_.scala.Boolean]
51+
case class ReadBytes(path: String) extends GADT2[_root_.scala.Array[_root_.scala.Byte]]
52+
case class CopyOver(src: Seq[_root_.scala.Byte], path: String) extends GADT2[Int]
53+
}

tests/pos/t0049.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
class C1(x: AnyRef) {};
22

33
class C2 extends C1({ class A extends AnyRef {}; (new A) : AnyRef }) {};
4+
5+
class Outer:
6+
class C2 extends C1({ class A extends AnyRef {}; (new A) : AnyRef }) {};

0 commit comments

Comments
 (0)