From 9ea42b02f07136ffd4bd8954cb619a3b3a791278 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Apr 2015 21:27:55 +0200 Subject: [PATCH 01/13] Fix to error reporting of compiled units --- src/dotty/tools/dotc/Run.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala index c99f5efb9167..151288d23709 100644 --- a/src/dotty/tools/dotc/Run.scala +++ b/src/dotty/tools/dotc/Run.scala @@ -33,7 +33,7 @@ class Run(comp: Compiler)(implicit ctx: Context) { compileSources(sources) } catch { case NonFatal(ex) => - println(s"exception occurred while compiling $units%, %") + println(i"exception occurred while compiling $units%, %") throw ex } From 0da6780f503c85064f7228b8f3866a0defe88221 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Apr 2015 21:34:01 +0200 Subject: [PATCH 02/13] New symbol creation method: `newNormalizedClassSymbol`. It's common that one wants to create class symbols with arbitary parent types, not just TypeRefs. But for the casual user it's non-obvious how to do it. Hence the new creation method. --- src/dotty/tools/dotc/core/Symbols.scala | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index 2b91efbcd83c..94ac258daf6e 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -109,6 +109,30 @@ trait Symbols { this: Context => ClassInfo(owner.thisType, _, parents, decls, selfInfo), privateWithin, coord, assocFile) + /** Same as `newCompleteClassSymbol` except that `parents` can be a list of arbitary + * types which get normalized into type refs and parameter bindings. + */ + def newNormalizedClassSymbol( + owner: Symbol, + name: TypeName, + flags: FlagSet, + parentTypes: List[Type], + decls: Scope = newScope, + selfInfo: Type = NoType, + privateWithin: Symbol = NoSymbol, + coord: Coord = NoCoord, + assocFile: AbstractFile = null): ClassSymbol = { + def completer = new LazyType { + def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { + val cls = denot.asClass.classSymbol + val decls = newScope + val parentRefs: List[TypeRef] = normalizeToClassRefs(parentTypes, cls, decls) + denot.info = ClassInfo(owner.thisType, cls, parentRefs, decls) + } + } + newClassSymbol(owner, name, flags, completer, privateWithin, coord, assocFile) + } + /** Create a module symbol with associated module class * from its non-info fields and a function producing the info * of the module class (this info may be lazy). From a5eb07633581962289bf6ee32c2cc7de00333cf6 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Apr 2015 21:37:32 +0200 Subject: [PATCH 03/13] Make tpd.ClassDef work for polymorphic parent classes. The handling of the first parent of ClassDef was broken if that parent had type parameters. This was exposed by following commites which use ClassDef more intensively than before in creating anonymous classes representing closures. --- src/dotty/tools/dotc/ast/tpd.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index de0ef3344e4e..23b964dc4a0c 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -210,7 +210,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { ta.assignType(untpd.TypeDef(sym.name, TypeTree(sym.info)), sym) def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree], superArgs: List[Tree] = Nil)(implicit ctx: Context): TypeDef = { - val firstParent :: otherParents = cls.info.parents + val firstParentRef :: otherParentRefs = cls.info.parents + val firstParent = cls.typeRef.baseTypeWithArgs(firstParentRef.symbol) val superRef = if (cls is Trait) TypeTree(firstParent) else { @@ -225,7 +226,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val constr = firstParent.decl(nme.CONSTRUCTOR).suchThat(constr => isApplicable(constr.info)) New(firstParent, constr.symbol.asTerm, superArgs) } - val parents = superRef :: otherParents.map(TypeTree(_)) + val parents = superRef :: otherParentRefs.map(TypeTree(_)) val selfType = if (cls.classInfo.selfInfo ne NoType) ValDef(ctx.newSelfSym(cls)) From 959a112c6278ef06e501f117fbc3aba50f280eb7 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Apr 2015 21:38:44 +0200 Subject: [PATCH 04/13] New utility method tpd.AnonymousClass As the name implies, this creates an anonymous class. --- src/dotty/tools/dotc/ast/tpd.scala | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 23b964dc4a0c..4df3f7a63c38 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -245,6 +245,34 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { ta.assignType(untpd.TypeDef(cls.name, impl), cls) } + /** An anonymous class + * + * new parent { forwarders } + * + * where `forwarders` contains forwarders for all functions in `fns`. + * `fns` must be non-empty. The class has the same owner as the first function in `fns`. + * Its position is the union of all functions in `fns`. + */ + def AnonClass(parent: Type, fns: List[TermSymbol], methNames: List[TermName])(implicit ctx: Context): Block = { + def methName(fnName: TermName): TermName = if (fnName == nme.ANON_FUN) nme.apply else fnName + val owner = fns.head.owner + val parents = + if (parent.classSymbol.is(Trait)) defn.ObjectClass.typeRef :: parent :: Nil + else parent :: Nil + val cls = ctx.newNormalizedClassSymbol(owner, tpnme.ANON_FUN, Synthetic, parents, + coord = fns.map(_.pos).reduceLeft(_ union _)) + println(i"creating anon class with parent $parent -> ${cls.info.parents}%, %") + println(cls.classInfo.classParents) + val constr = ctx.newConstructor(cls, Synthetic, Nil, Nil).entered + def forwarder(fn: TermSymbol, name: TermName) = { + val fwdMeth = fn.copy(cls, name, Synthetic | Method).entered.asTerm + DefDef(fwdMeth, prefss => ref(fn).appliedToArgss(prefss)) + } + val forwarders = (fns, methNames).zipped.map(forwarder) + val cdef = ClassDef(cls, DefDef(constr), forwarders) + Block(cdef :: Nil, New(cls.typeRef, Nil)) + } + // {