From 7f0637ce073131d8603c567329885e4443cd48d5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 21 Nov 2016 10:22:07 +0100 Subject: Make This and Super take idents as qualifier/mixin The qualifier of a This and the mixin of a Super were names, which meant that their positions were lost. Now they are untyped idents. --- .../tools/backend/jvm/DottyBackendInterface.scala | 4 ++-- src/dotty/tools/dotc/ast/Desugar.scala | 2 +- src/dotty/tools/dotc/ast/Trees.scala | 14 +++++------ src/dotty/tools/dotc/ast/tpd.scala | 7 ++++-- src/dotty/tools/dotc/ast/untpd.scala | 8 +++++-- src/dotty/tools/dotc/core/tasty/TastyFormat.scala | 25 +++++++++++--------- src/dotty/tools/dotc/core/tasty/TreePickler.scala | 13 +++++++---- .../tools/dotc/core/tasty/TreeUnpickler.scala | 13 ++++++++--- src/dotty/tools/dotc/parsing/Parsers.scala | 27 +++++++++++----------- src/dotty/tools/dotc/printing/PlainPrinter.scala | 5 +++- src/dotty/tools/dotc/transform/Erasure.scala | 4 ++-- .../tools/dotc/transform/SuperAccessors.scala | 6 ++--- src/dotty/tools/dotc/typer/TypeAssigner.scala | 4 ++-- 13 files changed, 79 insertions(+), 53 deletions(-) diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 03c4315fe..a7c449947 100644 --- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -973,7 +973,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma } object This extends ThisDeconstructor { - def get = field.qual + def get = field.qual.name def apply(s: Symbol): This = tpd.This(s.asClass) } @@ -1020,7 +1020,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma } object Super extends SuperDeconstructor { def _1: Tree = field.qual - def _2: Name = field.mix + def _2: Name = field.mix.name } object ArrayValue extends ArrayValueDeconstructor { def _1: Type = field.tpe match { diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 3c510c7b9..8f9c42e21 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -340,7 +340,7 @@ object desugar { val isDefinedMeth = syntheticProperty(nme.isDefined, Literal(Constant(true))) val caseParams = constrVparamss.head.toArray val productElemMeths = for (i <- 0 until arity) yield - syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeName), caseParams(i).name)) + syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeIdent), caseParams(i).name)) def isRepeated(tree: Tree): Boolean = tree match { case PostfixOp(_, nme.raw.STAR) => true case ByNameTypeTree(tree1) => isRepeated(tree1) diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index 78ac66812..2801bcae2 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -159,7 +159,7 @@ object Trees { /** Does this tree define a new symbol that is not defined elsewhere? */ def isDef: Boolean = false - /** Is this tree either the empty tree or the empty ValDef? */ + /** Is this tree either the empty tree or the empty ValDef or an empty type ident? */ def isEmpty: Boolean = false /** Convert tree to a list. Gives a singleton list, except @@ -353,7 +353,7 @@ object Trees { } /** qual.this */ - case class This[-T >: Untyped] private[ast] (qual: TypeName) + case class This[-T >: Untyped] private[ast] (qual: untpd.Ident) extends DenotingTree[T] with TermTree[T] { type ThisTree[-T >: Untyped] = This[T] // Denotation of a This tree is always the underlying class; needs correction for modules. @@ -368,7 +368,7 @@ object Trees { } /** C.super[mix], where qual = C.this */ - case class Super[-T >: Untyped] private[ast] (qual: Tree[T], mix: TypeName) + case class Super[-T >: Untyped] private[ast] (qual: Tree[T], mix: untpd.Ident) extends ProxyTree[T] with TermTree[T] { type ThisTree[-T >: Untyped] = Super[T] def forwardTo = qual @@ -890,12 +890,12 @@ object Trees { case tree: Select if (qualifier eq tree.qualifier) && (name == tree.name) => tree case _ => finalize(tree, untpd.Select(qualifier, name)) } - def This(tree: Tree)(qual: TypeName): This = tree match { - case tree: This if qual == tree.qual => tree + def This(tree: Tree)(qual: untpd.Ident): This = tree match { + case tree: This if qual eq tree.qual => tree case _ => finalize(tree, untpd.This(qual)) } - def Super(tree: Tree)(qual: Tree, mix: TypeName): Super = tree match { - case tree: Super if (qual eq tree.qual) && (mix == tree.mix) => tree + def Super(tree: Tree)(qual: Tree, mix: untpd.Ident): Super = tree match { + case tree: Super if (qual eq tree.qual) && (mix eq tree.mix) => tree case _ => finalize(tree, untpd.Super(qual, mix)) } def Apply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): Apply = tree match { diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 09f2099d2..219d6d4ec 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -31,11 +31,14 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { untpd.Select(qualifier, tp.name).withType(tp) def This(cls: ClassSymbol)(implicit ctx: Context): This = - untpd.This(cls.name).withType(cls.thisType) + untpd.This(untpd.Ident(cls.name)).withType(cls.thisType) - def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context): Super = + def Super(qual: Tree, mix: untpd.Ident, inConstrCall: Boolean, mixinClass: Symbol)(implicit ctx: Context): Super = ta.assignType(untpd.Super(qual, mix), qual, inConstrCall, mixinClass) + def Super(qual: Tree, mixName: TypeName, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context): Super = + Super(qual, if (mixName.isEmpty) untpd.EmptyTypeIdent else untpd.Ident(mixName), inConstrCall, mixinClass) + def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply = ta.assignType(untpd.Apply(fn, args), fn, args) diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index ac35ad09c..6c5210287 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -80,6 +80,10 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree]) extends TypTree case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree) extends DefTree + @sharable object EmptyTypeIdent extends Ident(tpnme.EMPTY) with WithoutTypeOrPos[Untyped] { + override def isEmpty = true + } + /** A block arising from a right-associative infix operation, where, e.g. * * a +: b @@ -225,8 +229,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def BackquotedIdent(name: Name): BackquotedIdent = new BackquotedIdent(name) def Select(qualifier: Tree, name: Name): Select = new Select(qualifier, name) def SelectWithSig(qualifier: Tree, name: Name, sig: Signature): Select = new SelectWithSig(qualifier, name, sig) - def This(qual: TypeName): This = new This(qual) - def Super(qual: Tree, mix: TypeName): Super = new Super(qual, mix) + def This(qual: Ident): This = new This(qual) + def Super(qual: Tree, mix: Ident): Super = new Super(qual, mix) def Apply(fun: Tree, args: List[Tree]): Apply = new Apply(fun, args) def TypeApply(fun: Tree, args: List[Tree]): TypeApply = new TypeApply(fun, args) def Literal(const: Constant): Literal = new Literal(const) diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 5e84c7428..cb1b56c3c 100644 --- a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -73,8 +73,9 @@ Standard-Section: "ASTs" TopLevelStat* Application IDENT NameRef Type // used when term ident’s type is not a TermRef SELECT possiblySigned_NameRef qual_Term + QUALTHIS typeIdent_Tree NEW cls_Type - SUPER Length this_Term mixinTrait_Type? + SUPER Length this_Term mixinTypeIdent_Tree? TYPED Length expr_Term ascription_Type NAMEDARG Length paramName_NameRef arg_Term ASSIGN Length lhs_Term rhs_Term @@ -279,16 +280,17 @@ object TastyFormat { final val RENAMED = 79 final val THIS = 96 - final val CLASSconst = 97 - final val ENUMconst = 98 - final val BYNAMEtype = 99 - final val BYNAMEtpt = 100 - final val NEW = 101 - final val IMPLICITarg = 102 - final val PRIVATEqualified = 103 - final val PROTECTEDqualified = 104 - final val RECtype = 105 - final val SINGLETONtpt = 106 + final val QUALTHIS = 97 + final val CLASSconst = 98 + final val ENUMconst = 99 + final val BYNAMEtype = 100 + final val BYNAMEtpt = 101 + final val NEW = 102 + final val IMPLICITarg = 103 + final val PRIVATEqualified = 104 + final val PROTECTEDqualified = 105 + final val RECtype = 106 + final val SINGLETONtpt = 107 final val IDENT = 112 final val IDENTtpt = 113 @@ -506,6 +508,7 @@ object TastyFormat { case TEMPLATE => "TEMPLATE" case SELFDEF => "SELFDEF" case THIS => "THIS" + case QUALTHIS => "QUALTHIS" case SUPER => "SUPER" case CLASSconst => "CLASSconst" case ENUMconst => "ENUMconst" diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 279ab5026..80270aa25 100644 --- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -360,8 +360,13 @@ class TreePickler(pickler: TastyPickler) { pickleName(name) pickleType(tree.tpe) } - case This(_) => - pickleType(tree.tpe) + case This(qual) => + if (qual.isEmpty) pickleType(tree.tpe) + else { + writeByte(QUALTHIS) + val ThisType(tref) = tree.tpe + pickleTree(qual.withType(tref)) + } case Select(qual, name) => writeByte(if (name.isTypeName) SELECTtpt else SELECT) val realName = tree.tpe match { @@ -396,8 +401,8 @@ class TreePickler(pickler: TastyPickler) { withLength { pickleTree(qual); if (!mix.isEmpty) { - val SuperType(_, mixinType) = tree.tpe - pickleType(mixinType) + val SuperType(_, mixinType: TypeRef) = tree.tpe + pickleTree(mix.withType(mixinType)) } } case New(tpt) => diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 1f0bbca19..eba9ab533 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -885,6 +885,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle untpd.Select(qual, unshadowed).withType(tpf(qual.tpe.widenIfUnstable)) } + def readQualId(): (untpd.Ident, TypeRef) = { + val qual = readTerm().asInstanceOf[untpd.Ident] + (untpd.Ident(qual.name).withPos(qual.pos), qual.tpe.asInstanceOf[TypeRef]) + } + def readSimpleTerm(): Tree = tag match { case SHARED => forkAt(readAddr()).readTerm() @@ -902,6 +907,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle case SELECTtpt => val name = readName().toTypeName completeSelect(name, TypeRef(_, name)) + case QUALTHIS => + val (qual, tref) = readQualId() + untpd.This(qual).withType(ThisType.raw(tref)) case NEW => New(readTpt()) case SINGLETONtpt => @@ -933,9 +941,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle (tag: @switch) match { case SUPER => val qual = readTerm() - val mixClass = ifBefore(end)(readType().typeSymbol, NoSymbol) - val mixName = if (mixClass.exists) mixClass.name.asTypeName else tpnme.EMPTY - tpd.Super(qual, mixName, ctx.mode.is(Mode.InSuperCall), mixClass) + val (mixId, mixTpe) = ifBefore(end)(readQualId(), (untpd.EmptyTypeIdent, NoType)) + tpd.Super(qual, mixId, ctx.mode.is(Mode.InSuperCall), mixTpe.typeSymbol) case APPLY => val fn = readTerm() val isJava = fn.symbol.is(JavaDefined) diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index e0c6be8c8..68d7e1a53 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -527,27 +527,28 @@ object Parsers { */ def path(thisOK: Boolean, finish: Tree => Tree = id): Tree = { val start = in.offset - def handleThis(name: TypeName) = { + def handleThis(qual: Ident) = { in.nextToken() - val t = atPos(start) { This(name) } + val t = atPos(start) { This(qual) } if (!thisOK && in.token != DOT) syntaxError("`.' expected") dotSelectors(t, finish) } - def handleSuper(name: TypeName) = { + def handleSuper(qual: Ident) = { in.nextToken() val mix = mixinQualifierOpt() - val t = atPos(start) { Super(This(name), mix) } + val t = atPos(start) { Super(This(qual), mix) } accept(DOT) dotSelectors(selector(t), finish) } - if (in.token == THIS) handleThis(tpnme.EMPTY) - else if (in.token == SUPER) handleSuper(tpnme.EMPTY) + if (in.token == THIS) handleThis(EmptyTypeIdent) + else if (in.token == SUPER) handleSuper(EmptyTypeIdent) else { val t = termIdent() if (in.token == DOT) { + def qual = cpy.Ident(t)(t.name.toTypeName) in.nextToken() - if (in.token == THIS) handleThis(t.name.toTypeName) - else if (in.token == SUPER) handleSuper(t.name.toTypeName) + if (in.token == THIS) handleThis(qual) + else if (in.token == SUPER) handleSuper(qual) else selectors(t, finish) } else t @@ -556,9 +557,9 @@ object Parsers { /** MixinQualifier ::= `[' Id `]' */ - def mixinQualifierOpt(): TypeName = - if (in.token == LBRACKET) inBrackets(ident().toTypeName) - else tpnme.EMPTY + def mixinQualifierOpt(): Ident = + if (in.token == LBRACKET) inBrackets(atPos(in.offset) { typeIdent() }) + else EmptyTypeIdent /** StableId ::= Id * | Path `.' Id @@ -617,7 +618,7 @@ object Parsers { termIdent() else if (in.token == THIS) { in.nextToken() - This(tpnme.EMPTY) + This(EmptyTypeIdent) } else if (in.token == LBRACE) if (inPattern) Block(Nil, inBraces(pattern())) @@ -2145,7 +2146,7 @@ object Parsers { val first = expr1() if (in.token == ARROW) { first match { - case Typed(tree @ This(tpnme.EMPTY), tpt) => + case Typed(tree @ This(EmptyTypeIdent), tpt) => self = makeSelfDef(nme.WILDCARD, tpt).withPos(first.pos) case _ => val ValDef(name, tpt, _) = convertToParam(first, expected = "self type clause") diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala index 06d44e301..4894fa019 100644 --- a/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -127,7 +127,10 @@ class PlainPrinter(_ctx: Context) extends Printer { homogenize(tp) match { case tp: TypeType => toTextRHS(tp) - case tp: TermRef if !tp.denotationIsCurrent || tp.symbol.is(Module) || tp.symbol.name.isImportName => + case tp: TermRef + if !tp.denotationIsCurrent && !homogenizedView || // always print underyling when testing picklers + tp.symbol.is(Module) || + tp.symbol.name.isImportName => toTextRef(tp) ~ ".type" case tp: TermRef if tp.denot.isOverloaded => "" diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index a503d55e5..069176111 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -352,10 +352,10 @@ object Erasure extends TypeTestsCasts{ assignType(untpd.cpy.Select(tree)(qual, tree.name.primitiveArrayOp), qual) def adaptIfSuper(qual: Tree): Tree = qual match { - case Super(thisQual, tpnme.EMPTY) => + case Super(thisQual, untpd.EmptyTypeIdent) => val SuperType(thisType, supType) = qual.tpe if (sym.owner is Flags.Trait) - cpy.Super(qual)(thisQual, sym.owner.asClass.name) + cpy.Super(qual)(thisQual, untpd.Ident(sym.owner.asClass.name)) .withType(SuperType(thisType, sym.owner.typeRef)) else qual.withType(SuperType(thisType, thisType.firstParent)) diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala index 10be6db65..fea478c9b 100644 --- a/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -106,7 +106,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { ctx.error(s"super not allowed here: use this.${sel.name.decode} instead", sel.pos) else if (sym is Deferred) { val member = sym.overridingSymbol(clazz) - if (mix != tpnme.EMPTY || + if (!mix.name.isEmpty || !member.exists || !((member is AbsOverride) && member.isIncompleteIn(clazz))) ctx.error( @@ -114,7 +114,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { sel.pos) else ctx.log(i"ok super $sel ${sym.showLocated} $member $clazz ${member.isIncompleteIn(clazz)}") } - else if (mix == tpnme.EMPTY && !(sym.owner is Trait)) + else if (mix.name.isEmpty && !(sym.owner is Trait)) // SI-4989 Check if an intermediate class between `clazz` and `sym.owner` redeclares the method as abstract. for (intermediateClass <- clazz.info.baseClasses.tail.takeWhile(_ != sym.owner)) { val overriding = sym.overridingSymbol(intermediateClass) @@ -124,7 +124,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { sel.pos) } - if (name.isTermName && mix == tpnme.EMPTY && + if (name.isTermName && mix.name.isEmpty && ((clazz is Trait) || clazz != ctx.owner.enclosingClass || !validCurrentClass)) superAccessorCall(sel)(ctx.withPhase(thisTransformer.next)) else sel diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 1599d95e6..ee2d68278 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -282,7 +282,7 @@ trait TypeAssigner { } def assignType(tree: untpd.This)(implicit ctx: Context) = { - val cls = qualifyingClass(tree, tree.qual, packageOK = false) + val cls = qualifyingClass(tree, tree.qual.name, packageOK = false) tree.withType(cls.thisType) } @@ -291,7 +291,7 @@ trait TypeAssigner { val qtype @ ThisType(_) = qual.tpe val cls = qtype.cls - def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match { + def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix.name) match { case p :: Nil => p case Nil => -- cgit v1.2.3