From 8bfe94c5952d2079069ccd58b9022879493ea0d6 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 2 Nov 2009 16:48:56 +0000 Subject: [PATCH] Fixed #2545. Fixed problem with cyclic dependcies when adding package objects. Prepared for module expansion to lazy vals. git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@19375 5e8d7ff9-d8ef-0310-90f0-a4852d11357a --- build.xml | 22 ++++++++++++++++ .../scala/tools/nsc/ast/TreeGen.scala | 14 +++++++++++ .../tools/nsc/symtab/SymbolLoaders.scala | 5 ++-- .../scala/tools/nsc/typechecker/Namers.scala | 14 ++++------- .../tools/nsc/typechecker/RefChecks.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 20 ++++++++++++--- src/library/scala/package.scala | 2 +- src/library/scala/util/control/Breaks.scala | 25 ++++++++++++++++--- test/files/pos/t2545.scala | 10 ++++++++ 9 files changed, 93 insertions(+), 21 deletions(-) create mode 100755 test/files/pos/t2545.scala diff --git a/build.xml b/build.xml index 949eb3a7e..cf26bc8f9 100644 --- a/build.xml +++ b/build.xml @@ -516,6 +516,18 @@ QUICK BUILD (QUICK) + + + + + + + @@ -963,6 +976,14 @@ BOOTSTRAPPING BUILD (STRAP) addparams="${scalac.args.all}"> + + + + diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index b86966da9..d2eaee779 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -239,6 +239,20 @@ abstract class TreeGen ) } + // var m$: T = null; or, if class member: local var m$: T = _; + /*!!! + def mkModuleValDef(accessor: Symbol) = { + val mval = accessor.owner.newValue(accessor.pos.focus, nme.moduleVarName(accessor.name)) + .setInfo(accessor.tpe.finalResultType) + .setFlag(LAZY); + if (mval.owner.isClass) { + mval setFlag (PRIVATE | LOCAL | SYNTHETIC) + mval.owner.info.decls.enter(mval) + } + ValDef(mval, New(TypeTree(mval.tpe), List(List()))) + } + */ + // var m$: T = null; or, if class member: local var m$: T = _; def mkModuleVarDef(accessor: Symbol) = { val mvar = accessor.owner.newVariable(accessor.pos.focus, nme.moduleVarName(accessor.name)) diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index e521a0e57..972f30f93 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -164,9 +164,10 @@ abstract class SymbolLoaders { // if there's a $member object, enter its members as well. val pkgModule = root.info.decl(nme.PACKAGEkw) - if (pkgModule.isModule && !(pkgModule.rawInfo.isInstanceOf[SourcefileLoader] && - classpath.name == "scala")) + if (pkgModule.isModule && !pkgModule.rawInfo.isInstanceOf[SourcefileLoader]) { + //println("open "+pkgModule)//DEBUG openPackageModule(pkgModule) + } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index e5f0b57a2..2c67c289d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -359,9 +359,6 @@ trait Namers { self: Analyzer => tree.symbol = enterModuleSymbol(tree) tree.symbol.moduleClass.setInfo(namerOf(tree.symbol).moduleClassTypeCompleter((tree))) finish - if (tree.symbol.name == nme.PACKAGEkw && tree.symbol.owner != ScalaPackageClass) { - loaders.openPackageModule(tree.symbol) - } case vd @ ValDef(mods, name, tp, rhs) => if ((!context.owner.isClass || @@ -392,7 +389,7 @@ trait Namers { self: Analyzer => if (mods.isDeferred) { getter setPos tree.pos // unfocus getter position, because there won't be a separate value } else { - var vsym = + val vsym = if (!context.owner.isClass) { assert(mods.isLazy) // if not a field, it has to be a lazy val owner.newValue(tree.pos, name + "$lzy" ).setFlag(mods.flags | MUTABLE) @@ -1132,14 +1129,13 @@ trait Namers { self: Analyzer => newNamer(context.makeNewScope(tree, sym)).classSig(tparams, impl) case ModuleDef(_, _, impl) => - /** no, does not work here. - if (tree.symbol.name == nme.PACKAGEkw) { - loaders.openPackageModule(tree.symbol) - } - */ val clazz = sym.moduleClass clazz.setInfo(newNamer(context.makeNewScope(tree, clazz)).templateSig(impl)) //clazz.typeOfThis = singleType(sym.owner.thisType, sym); + tree.symbol.setInfo(clazz.tpe) // initialize module to avoid cycles + if (tree.symbol.name == nme.PACKAGEkw) { + loaders.openPackageModule(tree.symbol) + } clazz.tpe case DefDef(mods, _, tparams, vparamss, tpt, rhs) => diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 84e23a354..5c7abda64 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -780,7 +780,7 @@ abstract class RefChecks extends InfoTransform { val cdef = ClassDef(mods | MODULE, name, List(), impl) .setPos(tree.pos) .setSymbol(sym.moduleClass) - .setType(NoType); + .setType(NoType) if (sym.isStatic) { if (!sym.allOverriddenSymbols.isEmpty) { val factory = sym.owner.newMethod(sym.pos, sym.name) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index e9755559f..5e5831038 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1420,10 +1420,17 @@ trait Typers { self: Analyzer => templ setSymbol clazz.newLocalDummy(templ.pos) val self1 = templ.self match { case vd @ ValDef(mods, name, tpt, EmptyTree) => - val tpt1 = checkNoEscaping.privates(clazz.thisSym, typedType(tpt)) + val tpt1 = + checkNoEscaping.privates( + clazz.thisSym, + treeCopy.TypeTree(tpt) setType vd.symbol.tpe) treeCopy.ValDef(vd, mods, name, tpt1, EmptyTree) setType NoType } - if (self1.name != nme.WILDCARD) context.scope enter self1.symbol +// was: +// val tpt1 = checkNoEscaping.privates(clazz.thisSym, typedType(tpt)) +// treeCopy.ValDef(vd, mods, name, tpt1, EmptyTree) setType NoType +// but this leads to cycles for existential self types ==> #2545 + if (self1.name != nme.WILDCARD) context.scope enter self1.symbol val selfType = if (clazz.isAnonymousClass && !phase.erasedTypes) intersectionType(clazz.info.parents, clazz.owner) @@ -2944,13 +2951,18 @@ trait Typers { self: Analyzer => .setOriginal(tpt1) .setType(appliedType(tpt1.tpe, context.undetparams map (_.tpe))) } + /** If current tree appears in > * return `tp with x.type' else return `tp'. */ def narrowRhs(tp: Type) = { var sym = context.tree.symbol - if (sym != null && sym != NoSymbol && sym.owner.isClass && sym.getter(sym.owner) != NoSymbol) - sym = sym.getter(sym.owner) + if (sym != null && sym != NoSymbol) + if (sym.owner.isClass) { + if (sym.getter(sym.owner) != NoSymbol) sym = sym.getter(sym.owner) + } else if (sym hasFlag LAZY) { + if (sym.lazyAccessor != NoSymbol) sym = sym.lazyAccessor + } context.tree match { case ValDef(mods, _, _, Apply(Select(`tree`, _), _)) if !(mods hasFlag MUTABLE) => val pre = if (sym.owner.isClass) sym.owner.thisType else NoPrefix diff --git a/src/library/scala/package.scala b/src/library/scala/package.scala index 8aed92949..f62efb08d 100644 --- a/src/library/scala/package.scala +++ b/src/library/scala/package.scala @@ -11,7 +11,7 @@ package object scala { - type Travarsable[+A] = scala.collection.Traversable[A] + type Traversable[+A] = scala.collection.Traversable[A] val Traversable = scala.collection.Traversable type Iterable[+A] = scala.collection.Iterable[A] diff --git a/src/library/scala/util/control/Breaks.scala b/src/library/scala/util/control/Breaks.scala index 3ceca71e7..7e658a434 100644 --- a/src/library/scala/util/control/Breaks.scala +++ b/src/library/scala/util/control/Breaks.scala @@ -11,10 +11,11 @@ package scala.util.control -/** An object that can be used for the break control abstraction. +/** A class that can be instantiated for the break control abstraction. * Example usage:
  *
