diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/RefChecks.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 121 |
1 files changed, 68 insertions, 53 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 3b2e07bdbd..da269168ec 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -6,15 +6,17 @@ package scala.tools.nsc package typechecker -import symtab.Flags._ -import scala.collection.{ mutable, immutable } -import transform.InfoTransform -import scala.collection.mutable.ListBuffer import scala.language.postfixOps + +import scala.collection.mutable +import scala.collection.mutable.ListBuffer import scala.tools.nsc.settings.ScalaVersion -import scala.tools.nsc.settings.AnyScalaVersion import scala.tools.nsc.settings.NoScalaVersion +import symtab.Flags._ +import transform.InfoTransform + + /** <p> * Post-attribution checking and transformation. * </p> @@ -48,7 +50,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans import global._ import definitions._ - import typer.{typed, typedOperator, atOwner} + import typer.typed /** the following two members override abstract members in Transform */ val phaseName: String = "refchecks" @@ -86,17 +88,19 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans if (sym.hasAccessBoundary) "" + sym.privateWithin.name else "" ) - def overridesTypeInPrefix(tp1: Type, tp2: Type, prefix: Type): Boolean = (tp1.dealiasWiden, tp2.dealiasWiden) match { + def overridesTypeInPrefix(tp1: Type, tp2: Type, prefix: Type, isModuleOverride: Boolean): Boolean = (tp1.dealiasWiden, tp2.dealiasWiden) match { case (MethodType(List(), rtp1), NullaryMethodType(rtp2)) => rtp1 <:< rtp2 case (NullaryMethodType(rtp1), MethodType(List(), rtp2)) => rtp1 <:< rtp2 case (TypeRef(_, sym, _), _) if sym.isModuleClass => - overridesTypeInPrefix(NullaryMethodType(tp1), tp2, prefix) + overridesTypeInPrefix(NullaryMethodType(tp1), tp2, prefix, isModuleOverride) case _ => def classBoundAsSeen(tp: Type) = tp.typeSymbol.classBound.asSeenFrom(prefix, tp.typeSymbol.owner) - - (tp1 <:< tp2) || ( // object override check + (tp1 <:< tp2) || isModuleOverride && ( + // Object override check. This requires that both the overridden and the overriding member are object + // definitions. The overriding module type is allowed to replace the original one with the same name + // as long as it conform to the original non-singleton type. tp1.typeSymbol.isModuleClass && tp2.typeSymbol.isModuleClass && { val cb1 = classBoundAsSeen(tp1) val cb2 = classBoundAsSeen(tp2) @@ -518,7 +522,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } def checkOverrideTerm() { other.cookJavaRawInfo() // #2454 - if (!overridesTypeInPrefix(lowType, highType, rootType)) { // 8 + if (!overridesTypeInPrefix(lowType, highType, rootType, low.isModuleOrModuleClass && high.isModuleOrModuleClass)) { // 8 overrideTypeError() explainTypes(lowType, highType) } @@ -1150,11 +1154,13 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def toConstructor(pos: Position, tpe: Type): Tree = { val rtpe = tpe.finalResultType assert(rtpe.typeSymbol hasFlag CASE, tpe) - localTyper.typedOperator { + val tree = localTyper.typedOperator { atPos(pos) { Select(New(TypeTree(rtpe)), rtpe.typeSymbol.primaryConstructor) } } + checkUndesiredProperties(rtpe.typeSymbol, tree.pos) + tree } override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { @@ -1182,59 +1188,54 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans private def eliminateModuleDefs(moduleDef: Tree): List[Tree] = exitingRefchecks { val ModuleDef(_, _, impl) = moduleDef val module = moduleDef.symbol - val moduleClass = module.moduleClass val site = module.owner val moduleName = module.name.toTermName // The typer doesn't take kindly to seeing this ClassDef; we have to // set NoType so it will be ignored. - val cdef = ClassDef(moduleClass, impl) setType NoType - - // This code is related to the fix of SI-9375, which stops adding `readResolve` methods to - // non-static (nested) modules. Before the fix, the method would cause the module accessor - // to become notPrivate. To prevent binary changes in the 2.11.x branch, we mimic that behavior. - // There is a bit of code duplication between here and SyntheticMethods. We cannot call - // makeNotPrivate already in SyntheticMethod: that is during type checking, and not all references - // are resolved yet, so we cannot rename a definition. This code doesn't exist in the 2.12.x branch. - def hasConcreteImpl(name: Name) = moduleClass.info.member(name).alternatives exists (m => !m.isDeferred) - val hadReadResolveBeforeSI9375 = moduleClass.isSerializable && !hasConcreteImpl(nme.readResolve) - if (hadReadResolveBeforeSI9375) - moduleClass.sourceModule.makeNotPrivate(moduleClass.sourceModule.owner) - - // Create the module var unless the immediate owner is a class and - // the module var already exists there. See SI-5012, SI-6712. - def findOrCreateModuleVar() = { - val vsym = ( - if (site.isTerm) NoSymbol - else site.info decl nme.moduleVarName(moduleName) - ) - vsym orElse (site newModuleVarSymbol module) - } - def newInnerObject() = { - // Create the module var unless it is already in the module owner's scope. - // The lookup is on module.enclClass and not module.owner lest there be a - // nullary method between us and the class; see SI-5012. - val moduleVar = findOrCreateModuleVar() - val rhs = gen.newModule(module, moduleVar.tpe) - val body = if (site.isTrait) rhs else gen.mkAssignAndReturn(moduleVar, rhs) - val accessor = DefDef(module, body.changeOwner(moduleVar -> module)) - - ValDef(moduleVar) :: accessor :: Nil - } + val cdef = ClassDef(module.moduleClass, impl) setType NoType + def matchingInnerObject() = { val newFlags = (module.flags | STABLE) & ~MODULE - val newInfo = NullaryMethodType(moduleClass.tpe) + val newInfo = NullaryMethodType(module.moduleClass.tpe) val accessor = site.newMethod(moduleName, module.pos, newFlags) setInfoAndEnter newInfo DefDef(accessor, Select(This(site), module)) :: Nil } val newTrees = cdef :: ( if (module.isStatic) + // trait T { def f: Object }; object O extends T { object f }. Need to generate method f in O. if (module.isOverridingSymbol) matchingInnerObject() else Nil else - newInnerObject() + newInnerObject(site, module) ) transformTrees(newTrees map localTyper.typedPos(moduleDef.pos)) } + def newInnerObject(site: Symbol, module: Symbol): List[Tree] = { + if (site.isTrait) + DefDef(module, EmptyTree) :: Nil + else { + val moduleVar = site newModuleVarSymbol module + // used for the mixin case: need a new symbol owned by the subclass for the accessor, rather than repurposing the module symbol + def mkAccessorSymbol = + site.newMethod(module.name.toTermName, site.pos, STABLE | MODULE | MIXEDIN) + .setInfo(moduleVar.tpe) + .andAlso(self => if (module.isPrivate) self.expandName(module.owner)) + + val accessor = if (module.owner == site) module else mkAccessorSymbol + val accessorDef = DefDef(accessor, gen.mkAssignAndReturn(moduleVar, gen.newModule(module, moduleVar.tpe)).changeOwner(moduleVar -> accessor)) + + ValDef(moduleVar) :: accessorDef :: Nil + } + } + + def mixinModuleDefs(clazz: Symbol): List[Tree] = { + val res = for { + mixinClass <- clazz.mixinClasses.iterator + module <- mixinClass.info.decls.iterator.filter(_.isModule) + newMember <- newInnerObject(clazz, module) + } yield transform(localTyper.typedPos(clazz.pos)(newMember)) + res.toList + } def transformStat(tree: Tree, index: Int): List[Tree] = tree match { case t if treeInfo.isSelfConstrCall(t) => @@ -1480,10 +1481,13 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case m: MemberDef => val sym = m.symbol applyChecks(sym.annotations) - // validate implicitNotFoundMessage - analyzer.ImplicitNotFoundMsg.check(sym) foreach { warn => - reporter.warning(tree.pos, f"Invalid implicitNotFound message for ${sym}%s${sym.locationString}%s:%n$warn") - } + + def messageWarning(name: String)(warn: String) = + reporter.warning(tree.pos, f"Invalid $name message for ${sym}%s${sym.locationString}%s:%n$warn") + + // validate implicitNotFoundMessage and implicitAmbiguousMessage + analyzer.ImplicitNotFoundMsg.check(sym) foreach messageWarning("implicitNotFound") + analyzer.ImplicitAmbiguousMsg.check(sym) foreach messageWarning("implicitAmbiguous") case tpt@TypeTree() => if(tpt.original != null) { @@ -1526,11 +1530,21 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } private def transformCaseApply(tree: Tree) = { + def loop(t: Tree): Unit = t match { + case Ident(_) => + checkUndesiredProperties(t.symbol, t.pos) + case Select(qual, _) => + checkUndesiredProperties(t.symbol, t.pos) + loop(qual) + case _ => + } + tree foreach { case i@Ident(_) => enterReference(i.pos, i.symbol) // SI-5390 need to `enterReference` for `a` in `a.B()` case _ => } + loop(tree) toConstructor(tree.pos, tree.tpe) } @@ -1669,11 +1683,12 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // SI-7870 default getters for constructors live in the companion module checkOverloadedRestrictions(currentOwner, currentOwner.companionModule) val bridges = addVarargBridges(currentOwner) + val moduleDesugared = if (currentOwner.isTrait) Nil else mixinModuleDefs(currentOwner) checkAllOverrides(currentOwner) checkAnyValSubclass(currentOwner) if (currentOwner.isDerivedValueClass) currentOwner.primaryConstructor makeNotPrivate NoSymbol // SI-6601, must be done *after* pickler! - if (bridges.nonEmpty) deriveTemplate(tree)(_ ::: bridges) else tree + if (bridges.nonEmpty || moduleDesugared.nonEmpty) deriveTemplate(tree)(_ ::: bridges ::: moduleDesugared) else tree case dc@TypeTreeWithDeferredRefCheck() => abort("adapt should have turned dc: TypeTreeWithDeferredRefCheck into tpt: TypeTree, with tpt.original == dc") case tpt@TypeTree() => |