From dde82ae61685698e66cb260ed1d66a0ba1b3c2da Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 17 Nov 2016 17:57:13 +1000 Subject: 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. Fixes scala/scala-dev#268 --- .../tools/nsc/transform/AccessorSynthesis.scala | 2 +- .../scala/tools/nsc/transform/Fields.scala | 29 +++++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala b/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala index a1923ead21..a0bba46398 100644 --- a/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala +++ b/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala @@ -332,7 +332,7 @@ trait AccessorSynthesis extends Transform with ast.TreeDSL { val isUnit = isUnitGetter(lazyAccessor) val selectVar = if (isUnit) UNIT else Select(thisRef, lazyVar) - val storeRes = if (isUnit) rhsAtSlowDef else Assign(selectVar, rhsAtSlowDef) + val storeRes = if (isUnit) rhsAtSlowDef else Assign(selectVar, fields.castHack(rhsAtSlowDef, lazyVar.info)) def needsInit = mkTest(lazyAccessor) val doInit = Block(List(storeRes), mkSetFlag(lazyAccessor)) diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index 0fe7a82b15..b09223110a 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -510,6 +510,16 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor def nonStaticModuleToMethod(module: Symbol): Unit = if (!module.isStatic) module setFlag METHOD | STABLE + // scala/scala-dev#219, scala/scala-dev#268 + // Cast to avoid spurious mismatch in paths containing trait vals that have + // not been rebound to accessors in the subclass we're in now. + // For example, for a lazy val mixed into a class, the lazy var's info + // will not refer to symbols created during our info transformer, + // so if its type depends on a val that is now implemented after the info transformer, + // we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`. + // TODO: could we rebind more aggressively? consider overriding in type equality? + def castHack(tree: Tree, pt: Type) = gen.mkAsInstanceOf(tree, pt) + class FieldsTransformer(unit: CompilationUnit) extends TypingTransformer(unit) with CheckedAccessorTreeSynthesis { protected def typedPos(pos: Position)(tree: Tree): Tree = localTyper.typedPos(pos)(tree) @@ -596,15 +606,6 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor // synth trees for accessors/fields and trait setters when they are mixed into a class def fieldsAndAccessors(clazz: Symbol): List[Tree] = { - // scala/scala-dev#219 - // Cast to avoid spurious mismatch in paths containing trait vals that have - // not been rebound to accessors in the subclass we're in now. - // For example, for a lazy val mixed into a class, the lazy var's info - // will not refer to symbols created during our info transformer, - // so if its type depends on a val that is now implemented after the info transformer, - // we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`. - // TODO: could we rebind more aggressively? consider overriding in type equality? - def cast(tree: Tree, pt: Type) = gen.mkAsInstanceOf(tree, pt) // Could be NoSymbol, which denotes an error, but it's refchecks' job to report it (this fallback is for robustness). // 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 // accessor created by newMatchingModuleAccessor for a static module that does need an accessor // (because there's a matching member in a super class) if (getter.asTerm.referenced.isModule) - mkAccessor(getter)(cast(Select(This(clazz), getter.asTerm.referenced), getter.info.resultType)) + mkAccessor(getter)(castHack(Select(This(clazz), getter.asTerm.referenced), getter.info.resultType)) else { val fieldMemoization = fieldMemoizationIn(getter, clazz) // TODO: drop getter for constant? (when we no longer care about producing identical bytecode?) if (fieldMemoization.constantTyped) mkAccessor(getter)(gen.mkAttributedQualifier(fieldMemoization.tp)) else fieldAccess(getter) match { case NoSymbol => EmptyTree - case fieldSel => mkAccessor(getter)(cast(Select(This(clazz), fieldSel), getter.info.resultType)) + case fieldSel => mkAccessor(getter)(castHack(Select(This(clazz), fieldSel), getter.info.resultType)) } } @@ -636,7 +637,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor else fieldAccess(setter) match { case NoSymbol => EmptyTree case fieldSel => afterOwnPhase { // the assign only type checks after our phase (assignment to val) - mkAccessor(setter)(Assign(Select(This(clazz), fieldSel), cast(Ident(setter.firstParam), fieldSel.info))) + mkAccessor(setter)(Assign(Select(This(clazz), fieldSel), castHack(Ident(setter.firstParam), fieldSel.info))) } } @@ -657,7 +658,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor val selectSuper = Select(Super(This(clazz), tpnme.EMPTY), getter.name) val lazyVar = lazyVarOf(getter) - val rhs = cast(Apply(selectSuper, Nil), lazyVar.info) + val rhs = castHack(Apply(selectSuper, Nil), lazyVar.info) synthAccessorInClass.expandLazyClassMember(lazyVar, getter, rhs) } @@ -708,7 +709,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor val transformedRhs = atOwner(statSym)(transform(rhs)) if (rhs == EmptyTree) mkAccessor(statSym)(EmptyTree) - else if (currOwner.isTrait) mkAccessor(statSym)(transformedRhs) + else if (currOwner.isTrait) mkAccessor(statSym)(castHack(transformedRhs, statSym.info.resultType)) else if (!currOwner.isClass) mkLazyLocalDef(vd.symbol, transformedRhs) else { // TODO: make `synthAccessorInClass` a field and update it in atOwner? -- cgit v1.2.3