Skip to content

Commit 8aa4c2d

Browse files
committed
Fix more compiler crashes with fields, refinement types
In the same manner as scala/scala-dev#219, the placement of the fields phase after uncurry is presenting some challenges in keeping our trees type correct. This commit whacks a few more moles by adding a casts in the body of synthetic methods.
1 parent 73678d4 commit 8aa4c2d

File tree

3 files changed

+33
-15
lines changed

3 files changed

+33
-15
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ trait AccessorSynthesis extends Transform with ast.TreeDSL {
332332

333333
val isUnit = isUnitGetter(lazyAccessor)
334334
val selectVar = if (isUnit) UNIT else Select(thisRef, lazyVar)
335-
val storeRes = if (isUnit) rhsAtSlowDef else Assign(selectVar, rhsAtSlowDef)
335+
val storeRes = if (isUnit) rhsAtSlowDef else Assign(selectVar, fields.castHack(rhsAtSlowDef, lazyVar.info.resultType))
336336

337337
def needsInit = mkTest(lazyAccessor)
338338
val doInit = Block(List(storeRes), mkSetFlag(lazyAccessor))

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

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,16 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
510510
def nonStaticModuleToMethod(module: Symbol): Unit =
511511
if (!module.isStatic) module setFlag METHOD | STABLE
512512

513+
// scala/scala-dev#219, scala/scala-dev#268
514+
// Cast to avoid spurious mismatch in paths containing trait vals that have
515+
// not been rebound to accessors in the subclass we're in now.
516+
// For example, for a lazy val mixed into a class, the lazy var's info
517+
// will not refer to symbols created during our info transformer,
518+
// so if its type depends on a val that is now implemented after the info transformer,
519+
// we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`.
520+
// TODO: could we rebind more aggressively? consider overriding in type equality?
521+
def castHack(tree: Tree, pt: Type) = gen.mkAsInstanceOf(tree, pt)
522+
513523
class FieldsTransformer(unit: CompilationUnit) extends TypingTransformer(unit) with CheckedAccessorTreeSynthesis {
514524
protected def typedPos(pos: Position)(tree: Tree): Tree = localTyper.typedPos(pos)(tree)
515525

@@ -596,15 +606,6 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
596606

597607
// synth trees for accessors/fields and trait setters when they are mixed into a class
598608
def fieldsAndAccessors(clazz: Symbol): List[Tree] = {
599-
// scala/scala-dev#219
600-
// Cast to avoid spurious mismatch in paths containing trait vals that have
601-
// not been rebound to accessors in the subclass we're in now.
602-
// For example, for a lazy val mixed into a class, the lazy var's info
603-
// will not refer to symbols created during our info transformer,
604-
// so if its type depends on a val that is now implemented after the info transformer,
605-
// we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`.
606-
// TODO: could we rebind more aggressively? consider overriding in type equality?
607-
def cast(tree: Tree, pt: Type) = gen.mkAsInstanceOf(tree, pt)
608609

609610
// Could be NoSymbol, which denotes an error, but it's refchecks' job to report it (this fallback is for robustness).
610611
// This is the result of overriding a val with a def, so that no field is found in the subclass.
@@ -615,14 +616,14 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
615616
// accessor created by newMatchingModuleAccessor for a static module that does need an accessor
616617
// (because there's a matching member in a super class)
617618
if (getter.asTerm.referenced.isModule)
618-
mkAccessor(getter)(cast(Select(This(clazz), getter.asTerm.referenced), getter.info.resultType))
619+
mkAccessor(getter)(castHack(Select(This(clazz), getter.asTerm.referenced), getter.info.resultType))
619620
else {
620621
val fieldMemoization = fieldMemoizationIn(getter, clazz)
621622
// TODO: drop getter for constant? (when we no longer care about producing identical bytecode?)
622623
if (fieldMemoization.constantTyped) mkAccessor(getter)(gen.mkAttributedQualifier(fieldMemoization.tp))
623624
else fieldAccess(getter) match {
624625
case NoSymbol => EmptyTree
625-
case fieldSel => mkAccessor(getter)(cast(Select(This(clazz), fieldSel), getter.info.resultType))
626+
case fieldSel => mkAccessor(getter)(castHack(Select(This(clazz), fieldSel), getter.info.resultType))
626627
}
627628
}
628629

@@ -636,7 +637,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
636637
else fieldAccess(setter) match {
637638
case NoSymbol => EmptyTree
638639
case fieldSel => afterOwnPhase { // the assign only type checks after our phase (assignment to val)
639-
mkAccessor(setter)(Assign(Select(This(clazz), fieldSel), cast(Ident(setter.firstParam), fieldSel.info)))
640+
mkAccessor(setter)(Assign(Select(This(clazz), fieldSel), castHack(Ident(setter.firstParam), fieldSel.info)))
640641
}
641642
}
642643

@@ -657,7 +658,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
657658
val selectSuper = Select(Super(This(clazz), tpnme.EMPTY), getter.name)
658659

659660
val lazyVar = lazyVarOf(getter)
660-
val rhs = cast(Apply(selectSuper, Nil), lazyVar.info)
661+
val rhs = castHack(Apply(selectSuper, Nil), lazyVar.info)
661662

662663
synthAccessorInClass.expandLazyClassMember(lazyVar, getter, rhs)
663664
}
@@ -708,7 +709,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
708709
val transformedRhs = atOwner(statSym)(transform(rhs))
709710

710711
if (rhs == EmptyTree) mkAccessor(statSym)(EmptyTree)
711-
else if (currOwner.isTrait) mkAccessor(statSym)(transformedRhs)
712+
else if (currOwner.isTrait) mkAccessor(statSym)(castHack(transformedRhs, statSym.info.resultType))
712713
else if (!currOwner.isClass) mkLazyLocalDef(vd.symbol, transformedRhs)
713714
else {
714715
// TODO: make `synthAccessorInClass` a field and update it in atOwner?

test/files/pos/sd268.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Context(val v : AnyRef)
2+
3+
trait AbidePlugin {
4+
val someVal = ""
5+
6+
val x = null.asInstanceOf[Context { val v : someVal.type }]
7+
lazy val y = null.asInstanceOf[Context { val v : someVal.type }]
8+
var z = null.asInstanceOf[Context { val v : someVal.type }]
9+
}
10+
11+
class C {
12+
val someVal = ""
13+
14+
val x = null.asInstanceOf[Context { val v : someVal.type }]
15+
lazy val y = null.asInstanceOf[Context { val v : someVal.type }]
16+
var z = null.asInstanceOf[Context { val v : someVal.type }]
17+
}

0 commit comments

Comments
 (0)