Skip to content

Commit 733aaf4

Browse files
adriaanmretronym
authored andcommitted
Avoid mismatched symbols in fields phase
The info of the var that stores a trait's lazy val's computed value is expressed in terms of symbols that exist before the fields phase. When we're implementing the lazy val in a subclass of that trait, we now see symbols created by the fields phase, which results in mismatches between the types of the lhs and rhs in the assignment of `lazyVar = super.lazyImpl`. So, type check the super-call to the trait's lazy accessor before our own phase. If the lazy var's info depends on a val that is now implemented by an accessor synthesize by our info transformer, we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`, unless we also run before our own phase (like when we were creating the info for the lazy var). This was revealed by Hanns Holger Rutz's efforts in compiling scala-refactoring's test suite (reported on scala-internals). Fixes scala/scala-dev#219
1 parent 9f16751 commit 733aaf4

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

src/compiler/scala/tools/nsc/transform/Fields.scala

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -633,8 +633,21 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
633633
val synthAccessorInClass = new SynthLazyAccessorsIn(clazz)
634634
def superLazy(getter: Symbol): List[ValOrDefDef] = {
635635
assert(!clazz.isTrait)
636-
// this contortion was the only way I can get the super select to be type checked correctly.. TODO: why does SelectSuper not work?
637-
val rhs = Apply(Select(Super(This(clazz), tpnme.EMPTY), getter.name), Nil)
636+
// this contortion was the only way I can get the super select to be type checked correctly..
637+
// TODO: why does SelectSuper not work?
638+
val selectSuper = Select(Super(This(clazz), tpnme.EMPTY), getter.name)
639+
640+
// scala/scala-dev#219
641+
// Type check the super-call to the trait's lazy accessor before our own phase,
642+
// so that we don't see other accessor symbols we mix into the class.
643+
// The lazy var's info will not refer to symbols created during our info transformer,
644+
// so if its type depends on a val that is now implemented after the info transformer,
645+
// we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`,
646+
// unless we also run before our own phase (like when we were creating the info for the lazy var).
647+
//
648+
// TODO: are there other spots where we may get a mismatch like this?
649+
val rhs = exitingUncurry(typedPos(getter.pos.focus)(Apply(selectSuper, Nil)))
650+
638651
explodeThicket(synthAccessorInClass.expandLazyClassMember(lazyVarOf(getter), getter, rhs, Map.empty)).asInstanceOf[List[ValOrDefDef]]
639652
}
640653

test/files/pos/sd219.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class Global { class Name }
2+
3+
trait CommonPrintUtils {
4+
val global: Global
5+
6+
lazy val precedence: global.Name => Int = ???
7+
}
8+
9+
trait CompilerProvider { val global: Global = ??? }
10+
11+
class AbstractPrinter extends CommonPrintUtils with CompilerProvider

0 commit comments

Comments
 (0)