Skip to content

Commit 4d67c39

Browse files
committed
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 05016d9 commit 4d67c39

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

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

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

test/files/pos/sd219.scala

+11
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)