From 2d3fe5733cbc6bcf06892c8ee3cb19f7987f6b6a Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 29 Oct 2011 19:35:15 +0000 Subject: Fix for crasher in explicitouter. Closes SI-4970, review by moors. --- src/compiler/scala/reflect/internal/TreeGen.scala | 71 +++++++++++----------- .../scala/tools/nsc/transform/ExplicitOuter.scala | 16 +++-- test/files/pos/t4970.scala | 13 ++++ 3 files changed, 60 insertions(+), 40 deletions(-) create mode 100644 test/files/pos/t4970.scala diff --git a/src/compiler/scala/reflect/internal/TreeGen.scala b/src/compiler/scala/reflect/internal/TreeGen.scala index ce7fba6686..fae3975ed5 100644 --- a/src/compiler/scala/reflect/internal/TreeGen.scala +++ b/src/compiler/scala/reflect/internal/TreeGen.scala @@ -64,44 +64,47 @@ abstract class TreeGen { * termSym as the Ident's symbol. In that case, termSym must * not be NoSymbol. */ - def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = tpe match { - case NoPrefix => - EmptyTree - case ThisType(clazz) => - if (clazz.isEffectiveRoot) EmptyTree - else mkAttributedThis(clazz) - case SingleType(pre, sym) => - mkApplyIfNeeded(mkAttributedStableRef(pre, sym)) - case TypeRef(pre, sym, args) => - if (sym.isRoot) { - mkAttributedThis(sym) - } else if (sym.isModuleClass) { - mkApplyIfNeeded(mkAttributedRef(pre, sym.sourceModule)) - } else if (sym.isModule || sym.isClass) { - assert(phase.erasedTypes, tpe) - mkAttributedThis(sym) - } else if (sym.isType) { - assert(termSym != NoSymbol, tpe) - mkAttributedIdent(termSym) setType tpe - } else { - mkAttributedRef(pre, sym) - } + def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = { + def failMessage = "mkAttributedQualifier(" + tpe + ", " + termSym + ")" + tpe match { + case NoPrefix => + EmptyTree + case ThisType(clazz) => + if (clazz.isEffectiveRoot) EmptyTree + else mkAttributedThis(clazz) + case SingleType(pre, sym) => + mkApplyIfNeeded(mkAttributedStableRef(pre, sym)) + case TypeRef(pre, sym, args) => + if (sym.isRoot) { + mkAttributedThis(sym) + } else if (sym.isModuleClass) { + mkApplyIfNeeded(mkAttributedRef(pre, sym.sourceModule)) + } else if (sym.isModule || sym.isClass) { + assert(phase.erasedTypes, failMessage) + mkAttributedThis(sym) + } else if (sym.isType) { + assert(termSym != NoSymbol, failMessage) + mkAttributedIdent(termSym) setType tpe + } else { + mkAttributedRef(pre, sym) + } - case ConstantType(value) => - Literal(value) setType tpe + case ConstantType(value) => + Literal(value) setType tpe - case AnnotatedType(_, atp, _) => - mkAttributedQualifier(atp) + case AnnotatedType(_, atp, _) => + mkAttributedQualifier(atp) - case RefinedType(parents, _) => - // I am unclear whether this is reachable, but - // the following implementation looks logical -Lex - val firstStable = parents.find(_.isStable) - assert(!firstStable.isEmpty, tpe) - mkAttributedQualifier(firstStable.get) + case RefinedType(parents, _) => + // I am unclear whether this is reachable, but + // the following implementation looks logical -Lex + val firstStable = parents.find(_.isStable) + assert(!firstStable.isEmpty, failMessage + " parents = " + parents) + mkAttributedQualifier(firstStable.get) - case _ => - abort("bad qualifier: " + tpe) + case _ => + abort("bad qualifier received: " + failMessage) + } } /** If this is a reference to a method with an empty * parameter list, wrap it in an apply. diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 1bc283841b..192c4e9b59 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -346,12 +346,16 @@ abstract class ExplicitOuter extends InfoTransform * @pre mixinClass is an inner class */ def mixinOuterAccessorDef(mixinClass: Symbol): Tree = { - val outerAcc = outerAccessor(mixinClass) overridingSymbol currentClass - assert(outerAcc != NoSymbol) - val path = - if (mixinClass.owner.isTerm) THIS(mixinClass.owner.enclClass) - else gen.mkAttributedQualifier(currentClass.thisType baseType mixinClass prefix) - + val outerAcc = outerAccessor(mixinClass) overridingSymbol currentClass + def mixinPrefix = currentClass.thisType baseType mixinClass prefix; + assert(outerAcc != NoSymbol, "No outer accessor for inner mixin " + mixinClass + " in " + currentClass) + // I added the mixinPrefix.typeArgs.nonEmpty condition to address the + // crash in SI-4970. I feel quite sure this can be improved. + val path = ( + if (mixinClass.owner.isTerm) gen.mkAttributedThis(mixinClass.owner.enclClass) + else if (mixinPrefix.typeArgs.nonEmpty) gen.mkAttributedThis(mixinPrefix.typeSymbol) + else gen.mkAttributedQualifier(mixinPrefix) + ) localTyper typed { (DEF(outerAcc) withPos currentClass.pos) === { // Need to cast for nested outer refs in presence of self-types. See ticket #3274. diff --git a/test/files/pos/t4970.scala b/test/files/pos/t4970.scala new file mode 100644 index 0000000000..f2f284f919 --- /dev/null +++ b/test/files/pos/t4970.scala @@ -0,0 +1,13 @@ +trait OuterClass[V <: OuterClass[V]#InnerClass] { + trait InnerClass {self: V => + def method = () + } +} + +trait SubOuterClass[T <: SubOuterClass[T]#SubInnerClass] extends OuterClass[T] { + class SubInnerClass extends super.InnerClass {self: T => } +} + +trait SubOuterClass2[T <: SubOuterClass2[T]#SubInnerClass2] extends OuterClass[T] { + class SubInnerClass2 extends super.InnerClass {self: InnerClass with T => } +} -- cgit v1.2.3