- *  import Breaks.{break, breakable}
+ *  val mybreaks = new Breaks
+ *  import mybreaks.{break, breakable}
  *
  *  breakable {
  *    for (...) {
@@ -22,6 +23,8 @@ package scala.util.control
  *    }
  *  }
* + * Calls to break from one instantiation of Breaks will never + * target breakable objects of some other instantion. */ class Breaks { @@ -37,11 +40,25 @@ class Breaks { } } - /* Break from closest enclosing breakable block */ + /* Break from dynamically closest enclosing breakable block + * @note this might be different than the statically closest enclosing + * block! + */ def break { throw breakException } } -/** A singleton object providing the Break functionality */ +/** An object that can be used for the break control abstraction. + * Example usage:
+ *
+ *  import Breaks.{break, breakable}
+ *
+ *  breakable {
+ *    for (...) {
+ *      if (...) break
+ *    }
+ *  }
+ * + */ object Breaks extends Breaks private class BreakException extends RuntimeException with ControlException diff --git a/test/files/pos/t2545.scala b/test/files/pos/t2545.scala new file mode 100755 index 000000000..b4238fb71 --- /dev/null +++ b/test/files/pos/t2545.scala @@ -0,0 +1,10 @@ +trait Frog[T] { + def hello: T + def size: Int + } + + trait OnlyWithFrogs { + self: Frog[_] => + + def sizeStr = size.toString + }