Skip to content

Commit d1255f3

Browse files
committed
Fix needsOuterIfReferenced
scala#17135 shows that traits also need an outer accessor if they are in a toplevel method (or lazy val). Fixes scala#17135
1 parent 6e5be23 commit d1255f3

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,9 @@ object ExplicitOuter {
199199

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

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

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

231233
/** The outer accessor of class `cls`. To find it is a bit tricky. The
232234
* 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+
}

0 commit comments

Comments
 (0)