From c2f101a33ea7f89681d6b74731bbcff948e7e6da Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 5 Dec 2013 12:05:49 +0100 Subject: Changes to Desugar and Namer. In particular: Changed the scheme to represent the types of setter parameters. --- src/dotty/tools/dotc/ast/Desugar.scala | 52 ++++++++++++++++++---- src/dotty/tools/dotc/printing/RefinedPrinter.scala | 6 +-- src/dotty/tools/dotc/typer/Namer.scala | 35 +++++++++------ src/dotty/tools/dotc/typer/Typer.scala | 21 +++------ 4 files changed, 74 insertions(+), 40 deletions(-) diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 1b7f4edc8..84e321158 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -20,19 +20,44 @@ object desugar { private type VarInfo = (NameTree, Tree) + /** var x: Int = expr + * ==> + * def x: Int = expr + * def x_=($1: like (var x: Int = expr)): Unit = () + */ def valDef(vdef: ValDef)(implicit ctx: Context): Tree = { val ValDef(mods, name, tpt, rhs) = vdef - if (!ctx.owner.isClass || (mods is Private) || !(mods is Mutable)) vdef - else { - val setterParam = makeSyntheticParameter(tpt = TypeTree(vdef)) + def setterNeeded = + (mods is Mutable) && ctx.owner.isClass && (!(mods is Private) || (ctx.owner is Trait)) + if (setterNeeded) { + // todo: copy of vdef as getter needed? + // val getter = ValDef(mods, name, tpt, rhs) withPos vdef.pos ? + // right now vdef maps via expandedTree to a thicket which concerns itself. + // I don't see a problem with that but if there is one we can avoid it by making a copy here. + val setterParam = makeSyntheticParameter(tpt = TypeTree()) val setterRhs = if (vdef.rhs.isEmpty) EmptyTree else unitLiteral val setter = cpy.DefDef(vdef, mods | Accessor, name.setterName, Nil, (setterParam :: Nil) :: Nil, TypeTree(defn.UnitType), setterRhs) // rhs gets filled in later, when field is generated and getter has parameters Thicket(vdef, setter) } + else vdef } + /** Expand context bounds to evidence params. E.g., + * + * def f[T >: L <: H : B](params) + * ==> + * def f[T >: L <: H](params)(implicit evidence$0: B[T]) + * + * Expand default arguments to default getters. E.g, + * + * def f(x: Int = 1)(y: String = x + "m") = ... + * ==> + * def f(x: Int)(y: String) = ... + * def f$default$1 = 1 + * def f$default$2(x: Int) = x + "m" + */ def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = { val DefDef(mods, name, tparams, vparamss, tpt, rhs) = meth val epbuf = new ListBuffer[ValDef] @@ -62,14 +87,20 @@ object desugar { cpy.DefDef(meth, mods, name, tparams1, vparamss1, tpt, rhs) } + /** The first n parameters in a possibly curried list of parameter sections */ def take(vparamss: List[List[ValDef]], n: Int): List[List[ValDef]] = vparamss match { case vparams :: vparamss1 => val len = vparams.length - if (len <= n) vparams :: take(vparamss1, n - len) else Nil + if (n == 0) Nil + else if (n < len) (vparams take n) :: Nil + else vparams :: take(vparamss1, n - len) case _ => Nil } + def normalizedVparamss = vparamss map (_ map (vparam => + cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt, EmptyTree))) + def defaultGetters(vparamss: List[List[ValDef]], n: Int = 0): List[DefDef] = vparamss match { case (vparam :: vparams) :: vparamss1 => def defaultGetter: DefDef = @@ -77,7 +108,7 @@ object desugar { mods = vparam.mods & AccessFlags, name = meth.name.defaultGetterName(n + 1), tparams = meth.tparams, - vparamss = take(meth.vparamss, n), + vparamss = take(normalizedVparamss, n), tpt = TypeTree(), rhs = vparam.rhs) val rest = defaultGetters(vparams :: vparamss1, n + 1) @@ -92,13 +123,18 @@ object desugar { if (defGetters.isEmpty) meth1 else { val mods1 = meth1.mods | DefaultParameterized - val vparamss1 = vparamss map (_ map (vparam => - cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt, EmptyTree))) - val meth2 = cpy.DefDef(meth1, mods1, meth1.name, meth1.tparams, vparamss1, meth1.tpt, meth1.rhs) + val meth2 = cpy.DefDef(meth1, meth1.mods | DefaultParameterized, + meth1.name, meth1.tparams, normalizedVparamss, meth1.tpt, meth1.rhs) Thicket(meth2 :: defGetters) } } + /** Fill in empty type bounds with Nothing/Any. Expand private local type parameters as follows: + * + * class C[T] + * ==> + * class C { type C$T; type T = C$T } + */ def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = { val TypeDef(mods, name, rhs) = tdef val rhs1 = rhs match { diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index abea42c1d..546a3e027 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -212,11 +212,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case SeqLiteral(elems) => "[" ~ toTextGlobal(elems, ",") ~ "]" case TypeTree(orig) => - if (tree.hasType) toText(tree.typeOpt) - else orig match { - case orig: ValDef => "like(" ~ toText(orig) ~ ")" - case _ => toText(orig) - } + if (tree.hasType) toText(tree.typeOpt) else toText(orig) case SingletonTypeTree(ref) => toTextLocal(ref) ~ ".type" case SelectFromTypeTree(qual, name) => diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 66d238614..bcdb4a43f 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -18,6 +18,11 @@ import language.implicitConversions trait NamerContextOps { this: Context => + /** Enter symbol into current class, if current class is owner of current context, + * or into current scope, if not. Should always be called instead of scope.enter + * in order to make sure that updates to class members are reflected in + * finger prints. + */ def enter(sym: Symbol): Symbol = { ctx.owner match { case cls: ClassSymbol => cls.enter(sym) @@ -26,6 +31,7 @@ trait NamerContextOps { this: Context => sym } + /** The denotation with the given name in current context */ def denotNamed(name: Name): Denotation = if (owner.isClass) if (outer.owner == owner) @@ -35,12 +41,15 @@ trait NamerContextOps { this: Context => else scope.denotsNamed(name).toDenot(NoPrefix) - def effectiveScope = + /** Either the current scope, or, if the current context owner is a class, + * the declarations of the current class. + */ + def effectiveScope: Scope = if (owner != null && owner.isClass) owner.asClass.decls else scope } -/** This class attaches creates symbols from definitions and imports and gives them +/** This class creates symbols from definitions and imports and gives them * lazy types. * * Timeline: @@ -64,7 +73,6 @@ class Namer { typer: Typer => import untpd._ - /** A partial map from unexpanded member and pattern defs and to their expansions. * Populated during enterSyms, emptied during typer. */ @@ -186,7 +194,7 @@ class Namer { typer: Typer => sym } - /** All PackageClassInfoTypes come from here. */ + /** Create package if it does not yet exist. */ private def createPackageSymbol(pid: RefTree)(implicit ctx: Context): Symbol = { val pkgOwner = pid match { case Ident(_) => if (ctx.owner eq defn.EmptyPackageClass) defn.RootClass else ctx.owner @@ -242,12 +250,6 @@ class Namer { typer: Typer => /** Create top-level symbols for statements and enter them into symbol table */ def index(stats: List[Tree])(implicit ctx: Context): Context = { - @tailrec def traverse(stats: List[Tree])(implicit ctx: Context): Context = stats match { - case stat :: stats1 => - traverse(stats1)(index(stat)) - case nil => - ctx - } /** Merge the definitions of a synthetic companion generated by a case class * and the real companion, if both exist. @@ -270,7 +272,7 @@ class Namer { typer: Typer => } } - val result = traverse(stats) + val result = (ctx /: stats) ((ctx, stat) => index(stat)(ctx)) mergeCompanionDefs() result } @@ -377,9 +379,16 @@ class Namer { typer: Typer => lazy val schema = paramFn(WildcardType) val site = sym.owner.thisType val inherited = { - // TODO: Look only at member of supertype instead? - if (sym.owner.isTerm) NoType + if ((sym is Param) && sym.owner.isSetter) { // fill in type from getter result type + val getterCtx = ctx.outersIterator + .dropWhile(_.owner != sym.owner) + .dropWhile(_.owner == sym.owner) + .next + getterCtx.denotNamed(sym.owner.asTerm.name.setterToGetter).info.widenExpr + } + else if (sym.owner.isTerm) NoType else + // TODO: Look only at member of supertype instead? ((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) => val itpe = cls.info .nonPrivateDecl(sym.name) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 6f5739396..fd97c2c22 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -619,18 +619,10 @@ class Typer extends Namer with Applications with Implicits { } def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = track("typedTypeTree") { - val (original1, ownType) = tree.original match { - case untpd.EmptyTree => - assert(isFullyDefined(pt, ForceDegree.none)) - (EmptyTree, pt) - case original: ValDef => - val meth = original.symbol // ??? was: symbolOfTree(original) TODO: come back to this - assert(meth.exists, meth) - (EmptyTree, meth.info) - case original => - val original1 = typed(original) - (original1, original1.tpe) - } + val original1 = typed(tree.original) + val ownType = + if (tree.original.isEmpty) { assert(isFullyDefined(pt, ForceDegree.none)); pt } + else original1.tpe cpy.TypeTree(tree, original1) withType ownType } @@ -1011,9 +1003,10 @@ class Typer extends Namer with Applications with Implicits { noMatches } case alts => + def all = if (altDenots.length == 2) "both" else "all" errorTree(tree, - i"""Ambiguous overload. The ${err.overloadedAltsStr(altDenots take 2)} - |both match $expectedStr""".stripMargin) + i"""Ambiguous overload. The ${err.overloadedAltsStr(altDenots)} + |$all match $expectedStr""".stripMargin) } } -- cgit v1.2.3