From 7fb9cd47f3a5ce10e1001b9a9aa5672dc38bf16e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 20 Aug 2013 14:34:55 +0200 Subject: Fixes handling of modules in namer. Now we make sure we keep mode invariants at all times. --- src/dotty/tools/dotc/core/NameOps.scala | 5 +- src/dotty/tools/dotc/core/SymDenotations.scala | 19 ++-- .../tools/dotc/core/pickling/ClassfileParser.scala | 2 +- src/dotty/tools/dotc/core/pickling/UnPickler.scala | 2 +- src/dotty/tools/dotc/typer/Namer.scala | 101 ++++++++++++++------- 5 files changed, 84 insertions(+), 45 deletions(-) (limited to 'src/dotty/tools/dotc') diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala index 1ca3bc418..6b365babb 100644 --- a/src/dotty/tools/dotc/core/NameOps.scala +++ b/src/dotty/tools/dotc/core/NameOps.scala @@ -105,9 +105,12 @@ object NameOps { name } - /** Convert this name to a module name */ + /** Convert this module name to corresponding module class name */ def moduleClassName: TypeName = (name ++ tpnme.MODULE_SUFFIX).toTypeName + /** Convert this module class name to corresponding source module name */ + def sourceModuleName: TermName = stripModuleClassSuffix.toTermName + /** If name ends in module class suffix, drop it */ def stripModuleClassSuffix: Name = if (isModuleClassName) name dropRight MODULE_SUFFIX.length else name diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index f05712d78..621023ab7 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -103,10 +103,12 @@ object SymDenotations { } protected[dotc] final def info_=(tp: Type) = { - if ((this is ModuleClass) && !(this is PackageClass)) + def illegal: String = s"illegal type for module $this: $tp" + if (this is Module) // make sure module invariants that allow moduleClass and sourceModule to work are kept. tp match { - case ClassInfo(_, _, _, _, ost) => - assert(ost.isInstanceOf[TermRef] || ost.isInstanceOf[TermSymbol], tp) + case tp: ClassInfo => assert(tp.selfInfo.isInstanceOf[TermRefBySym], illegal) + case tp: NamedType => assert(tp.isInstanceOf[TypeRefBySym], illegal) + case tp: ExprType => assert(tp.resultType.isInstanceOf[TypeRefBySym], illegal) case _ => } myInfo = tp @@ -458,10 +460,7 @@ object SymDenotations { case info: LazyType => info.moduleClass case _ => println(s"missing module class for $name: $myInfo"); NoSymbol } - else { - println(s"missing module class for non-module $name"); - NoSymbol - } + else NoSymbol /** The module implemented by this module class, NoSymbol if not applicable. */ final def sourceModule: Symbol = myInfo match { @@ -1062,7 +1061,7 @@ object SymDenotations { private var myDecls: Scope = EmptyScope private var mySourceModuleFn: () => Symbol = NoSymbolFn - private var myModuleClass: Symbol = NoSymbol + private var myModuleClassFn: () => Symbol = NoSymbolFn def proxy: LazyType = new LazyType { override def complete(denot: SymDenotation) = self.complete(denot) @@ -1070,11 +1069,11 @@ object SymDenotations { def decls: Scope = myDecls def sourceModule: Symbol = mySourceModuleFn() - def moduleClass: Symbol = myModuleClass + def moduleClass: Symbol = myModuleClassFn() def withDecls(decls: Scope): this.type = { myDecls = decls; this } def withSourceModule(sourceModule: => Symbol): this.type = { mySourceModuleFn = () => sourceModule; this } - def withModuleClass(moduleClass: Symbol): this.type = { myModuleClass = moduleClass; this } + def withModuleClass(moduleClass: => Symbol): this.type = { myModuleClassFn = () => moduleClass; this } } val NoSymbolFn = () => NoSymbol diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index ce26c604e..344508c11 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -794,7 +794,7 @@ class ClassfileParser( val start = starts(index) if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) val name = getExternalName(in.getChar(start + 1)) - if (name.isModuleClassName) c = cctx.requiredModule(name.stripModuleClassSuffix.asTermName) + if (name.isModuleClassName) c = cctx.requiredModule(name.sourceModuleName) else c = classNameToSymbol(name) values(index) = c } diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index d99bc0278..e2f1af5f9 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -456,7 +456,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: val unpickler = new LocalUnpickler() withDecls symScope(cls) if (flags is ModuleClass) unpickler withSourceModule ( - cls.owner.decls.lookup(cls.name.stripModuleClassSuffix.toTermName) + cls.owner.decls.lookup(cls.name.sourceModuleName) .suchThat(_ is Module).symbol) else unpickler } diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index cdda4f05a..0bd841098 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -107,6 +107,14 @@ class Namer { typer: Typer => } } + /** Find moduleClass/sourceModule in effective scope */ + private def findModuleBuddy(name: Name)(implicit ctx: Context) = { + val scope = ctx.effectiveScope + val it = scope.lookupAll(name).filter(_ is Module) + assert(it.hasNext, s"no companion $name in $scope") + it.next + } + /** If this tree is a member def or an import, create a symbol of it * and store in symOfTree map. */ @@ -120,15 +128,29 @@ class Namer { typer: Typer => sym } + /** Add moduleClass/sourceModule to completer if it is for a module val or class */ + def adjustIfModule(completer: LazyType, tree: MemberDef) = + if (tree.mods is Module) { + val name = tree.name + if (name.isTermName) + completer withModuleClass findModuleBuddy(name.moduleClassName) + else + completer withSourceModule findModuleBuddy(name.sourceModuleName) + } + else completer + println(i"creating symbol for $tree") tree match { case tree: TypeDef if tree.isClassDef => record(tree, ctx.newClassSymbol( - ctx.owner, tree.name, tree.mods.flags, new Completer(tree) withDecls newScope, + ctx.owner, tree.name, tree.mods.flags, + adjustIfModule(new Completer(tree), tree), privateWithinClass(tree.mods), tree.pos, ctx.source.file)) case tree: MemberDef => + var completer = new Completer(tree) record(tree, ctx.newSymbol( - ctx.owner, tree.name, tree.mods.flags, new Completer(tree), + ctx.owner, tree.name, tree.mods.flags, + adjustIfModule(new Completer(tree), tree), privateWithinClass(tree.mods), tree.pos)) case imp: Import => record(imp, ctx.newSymbol( @@ -252,7 +274,7 @@ class Namer { typer: Typer => typer1.defDefSig(tree, sym)(localContext.withTyper(typer1)) case tree: TypeDef => if (tree.isClassDef) - classDefSig(tree, sym.asClass, decls.asInstanceOf[MutableScope])(localContext) + classDefSig(tree, sym.asClass)(localContext) else typeDefSig(tree, sym)(localContext.withNewScope) case imp: Import => @@ -260,7 +282,50 @@ class Namer { typer: Typer => ImportType(tpd.SharedTree(expr1)) } - sym.info = typeSig(original) + /** The type signature of a ClassDef with given symbol */ + def classDefSig(cdef: TypeDef, cls: ClassSymbol)(implicit ctx: Context): Type = { + + def parentType(constr: untpd.Tree): Type = { + val Trees.Select(Trees.New(tpt), _) = methPart(constr) + val ptype = typedAheadType(tpt).tpe + if (ptype.uninstantiatedTypeParams.isEmpty) ptype + else typedAheadExpr(constr).tpe + } + + val TypeDef(_, name, impl @ Template(constr, parents, self, body)) = cdef + + val (params, rest) = body span { + case td: TypeDef => td.mods is Param + case td: ValDef => td.mods is ParamAccessor + case _ => false + } + val decls = newScope + index(params) + val selfInfo = if (self.isEmpty) NoType else createSymbol(self) + // pre-set info, so that parent types can refer to type params + cls.info = adjustIfModule(ClassInfo(cls.owner.thisType, cls, Nil, decls, selfInfo)) + val parentTypes = parents map parentType + val parentRefs = ctx.normalizeToRefs(parentTypes, cls, decls) + index(constr) + index(rest)(inClassContext(selfInfo)) + ClassInfo(cls.owner.thisType, cls, parentRefs, decls, selfInfo) + } + + def adjustIfModule(sig: Type): Type = + if (denot is Module) + sig match { + case sig: TypeRefBySym => + sig + case sig: TypeRef => + TypeRef.withSym(sig.prefix, sig.symbol.asType) + case sig: ClassInfo => + sig.derivedClassInfo(sig.prefix, sig.classParents, TermRef.withSym(sig.prefix, sourceModule.asTerm)) + case _ => + sig + } + else sig + + sym.info = adjustIfModule(typeSig(original)) } } @@ -352,32 +417,4 @@ class Namer { typer: Typer => else TypeBounds(rhsType, rhsType) } } - - /** The type signature of a ClassDef with given symbol */ - def classDefSig(cdef: TypeDef, cls: ClassSymbol, decls: MutableScope)(implicit ctx: Context): Type = { - - def parentType(constr: untpd.Tree): Type = { - val Trees.Select(Trees.New(tpt), _) = methPart(constr) - val ptype = typedAheadType(tpt).tpe - if (ptype.uninstantiatedTypeParams.isEmpty) ptype - else typedAheadExpr(constr).tpe - } - - val TypeDef(_, name, impl @ Template(constr, parents, self, body)) = cdef - - val (params, rest) = body span { - case td: TypeDef => td.mods is Param - case td: ValDef => td.mods is ParamAccessor - case _ => false - } - index(params) - val selfInfo = if (self.isEmpty) NoType else createSymbol(self) - // pre-set info, so that parent types can refer to type params - cls.info = ClassInfo(cls.owner.thisType, cls, Nil, decls, selfInfo) - val parentTypes = parents map parentType - val parentRefs = ctx.normalizeToRefs(parentTypes, cls, decls) - index(constr) - index(rest)(inClassContext(selfInfo)) - ClassInfo(cls.owner.thisType, cls, parentRefs, decls, selfInfo) - } } \ No newline at end of file -- cgit v1.2.3