From fb710457959d1c2d4b983986141875a8fde5992b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 24 Sep 2016 13:50:27 +0200 Subject: Make positions fit for meta In particular: - get rid of envelope, it's too complicated and hides too many errors - check that everywhere in parsed trees the position range of a parent node contains the position ranges of its children. - check that all non-empty trees coming from parser have positions. The commit contains lots of fixes to make these checks pass. In particular, it changes the scheme how definitions are positioned. Previously the position of a definition was the token range of the name defined by it. That does obviously not work with the parent/children invariant. Now, the position is the whole definition range, with the point at the defined name (care is taken to not count backticks). Namer is changed to still use the token range of defined name as the position of the symbol. --- src/dotty/tools/dotc/ast/Desugar.scala | 32 ++-- src/dotty/tools/dotc/ast/NavigateAST.scala | 9 +- src/dotty/tools/dotc/ast/Positioned.scala | 64 ++++++-- src/dotty/tools/dotc/ast/TreeInfo.scala | 2 +- src/dotty/tools/dotc/ast/Trees.scala | 4 +- src/dotty/tools/dotc/ast/untpd.scala | 2 +- src/dotty/tools/dotc/config/Config.scala | 3 + src/dotty/tools/dotc/parsing/JavaParsers.scala | 164 +++++++++++---------- src/dotty/tools/dotc/parsing/JavaScanners.scala | 1 + src/dotty/tools/dotc/parsing/Parsers.scala | 98 ++++++------ src/dotty/tools/dotc/printing/RefinedPrinter.scala | 1 + src/dotty/tools/dotc/typer/FrontEnd.scala | 2 + src/dotty/tools/dotc/typer/Namer.scala | 16 +- src/dotty/tools/dotc/typer/Typer.scala | 2 +- src/dotty/tools/dotc/typer/VarianceChecker.scala | 6 +- 15 files changed, 243 insertions(+), 163 deletions(-) (limited to 'src/dotty/tools') diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 7011d13a0..36cae6378 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -505,7 +505,7 @@ object desugar { val clsTmpl = cpy.Template(tmpl)(self = clsSelf, body = tmpl.body) val cls = TypeDef(clsName, clsTmpl) .withMods(mods.toTypeFlags & RetainedModuleClassFlags | ModuleClassCreationFlags) - Thicket(modul, classDef(cls)) + Thicket(modul, classDef(cls).withPos(mdef.pos)) } } @@ -516,7 +516,7 @@ object desugar { def patDef(pdef: PatDef)(implicit ctx: Context): Tree = { val PatDef(mods, pats, tpt, rhs) = pdef val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt)) - flatTree(pats1 map (makePatDef(mods, _, rhs))) + flatTree(pats1 map (makePatDef(pdef, mods, _, rhs))) } /** If `pat` is a variable pattern, @@ -534,9 +534,9 @@ object desugar { * If the original pattern variable carries a type annotation, so does the corresponding * ValDef or DefDef. */ - def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit ctx: Context): Tree = pat match { + def makePatDef(original: Tree, mods: Modifiers, pat: Tree, rhs: Tree)(implicit ctx: Context): Tree = pat match { case VarPattern(named, tpt) => - derivedValDef(named, tpt, rhs, mods) + derivedValDef(original, named, tpt, rhs, mods) case _ => val rhsUnchecked = makeAnnotated(defn.UncheckedAnnot, rhs) val vars = getVariables(pat) @@ -553,7 +553,7 @@ object desugar { case Nil => matchExpr case (named, tpt) :: Nil => - derivedValDef(named, tpt, matchExpr, mods) + derivedValDef(original, named, tpt, matchExpr, mods) case _ => val tmpName = ctx.freshName().toTermName val patMods = mods & (AccessFlags | Lazy) | Synthetic @@ -564,8 +564,8 @@ object desugar { val restDefs = for (((named, tpt), n) <- vars.zipWithIndex) yield - if (mods is Lazy) derivedDefDef(named, tpt, selector(n), mods &~ Lazy) - else derivedValDef(named, tpt, selector(n), mods) + if (mods is Lazy) derivedDefDef(original, named, tpt, selector(n), mods &~ Lazy) + else derivedValDef(original, named, tpt, selector(n), mods) flatTree(firstDef :: restDefs) } } @@ -663,14 +663,18 @@ object desugar { def makeAnnotated(cls: Symbol, tree: Tree)(implicit ctx: Context) = Annotated(untpd.New(untpd.TypeTree(cls.typeRef), Nil), tree) - private def derivedValDef(named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit ctx: Context) = { - val vdef = ValDef(named.name.asTermName, tpt, rhs).withMods(mods).withPos(named.pos) + private def derivedValDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit ctx: Context) = { + val vdef = ValDef(named.name.asTermName, tpt, rhs) + .withMods(mods) + .withPos(original.pos.withPoint(named.pos.start)) val mayNeedSetter = valDef(vdef) mayNeedSetter } - private def derivedDefDef(named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers) = - DefDef(named.name.asTermName, Nil, Nil, tpt, rhs).withMods(mods).withPos(named.pos) + private def derivedDefDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers) = + DefDef(named.name.asTermName, Nil, Nil, tpt, rhs) + .withMods(mods) + .withPos(original.pos.withPoint(named.pos.start)) /** Main desugaring method */ def apply(tree: Tree)(implicit ctx: Context): Tree = { @@ -760,7 +764,7 @@ object desugar { */ def makeLambda(pat: Tree, body: Tree): Tree = pat match { case VarPattern(named, tpt) => - Function(derivedValDef(named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body) + Function(derivedValDef(pat, named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body) case _ => makeCaseLambda(CaseDef(pat, EmptyTree, body) :: Nil, unchecked = false) } @@ -863,7 +867,7 @@ object desugar { val rhss = valeqs map { case GenAlias(_, rhs) => rhs } val (defpat0, id0) = makeIdPat(pat) val (defpats, ids) = (pats map makeIdPat).unzip - val pdefs = (defpats, rhss).zipped map (makePatDef(Modifiers(), _, _)) + val pdefs = (valeqs, defpats, rhss).zipped.map(makePatDef(_, Modifiers(), _, _)) val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, rhs) :: Nil, Block(pdefs, makeTuple(id0 :: ids))) val allpats = pat :: pats val vfrom1 = new IrrefutableGenFrom(makeTuple(allpats), rhs1) @@ -946,7 +950,7 @@ object desugar { makeFor(nme.map, nme.flatMap, enums, body) orElse tree case PatDef(mods, pats, tpt, rhs) => val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt)) - flatTree(pats1 map (makePatDef(mods, _, rhs))) + flatTree(pats1 map (makePatDef(tree, mods, _, rhs))) case ParsedTry(body, handler, finalizer) => handler match { case Match(EmptyTree, cases) => Try(body, cases, finalizer) diff --git a/src/dotty/tools/dotc/ast/NavigateAST.scala b/src/dotty/tools/dotc/ast/NavigateAST.scala index 2b11f81f3..33aa87d8e 100644 --- a/src/dotty/tools/dotc/ast/NavigateAST.scala +++ b/src/dotty/tools/dotc/ast/NavigateAST.scala @@ -19,10 +19,9 @@ object NavigateAST { case _ => val loosePath = untypedPath(tree, exactMatch = false) throw new - Error(i"""no untyped tree for $tree, pos = ${tree.pos}, envelope = ${tree.envelope} + Error(i"""no untyped tree for $tree, pos = ${tree.pos} |best matching path =\n$loosePath%\n====\n% - |path positions = ${loosePath.map(_.pos)} - |path envelopes = ${loosePath.map(_.envelope)}""") + |path positions = ${loosePath.map(_.pos)}""") } /** The reverse path of untyped trees starting with a tree that closest matches @@ -40,7 +39,7 @@ object NavigateAST { def untypedPath(tree: tpd.Tree, exactMatch: Boolean = false)(implicit ctx: Context): List[Positioned] = tree match { case tree: MemberDef[_] => - untypedPath(tree.envelope) match { + untypedPath(tree.pos) match { case path @ (last: DefTree[_]) :: _ => path case path if !exactMatch => path case _ => Nil @@ -76,7 +75,7 @@ object NavigateAST { path } def singlePath(p: Positioned, path: List[Positioned]): List[Positioned] = - if (p.envelope contains pos) childPath(p.productIterator, p :: path) + if (p.pos contains pos) childPath(p.productIterator, p :: path) else path singlePath(from, Nil) } diff --git a/src/dotty/tools/dotc/ast/Positioned.scala b/src/dotty/tools/dotc/ast/Positioned.scala index e7f5de591..ab9c06ca1 100644 --- a/src/dotty/tools/dotc/ast/Positioned.scala +++ b/src/dotty/tools/dotc/ast/Positioned.scala @@ -3,6 +3,10 @@ package ast import util.Positions._ import util.DotClass +import core.Contexts.Context +import core.Decorators._ +import core.Flags.JavaDefined +import core.StdNames.nme /** A base class for things that have positions (currently: modifiers and trees) */ @@ -16,7 +20,7 @@ abstract class Positioned extends DotClass with Product { */ def pos: Position = curPos - /** Destructively update `curPos` to given position. Also, set any missing + /** Destructively update `curPos` to given position. Also, set any missing * positions in children. */ protected def setPos(pos: Position): Unit = { @@ -24,11 +28,6 @@ abstract class Positioned extends DotClass with Product { if (pos.exists) setChildPositions(pos.toSynthetic) } - /** The envelope containing the item in its entirety. Envelope is different from - * `pos` for definitions (instances of MemberDef). - */ - def envelope: Position = pos.toSynthetic - /** A positioned item like this one with the position set to `pos`. * if the positioned item is source-derived, a clone is returned. * If the positioned item is synthetic, the position is updated @@ -106,8 +105,7 @@ abstract class Positioned extends DotClass with Product { } } - /** The initial, synthetic position. This is usually the union of all positioned children's - * envelopes. + /** The initial, synthetic position. This is usually the union of all positioned children's positions. */ protected def initialPos: Position = { var n = productArity @@ -115,7 +113,7 @@ abstract class Positioned extends DotClass with Product { while (n > 0) { n -= 1 productElement(n) match { - case p: Positioned => pos = pos union p.envelope + case p: Positioned => pos = pos union p.pos case xs: List[_] => pos = unionPos(pos, xs) case _ => } @@ -124,7 +122,7 @@ abstract class Positioned extends DotClass with Product { } private def unionPos(pos: Position, xs: List[_]): Position = xs match { - case (p: Positioned) :: xs1 => unionPos(pos union p.envelope, xs1) + case (p: Positioned) :: xs1 => unionPos(pos union p.pos, xs1) case _ => pos } @@ -138,7 +136,7 @@ abstract class Positioned extends DotClass with Product { false } (this eq that) || - (this.envelope contains that.pos) && { + (this.pos contains that.pos) && { var n = productArity var found = false while (n > 0 && !found) { @@ -148,4 +146,48 @@ abstract class Positioned extends DotClass with Product { found } } + + /** Check that all positioned items in this tree satisfy the following conditions: + * - Parent positions contain child positions + * - If item is a non-empty tree, it has a position + */ + def checkPos(complete: Boolean)(implicit ctx: Context): Unit = try { + import untpd._ + def check(p: Any): Unit = p match { + case p: Positioned => + assert(pos contains p.pos, + s"""position error, parent position does not contain child positon + |parent = $this, + |parent position = $pos, + |child = $p, + |child position = ${p.pos}""".stripMargin) + p match { + case tree: Tree if !tree.isEmpty => + assert(tree.pos.exists, + s"position error: position not set for $tree # ${tree.uniqueId}") + case _ => + } + p.checkPos(complete) + case xs: List[_] => + xs.foreach(check) + case _ => + } + this match { + case tree: DefDef if tree.name == nme.CONSTRUCTOR && tree.mods.is(JavaDefined) => + // Special treatment for constructors coming from Java: + // Leave out tparams, they are copied with wrong positions from parent class + check(tree.mods) + check(tree.vparamss) + case _ => + var n = productArity + while (n > 0) { + n -= 1 + check(productElement(n)) + } + } + } catch { + case ex: AssertionError => + println(i"error while checking $this") + throw ex + } } diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index 7c3f7f385..6c371abc1 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -480,7 +480,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => require(sym.pos.exists) object accum extends TreeAccumulator[List[Tree]] { def apply(x: List[Tree], tree: Tree)(implicit ctx: Context): List[Tree] = { - if (tree.envelope.contains(sym.pos)) + if (tree.pos.contains(sym.pos)) if (definedSym(tree) == sym) tree :: x else { val x1 = foldOver(x, tree) diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index cf11c27fa..4ba4eda0a 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -341,8 +341,6 @@ object Trees { } protected def setMods(mods: Modifiers[T @uncheckedVariance]) = myMods = mods - - override def envelope: Position = rawMods.pos.union(pos).union(initialPos) } /** A ValDef or DefDef tree */ @@ -619,7 +617,6 @@ object Trees { type ThisTree[-T >: Untyped] = Bind[T] override def isType = name.isTypeName override def isTerm = name.isTermName - override def envelope: Position = pos union initialPos } /** tree_1 | ... | tree_n */ @@ -740,6 +737,7 @@ object Trees { val newTrees = trees.map(_.withPos(pos)) new Thicket[T](newTrees).asInstanceOf[this.type] } + override def pos = (NoPosition /: trees) ((pos, t) => pos union t.pos) override def foreachInThicket(op: Tree[T] => Unit): Unit = trees foreach (_.foreachInThicket(op)) } diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index 6bbb76b89..4e18b1d5c 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -258,7 +258,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { implicit class UntypedTreeDecorator(val self: Tree) extends AnyVal { def locateEnclosing(base: List[Tree], pos: Position): List[Tree] = { def encloses(elem: Any) = elem match { - case t: Tree => t.envelope contains pos + case t: Tree => t.pos contains pos case _ => false } base.productIterator find encloses match { diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala index 0949d7fee..c188bfab4 100644 --- a/src/dotty/tools/dotc/config/Config.scala +++ b/src/dotty/tools/dotc/config/Config.scala @@ -63,6 +63,9 @@ object Config { */ final val checkNoDoubleBindings = true + /** Check positions for consistency after parsing */ + final val checkPositions = true + /** Show subtype traces for all deep subtype recursions */ final val traceDeepSubTypeRecursions = false diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala index fbb362354..c00cd7c59 100644 --- a/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -10,6 +10,7 @@ import scala.language.implicitConversions import JavaTokens._ import JavaScanners._ +import Scanners.Offset import Parsers._ import core._ import Contexts._ @@ -107,9 +108,6 @@ object JavaParsers { def unimplementedExpr = Ident("???".toTermName) - def makePackaging(pkg: RefTree, stats: List[Tree]): PackageDef = - atPos(pkg.pos) { PackageDef(pkg, stats) } - def makeTemplate(parents: List[Tree], stats: List[Tree], tparams: List[TypeDef], needsDummyConstr: Boolean) = { def pullOutFirstConstr(stats: List[Tree]): (Tree, List[Tree]) = stats match { case (meth: DefDef) :: rest if meth.name == CONSTRUCTOR => (meth, rest) @@ -250,14 +248,14 @@ object JavaParsers { var t: RefTree = atPos(in.offset) { Ident(ident()) } while (in.token == DOT) { in.nextToken() - t = atPos(in.offset) { Select(t, ident()) } + t = atPos(t.pos.start, in.offset) { Select(t, ident()) } } t } def optArrayBrackets(tpt: Tree): Tree = if (in.token == LBRACKET) { - val tpt1 = atPos(in.offset) { arrayOf(tpt) } + val tpt1 = atPos(tpt.pos.start, in.offset) { arrayOf(tpt) } in.nextToken() accept(RBRACKET) optArrayBrackets(tpt1) @@ -294,7 +292,7 @@ object JavaParsers { } while (in.token == DOT) { in.nextToken() - t = typeArgs(atPos(in.offset)(typeSelect(t, ident()))) + t = typeArgs(atPos(t.pos.start, in.offset)(typeSelect(t, ident()))) } convertToTypeId(t) } else { @@ -328,7 +326,7 @@ object JavaParsers { val t1 = convertToTypeId(t) val args = repsep(typeArg, COMMA) acceptClosingAngle() - atPos(t1.pos) { + atPos(t1.pos.start) { AppliedTypeTree(t1, args) } } else t @@ -356,7 +354,11 @@ object JavaParsers { // assumed true unless we see public/private/protected var isPackageAccess = true var annots: List[Tree] = Nil - def addAnnot(sym: ClassSymbol) = annots :+= New(TypeTree(sym.typeRef)).withPos(Position(in.offset)) + def addAnnot(sym: ClassSymbol) = + annots :+= atPos(in.offset) { + in.nextToken() + New(TypeTree(sym.typeRef)) + } while (true) { in.token match { @@ -387,13 +389,10 @@ object JavaParsers { in.nextToken() case NATIVE => addAnnot(NativeAnnot) - in.nextToken() case TRANSIENT => addAnnot(TransientAnnot) - in.nextToken() case VOLATILE => addAnnot(VolatileAnnot) - in.nextToken() case SYNCHRONIZED | STRICTFP => in.nextToken() case _ => @@ -443,16 +442,19 @@ object JavaParsers { } def formalParam(): ValDef = { + val start = in.offset if (in.token == FINAL) in.nextToken() annotations() var t = typ() if (in.token == DOTDOTDOT) { in.nextToken() - t = atPos(t.pos) { + t = atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) } } - varDecl(Position(in.offset), Modifiers(Flags.JavaDefined | Flags.Param), t, ident().toTermName) + atPos(start, in.offset) { + varDecl(Modifiers(Flags.JavaDefined | Flags.Param), t, ident().toTermName) + } } def optThrows(): Unit = { @@ -462,7 +464,7 @@ object JavaParsers { } } - def methodBody(): Tree = { + def methodBody(): Tree = atPos(in.offset) { skipAhead() accept(RBRACE) // skip block unimplementedExpr @@ -470,16 +472,18 @@ object JavaParsers { def definesInterface(token: Int) = token == INTERFACE || token == AT - def termDecl(mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = { + def termDecl(start: Offset, mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = { val inInterface = definesInterface(parentToken) val tparams = if (in.token == LT) typeParams(Flags.JavaDefined | Flags.Param) else List() val isVoid = in.token == VOID var rtpt = - if (isVoid) { - in.nextToken() - TypeTree(UnitType) withPos Position(in.offset) - } else typ() - var offset = in.offset + if (isVoid) + atPos(in.offset) { + in.nextToken() + TypeTree(UnitType) + } + else typ() + var nameOffset = in.offset val rtptName = rtpt match { case Ident(name) => name case _ => nme.EMPTY @@ -489,14 +493,15 @@ object JavaParsers { val vparams = formalParams() optThrows() List { - atPos(offset) { - DefDef(nme.CONSTRUCTOR, parentTParams, List(vparams), TypeTree(), methodBody()).withMods(mods) + atPos(start) { + DefDef(nme.CONSTRUCTOR, parentTParams, + List(vparams), TypeTree(), methodBody()).withMods(mods) } } } else { var mods1 = mods if (mods is Flags.Abstract) mods1 = mods &~ Flags.Abstract - offset = in.offset + nameOffset = in.offset val name = ident() if (in.token == LPAREN) { // method declaration @@ -510,13 +515,14 @@ object JavaParsers { } else { if (parentToken == AT && in.token == DEFAULT) { val annot = - atPos(offset) { + atPos(nameOffset) { New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), Nil) } mods1 = mods1 withAddedAnnotation annot + val unimplemented = unimplementedExpr skipTo(SEMI) accept(SEMI) - unimplementedExpr + unimplemented } else { accept(SEMI) EmptyTree @@ -524,13 +530,13 @@ object JavaParsers { } //if (inInterface) mods1 |= Flags.Deferred List { - atPos(offset) { + atPos(start, nameOffset) { DefDef(name.toTermName, tparams, List(vparams), rtpt, body).withMods(mods1 | Flags.Method) } } } else { if (inInterface) mods1 |= Flags.Final | Flags.JavaStatic - val result = fieldDecls(Position(offset), mods1, rtpt, name) + val result = fieldDecls(start, nameOffset, mods1, rtpt, name) accept(SEMI) result } @@ -546,19 +552,21 @@ object JavaParsers { * Once we have reached the end of the statement, we know whether * these potential definitions are real or not. */ - def fieldDecls(pos: Position, mods: Modifiers, tpt: Tree, name: Name): List[Tree] = { - val buf = ListBuffer[Tree](varDecl(pos, mods, tpt, name.toTermName)) + def fieldDecls(start: Offset, firstNameOffset: Offset, mods: Modifiers, tpt: Tree, name: Name): List[Tree] = { + val buf = ListBuffer[Tree]( + atPos(start, firstNameOffset) { varDecl(mods, tpt, name.toTermName) }) val maybe = new ListBuffer[Tree] // potential variable definitions. while (in.token == COMMA) { in.nextToken() if (in.token == IDENTIFIER) { // if there's an ident after the comma ... + val nextNameOffset = in.offset val name = ident() if (in.token == EQUALS || in.token == SEMI) { // ... followed by a `=` or `;`, we know it's a real variable definition buf ++= maybe - buf += varDecl(Position(in.offset), mods, tpt, name.toTermName) + buf += atPos(start, nextNameOffset) { varDecl(mods, tpt, name.toTermName) } maybe.clear() } else if (in.token == COMMA) { // ... if there's a comma after the ident, it could be a real vardef or not. - maybe += varDecl(Position(in.offset), mods, tpt, name.toTermName) + maybe += atPos(start, nextNameOffset) { varDecl(mods, tpt, name.toTermName) } } else { // ... if there's something else we were still in the initializer of the // previous var def; skip to next comma or semicolon. skipTo(COMMA, SEMI) @@ -576,35 +584,32 @@ object JavaParsers { buf.toList } - def varDecl(pos: Position, mods: Modifiers, tpt: Tree, name: TermName): ValDef = { + def varDecl(mods: Modifiers, tpt: Tree, name: TermName): ValDef = { val tpt1 = optArrayBrackets(tpt) if (in.token == EQUALS && !(mods is Flags.Param)) skipTo(COMMA, SEMI) val mods1 = if (mods is Flags.Final) mods else mods | Flags.Mutable - atPos(pos) { - ValDef(name, tpt1, if (mods is Flags.Param) EmptyTree else unimplementedExpr).withMods(mods1) - } + ValDef(name, tpt1, if (mods is Flags.Param) EmptyTree else unimplementedExpr).withMods(mods1) } - def memberDecl(mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = in.token match { + def memberDecl(start: Offset, mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = in.token match { case CLASS | ENUM | INTERFACE | AT => - typeDecl(if (definesInterface(parentToken)) mods | Flags.JavaStatic else mods) + typeDecl(start, if (definesInterface(parentToken)) mods | Flags.JavaStatic else mods) case _ => - termDecl(mods, parentToken, parentTParams) + termDecl(start, mods, parentToken, parentTParams) } def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree = atPos(cdef.pos) { + assert(cdef.pos.exists) ModuleDef(cdef.name.toTermName, makeTemplate(List(), statics, List(), false)).withMods((cdef.mods & (Flags.AccessFlags | Flags.JavaDefined)).toTermFlags) } - private val wild = Ident(nme.WILDCARD) withPos Position(-1) - private val wildList = List(wild) // OPT This list is shared for performance. + private def wild = Ident(nme.WILDCARD) + private def wildList = List(wild) // OPT This list is shared for performance. def importCompanionObject(cdef: TypeDef): Tree = - atPos(cdef.pos) { - Import(Ident(cdef.name.toTermName), wildList) - } + Import(Ident(cdef.name.toTermName).withPos(NoPosition), wildList) // Importing the companion object members cannot be done uncritically: see // ticket #2377 wherein a class contains two static inner classes, each of which @@ -633,8 +638,8 @@ object JavaParsers { } def importDecl(): List[Tree] = { + val start = in.offset accept(IMPORT) - val offset = in.offset val buf = new ListBuffer[Name] def collectIdents() : Int = { if (in.token == ASTERISK) { @@ -657,7 +662,7 @@ object JavaParsers { accept(SEMI) val names = buf.toList if (names.length < 2) { - syntaxError(offset, "illegal import", skipIt = false) + syntaxError(start, "illegal import", skipIt = false) List() } else { val qual = ((Ident(names.head): Tree) /: names.tail.init) (Select(_, _)) @@ -667,7 +672,8 @@ object JavaParsers { // case nme.WILDCARD => Pair(ident, Ident(null) withPos Position(-1)) // case _ => Pair(ident, ident) // } - List(atPos(offset)(Import(qual, List(ident)))) + val imp = atPos(start) { Import(qual, List(ident)) } + imp :: Nil } } @@ -679,9 +685,9 @@ object JavaParsers { List() } - def classDecl(mods: Modifiers): List[Tree] = { + def classDecl(start: Offset, mods: Modifiers): List[Tree] = { accept(CLASS) - val offset = in.offset + val nameOffset = in.offset val name = identForType() val tparams = typeParams() val superclass = @@ -693,14 +699,15 @@ object JavaParsers { } val interfaces = interfacesOpt() val (statics, body) = typeBody(CLASS, name, tparams) - addCompanionObject(statics, atPos(offset) { + val cls = atPos(start, nameOffset) { TypeDef(name, makeTemplate(superclass :: interfaces, body, tparams, true)).withMods(mods) - }) + } + addCompanionObject(statics, cls) } - def interfaceDecl(mods: Modifiers): List[Tree] = { + def interfaceDecl(start: Offset, mods: Modifiers): List[Tree] = { accept(INTERFACE) - val offset = in.offset + val nameOffset = in.offset val name = identForType() val tparams = typeParams() val parents = @@ -711,11 +718,12 @@ object JavaParsers { List(javaLangObject()) } val (statics, body) = typeBody(INTERFACE, name, tparams) - addCompanionObject(statics, atPos(offset) { + val iface = atPos(start, nameOffset) { TypeDef( name, tparams, makeTemplate(parents, body, tparams, false)).withMods(mods | Flags.Trait | Flags.JavaInterface | Flags.Abstract) - }) + } + addCompanionObject(statics, iface) } def typeBody(leadingToken: Int, parentName: Name, parentTParams: List[TypeDef]): (List[Tree], List[Tree]) = { @@ -730,7 +738,8 @@ object JavaParsers { val statics = new ListBuffer[Tree] val members = new ListBuffer[Tree] while (in.token != RBRACE && in.token != EOF) { - var mods = modifiers(inInterface) + val start = in.offset + var mods = atPos(start) { modifiers(inInterface) } if (in.token == LBRACE) { skipAhead() // skip init block, we just assume we have seen only static accept(RBRACE) @@ -738,7 +747,7 @@ object JavaParsers { in.nextToken() } else { if (in.token == ENUM || definesInterface(in.token)) mods |= Flags.JavaStatic - val decls = memberDecl(mods, parentToken, parentTParams) + val decls = memberDecl(start, mods, parentToken, parentTParams) (if ((mods is Flags.JavaStatic) || inInterface && !(decls exists (_.isInstanceOf[DefDef]))) statics else @@ -761,10 +770,10 @@ object JavaParsers { Select(javaLangDot(nme.annotation), tpnme.Annotation), scalaAnnotationDot(tpnme.ClassfileAnnotation) ) - def annotationDecl(mods: Modifiers): List[Tree] = { + def annotationDecl(start: Offset, mods: Modifiers): List[Tree] = { accept(AT) accept(INTERFACE) - val offset = in.offset + val nameOffset = in.offset val name = identForType() val (statics, body) = typeBody(AT, name, List()) val constructorParams = body.collect { @@ -774,14 +783,15 @@ object JavaParsers { List(), List(constructorParams), TypeTree(), EmptyTree).withMods(Modifiers(Flags.JavaDefined)) val body1 = body.filterNot(_.isInstanceOf[DefDef]) val templ = makeTemplate(annotationParents, constr :: body1, List(), false) - addCompanionObject(statics, atPos(offset) { + val annot = atPos(start, nameOffset) { TypeDef(name, templ).withMods(mods | Flags.Abstract) - }) + } + addCompanionObject(statics, annot) } - def enumDecl(mods: Modifiers): List[Tree] = { + def enumDecl(start: Offset, mods: Modifiers): List[Tree] = { accept(ENUM) - val offset = in.offset + val nameOffset = in.offset val name = identForType() def enumType = Ident(name) val interfaces = interfacesOpt() @@ -824,10 +834,11 @@ object JavaParsers { val superclazz = Apply(TypeApply( Select(New(javaLangDot(tpnme.Enum)), nme.CONSTRUCTOR), List(enumType)), List(Literal(Constant(null)),Literal(Constant(0)))) - addCompanionObject(consts ::: statics ::: predefs, atPos(offset) { + val enum = atPos(start, nameOffset) { TypeDef(name, List(), makeTemplate(superclazz :: interfaces, body, List(), true)).withMods(mods | Flags.Enum) - }) + } + addCompanionObject(consts ::: statics ::: predefs, enum) } def enumConst(enumType: Tree) = { @@ -848,22 +859,21 @@ object JavaParsers { } } - def typeDecl(mods: Modifiers): List[Tree] = in.token match { - case ENUM => enumDecl(mods) - case INTERFACE => interfaceDecl(mods) - case AT => annotationDecl(mods) - case CLASS => classDecl(mods) + def typeDecl(start: Offset, mods: Modifiers): List[Tree] = in.token match { + case ENUM => enumDecl(start, mods) + case INTERFACE => interfaceDecl(start, mods) + case AT => annotationDecl(start, mods) + case CLASS => classDecl(start, mods) case _ => in.nextToken(); syntaxError("illegal start of type declaration", skipIt = true); List(errorTypeTree) } /** CompilationUnit ::= [package QualId semi] TopStatSeq */ def compilationUnit(): Tree = { - var offset = in.offset + val start = in.offset val pkg: RefTree = if (in.token == AT || in.token == PACKAGE) { annotations() - offset = in.offset accept(PACKAGE) val pkg = qualId() accept(SEMI) @@ -880,13 +890,15 @@ object JavaParsers { buf ++= importDecl() while (in.token != EOF && in.token != RBRACE) { while (in.token == SEMI) in.nextToken() - if (in.token != EOF) - buf ++= typeDecl(modifiers(inInterface = false)) + if (in.token != EOF) { + val start = in.offset + val mods = atPos(start) { modifiers(inInterface = false) } + buf ++= typeDecl(start, mods) + } } + val unit = atPos(start) { PackageDef(pkg, buf.toList) } accept(EOF) - atPos(offset) { - makePackaging(pkg, buf.toList) - } + unit } } } diff --git a/src/dotty/tools/dotc/parsing/JavaScanners.scala b/src/dotty/tools/dotc/parsing/JavaScanners.scala index faac8e163..83e16627c 100644 --- a/src/dotty/tools/dotc/parsing/JavaScanners.scala +++ b/src/dotty/tools/dotc/parsing/JavaScanners.scala @@ -27,6 +27,7 @@ object JavaScanners { def nextToken(): Unit = { if (next.token == EMPTY) { + lastOffset = lastCharOffset fetchToken() } else { diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index 97213a685..153b58283 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -63,7 +63,7 @@ object Parsers { atPos(Position(start, end, point))(t) def atPos[T <: Positioned](start: Offset, point: Offset)(t: T): T = - atPos(start, point, in.lastOffset max start)(t) + if (in.lastOffset > start) atPos(start, point, in.lastOffset)(t) else t def atPos[T <: Positioned](start: Offset)(t: T): T = atPos(start, start)(t) @@ -71,7 +71,8 @@ object Parsers { def atPos[T <: Positioned](pos: Position)(t: T): T = if (t.pos.isSourceDerived) t else t.withPos(pos) - def tokenRange = Position(in.offset, in.lastCharOffset, in.offset) + def nameStart: Offset = + if (in.token == BACKQUOTED_IDENT) in.offset + 1 else in.offset def sourcePos(off: Int = in.offset): SourcePosition = source atPos Position(off) @@ -313,8 +314,6 @@ object Parsers { tree } - def emptyConstructor() = atPos(in.offset) { ast.untpd.emptyConstructor } - /* --------------- PLACEHOLDERS ------------------------------------------- */ /** The implicit parameters introduced by `_` in the current expression. @@ -694,9 +693,10 @@ object Parsers { } } else if (in.token == LBRACKET) { + val start = in.offset val tparams = typeParamClause(ParamOwner.TypeParam) if (isIdent && in.name.toString == "->") - atPos(in.skipToken())(TypeLambdaTree(tparams, typ())) + atPos(start, in.skipToken())(TypeLambdaTree(tparams, typ())) else { syntaxErrorOrIncomplete(expectedMessage("`->'")); typ() } } else infixType() @@ -762,7 +762,7 @@ object Parsers { else if (isSimpleLiteral) { SingletonTypeTree(literal()) } else if (in.token == USCORE) { val start = in.skipToken() - typeBounds().withPos(Position(start, in.offset, start)) + typeBounds().withPos(Position(start, in.lastOffset, start)) } else path(thisOK = false, handleSingletonType) match { case r @ SingletonTypeTree(_) => r @@ -866,7 +866,8 @@ object Parsers { def typeParamBounds(pname: TypeName): Tree = { val t = typeBounds() val cbs = contextBounds(pname) - if (cbs.isEmpty) t else atPos(t.pos.start) { ContextBounds(t, cbs) } + if (cbs.isEmpty) t + else atPos((t.pos union cbs.head.pos).start) { ContextBounds(t, cbs) } } def contextBounds(pname: TypeName): List[Tree] = in.token match { @@ -1075,7 +1076,8 @@ object Parsers { val tpt = typeDependingOn(location) if (isWildcard(t) && location != Location.InPattern) { val vd :: rest = placeholderParams - placeholderParams = cpy.ValDef(vd)(tpt = tpt) :: rest + placeholderParams = + cpy.ValDef(vd)(tpt = tpt).withPos(vd.pos union tpt.pos) :: rest } Typed(t, tpt) } @@ -1154,12 +1156,12 @@ object Parsers { case NEW => canApply = false val start = in.skipToken() - val (impl, missingBody) = template(emptyConstructor()) + val (impl, missingBody) = template(emptyConstructor) impl.parents match { case parent :: Nil if missingBody => if (parent.isType) ensureApplied(wrapNew(parent)) else parent case _ => - New(impl) + New(impl.withPos(Position(start, in.lastOffset))) } case _ => if (isLiteral) literal() @@ -1362,15 +1364,15 @@ object Parsers { */ val pattern2 = () => infixPattern() match { case p @ Ident(name) if isVarPattern(p) && in.token == AT => - val pos = in.skipToken() + val offset = in.skipToken() // compatibility for Scala2 `x @ _*` syntax infixPattern() match { case pt @ Ident(tpnme.WILDCARD_STAR) => migrationWarningOrError("The syntax `x @ _*' is no longer supported; use `x : _*' instead", p.pos.start) - atPos(p.pos.start, pos) { Typed(p, pt) } + atPos(p.pos.start, offset) { Typed(p, pt) } case p => - atPos(p.pos.start, pos) { Bind(name, p) } + atPos(p.pos.start, offset) { Bind(name, p) } } case p @ Ident(tpnme.WILDCARD_STAR) => // compatibility for Scala2 `_*` syntax @@ -1590,12 +1592,12 @@ object Parsers { def typeParamClause(ownerKind: ParamOwner.Value): List[TypeDef] = inBrackets { def typeParam(): TypeDef = { val isConcreteOwner = ownerKind == ParamOwner.Class || ownerKind == ParamOwner.Def - val modStart = in.offset + val start = in.offset var mods = annotsAsMods() if (ownerKind == ParamOwner.Class) { mods = modifiers(start = mods) mods = - atPos(modStart, in.offset) { + atPos(start, in.offset) { if (in.token == TYPE) { in.nextToken() mods | Param | ParamAccessor @@ -1605,13 +1607,13 @@ object Parsers { } } } - else mods = atPos(modStart) (mods | Param) + else mods = atPos(start) (mods | Param) if (ownerKind != ParamOwner.Def) { if (isIdent(nme.raw.PLUS)) mods |= Covariant else if (isIdent(nme.raw.MINUS)) mods |= Contravariant if (mods is VarianceFlags) in.nextToken() } - atPos(tokenRange) { + atPos(start, nameStart) { val name = if (isConcreteOwner || in.token != USCORE) ident().toTypeName else { @@ -1645,12 +1647,12 @@ object Parsers { var firstClauseOfCaseClass = ofCaseClass var implicitOffset = -1 // use once def param(): ValDef = { - val modStart = in.offset + val start = in.offset var mods = annotsAsMods() if (owner.isTypeName) { mods = modifiers(start = mods) | ParamAccessor mods = - atPos(modStart, in.offset) { + atPos(start, in.offset) { if (in.token == VAL) { in.nextToken() mods @@ -1663,8 +1665,8 @@ object Parsers { } } } - else mods = atPos(modStart) { mods | Param } - atPos(tokenRange) { + else mods = atPos(start) { mods | Param } + atPos(start, nameStart) { val name = ident() val tpt = if (ctx.settings.YmethodInfer.value && owner.isTermName && in.token != COLON) { @@ -1683,7 +1685,7 @@ object Parsers { if (in.token == EQUALS) { in.nextToken(); expr() } else EmptyTree if (implicitOffset >= 0) { - mods = mods.withPos(mods.pos.withStart(implicitOffset)) + mods = mods.withPos(mods.pos.union(Position(implicitOffset, implicitOffset))) implicitOffset = -1 } ValDef(name, tpt, default).withMods(addFlag(mods, implicitFlag)) @@ -1779,7 +1781,11 @@ object Parsers { else from } - def posMods(start: Int, mods: Modifiers) = atPos(start, in.skipToken())(mods) + def posMods(start: Int, mods: Modifiers) = { + val mods1 = atPos(start)(mods) + in.nextToken() + mods1 + } /** Def ::= val PatDef * | var VarDef @@ -1793,13 +1799,13 @@ object Parsers { */ def defOrDcl(start: Int, mods: Modifiers): Tree = in.token match { case VAL => - patDefOrDcl(posMods(start, mods), in.getDocComment(start)) + patDefOrDcl(start, posMods(start, mods), in.getDocComment(start)) case VAR => - patDefOrDcl(posMods(start, addFlag(mods, Mutable)), in.getDocComment(start)) + patDefOrDcl(start, posMods(start, addFlag(mods, Mutable)), in.getDocComment(start)) case DEF => - defDefOrDcl(posMods(start, mods), in.getDocComment(start)) + defDefOrDcl(start, posMods(start, mods), in.getDocComment(start)) case TYPE => - typeDefOrDcl(posMods(start, mods), in.getDocComment(start)) + typeDefOrDcl(start, posMods(start, mods), in.getDocComment(start)) case _ => tmplDef(start, mods) } @@ -1809,7 +1815,7 @@ object Parsers { * ValDcl ::= Id {`,' Id} `:' Type * VarDcl ::= Id {`,' Id} `:' Type */ - def patDefOrDcl(mods: Modifiers, docstring: Option[Comment] = None): Tree = { + def patDefOrDcl(start: Offset, mods: Modifiers, docstring: Option[Comment] = None): Tree = atPos(start, nameStart) { val lhs = commaSeparated(pattern2) val tpt = typedOpt() val rhs = @@ -1824,7 +1830,7 @@ object Parsers { } else EmptyTree lhs match { case (id @ Ident(name: TermName)) :: Nil => { - cpy.ValDef(id)(name, tpt, rhs).withMods(mods).setComment(docstring) + ValDef(name, tpt, rhs).withMods(mods).setComment(docstring) } case _ => PatDef(mods, lhs, tpt, rhs) } @@ -1835,7 +1841,7 @@ object Parsers { * DefDcl ::= DefSig `:' Type * DefSig ::= id [DefTypeParamClause] ParamClauses */ - def defDefOrDcl(mods: Modifiers, docstring: Option[Comment] = None): Tree = atPos(tokenRange) { + def defDefOrDcl(start: Offset, mods: Modifiers, docstring: Option[Comment] = None): Tree = atPos(start, nameStart) { def scala2ProcedureSyntax(resultTypeStr: String) = { val toInsert = if (in.token == LBRACE) s"$resultTypeStr =" @@ -1910,9 +1916,9 @@ object Parsers { /** TypeDef ::= type Id [TypeParamClause] `=' Type * TypeDcl ::= type Id [TypeParamClause] TypeBounds */ - def typeDefOrDcl(mods: Modifiers, docstring: Option[Comment] = None): Tree = { + def typeDefOrDcl(start: Offset, mods: Modifiers, docstring: Option[Comment] = None): Tree = { newLinesOpt() - atPos(tokenRange) { + atPos(start, nameStart) { val name = ident().toTypeName val tparams = typeParamClauseOpt(ParamOwner.Type) in.token match { @@ -1935,15 +1941,15 @@ object Parsers { val docstring = in.getDocComment(start) in.token match { case TRAIT => - classDef(posMods(start, addFlag(mods, Trait)), docstring) + classDef(start, posMods(start, addFlag(mods, Trait)), docstring) case CLASS => - classDef(posMods(start, mods), docstring) + classDef(start, posMods(start, mods), docstring) case CASECLASS => - classDef(posMods(start, mods | Case), docstring) + classDef(start, posMods(start, mods | Case), docstring) case OBJECT => - objectDef(posMods(start, mods | Module), docstring) + objectDef(start, posMods(start, mods | Module), docstring) case CASEOBJECT => - objectDef(posMods(start, mods | Case | Module), docstring) + objectDef(start, posMods(start, mods | Case | Module), docstring) case _ => syntaxErrorOrIncomplete("expected start of definition") EmptyTree @@ -1953,9 +1959,9 @@ object Parsers { /** ClassDef ::= Id [ClsTypeParamClause] * [ConstrMods] ClsParamClauses TemplateOpt */ - def classDef(mods: Modifiers, docstring: Option[Comment]): TypeDef = atPos(tokenRange) { + def classDef(start: Offset, mods: Modifiers, docstring: Option[Comment]): TypeDef = atPos(start, nameStart) { val name = ident().toTypeName - val constr = atPos(in.offset) { + val constr = atPos(in.lastOffset) { val tparams = typeParamClauseOpt(ParamOwner.Class) val cmods = constrModsOpt() val vparamss = paramClauses(name, mods is Case) @@ -1980,9 +1986,9 @@ object Parsers { /** ObjectDef ::= Id TemplateOpt */ - def objectDef(mods: Modifiers, docstring: Option[Comment] = None): ModuleDef = { + def objectDef(start: Offset, mods: Modifiers, docstring: Option[Comment] = None): ModuleDef = atPos(start, nameStart) { val name = ident() - val template = templateOpt(emptyConstructor()) + val template = templateOpt(emptyConstructor) ModuleDef(name, template).withMods(mods).setComment(docstring) } @@ -2021,12 +2027,12 @@ object Parsers { else { newLineOptWhenFollowedBy(LBRACE) if (in.token == LBRACE) template(constr)._1 - else Template(constr, Nil, EmptyValDef, Nil).withPos(constr.pos.toSynthetic) + else Template(constr, Nil, EmptyValDef, Nil) } /** TemplateBody ::= [nl] `{' TemplateStatSeq `}' */ - def templateBodyOpt(constr: DefDef, parents: List[Tree]) = atPos(constr.pos.start) { + def templateBodyOpt(constr: DefDef, parents: List[Tree]) = { val (self, stats) = if (in.token == LBRACE) templateBody() else (EmptyValDef, Nil) Template(constr, parents, self, stats) @@ -2037,7 +2043,7 @@ object Parsers { if (in.token == WITH) { syntaxError("early definitions are not supported; use trait parameters instead") in.nextToken() - template(emptyConstructor()) + template(emptyConstructor) } r } @@ -2072,7 +2078,7 @@ object Parsers { if (in.token == PACKAGE) { val start = in.skipToken() if (in.token == OBJECT) - stats += objectDef(atPos(start, in.skipToken()) { Modifiers(Package) }) + stats += objectDef(start, atPos(start, in.skipToken()) { Modifiers(Package) }) else stats += packaging(start) } else if (in.token == IMPORT) @@ -2206,7 +2212,7 @@ object Parsers { in.nextToken() if (in.token == OBJECT) { val docstring = in.getDocComment(start) - ts += objectDef(atPos(start, in.skipToken()) { Modifiers(Package) }, docstring) + ts += objectDef(start, atPos(start, in.skipToken()) { Modifiers(Package) }, docstring) if (in.token != EOF) { acceptStatSep() ts ++= topStatSeq() diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 7e2a2893e..701c81a9d 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -253,6 +253,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (vparamss.isEmpty || primaryConstrs.nonEmpty) tparamsTxt else { var modsText = modText(constr.mods, "") + if (!modsText.isEmpty) modsText = " " ~ modsText if (constr.mods.hasAnnotations && !constr.mods.hasFlags) modsText = modsText ~~ " this" withEnclosingDef(constr) { addVparamssText(tparamsTxt ~~ modsText, vparamss) } } diff --git a/src/dotty/tools/dotc/typer/FrontEnd.scala b/src/dotty/tools/dotc/typer/FrontEnd.scala index 6ca69ea45..e008430a7 100644 --- a/src/dotty/tools/dotc/typer/FrontEnd.scala +++ b/src/dotty/tools/dotc/typer/FrontEnd.scala @@ -7,6 +7,7 @@ import Contexts._ import Symbols._ import dotty.tools.dotc.parsing.JavaParsers.JavaParser import parsing.Parsers.Parser +import config.Config import config.Printers.{typr, default} import util.Stats._ import scala.util.control.NonFatal @@ -34,6 +35,7 @@ class FrontEnd extends Phase { else new Parser(unit.source).parse() val printer = if (ctx.settings.Xprint.value.contains("parser")) default else typr printer.println("parsed:\n" + unit.untpdTree.show) + if (Config.checkPositions) unit.untpdTree.checkPos(complete = true) } def enterSyms(implicit ctx: Context) = monitor("indexing") { diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 7a2348cd3..a0862ee38 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -273,6 +273,18 @@ class Namer { typer: Typer => } val inSuperCall = if (ctx.mode is Mode.InSuperCall) InSuperCall else EmptyFlags + + /** The position of the name defined by `tree` + * This is a point position if tree is synthetic, a range position if it comes from source. + * It might also be that tree does not have a position (for instance when synthesized by + * a calling chain from `viewExists`), in that case the return position is NoPosition. + */ + def namePos(tree: MemberDef) = + if (tree.pos.exists) + if (tree.mods.is(Synthetic)) Position(tree.pos.point, tree.pos.point) + else Position(tree.pos.point, tree.pos.point + tree.name.length, tree.pos.point) + else tree.pos + tree match { case tree: TypeDef if tree.isClassDef => val name = checkNoConflict(tree.name.encode).asTypeName @@ -280,7 +292,7 @@ class Namer { typer: Typer => val cls = recordSym(ctx.newClassSymbol( ctx.owner, name, flags | inSuperCall, cls => adjustIfModule(new ClassCompleter(cls, tree)(ctx), tree), - privateWithinClass(tree.mods), tree.pos, ctx.source.file), tree) + privateWithinClass(tree.mods), namePos(tree), ctx.source.file), tree) cls.completer.asInstanceOf[ClassCompleter].init() cls case tree: MemberDef => @@ -315,7 +327,7 @@ class Namer { typer: Typer => recordSym(ctx.newSymbol( ctx.owner, name, flags | deferred | method | higherKinded | inSuperCall1, adjustIfModule(completer, tree), - privateWithinClass(tree.mods), tree.pos), tree) + privateWithinClass(tree.mods), namePos(tree)), tree) case tree: Import => recordSym(ctx.newSymbol( ctx.owner, nme.IMPORT, Synthetic, new Completer(tree), NoSymbol, tree.pos), tree) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 82eda0d0a..dcba7e7c4 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1149,7 +1149,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (sym.is(Lazy, butNot = Deferred | Module | Synthetic) && !sym.isVolatile && ctx.scala2Mode && ctx.settings.rewrite.value.isDefined && !ctx.isAfterTyper) - patch(Position(toUntyped(vdef).envelope.start), "@volatile ") + patch(Position(toUntyped(vdef).pos.start), "@volatile ") } def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = track("typedDefDef") { diff --git a/src/dotty/tools/dotc/typer/VarianceChecker.scala b/src/dotty/tools/dotc/typer/VarianceChecker.scala index 274218ee3..d5dd5a024 100644 --- a/src/dotty/tools/dotc/typer/VarianceChecker.scala +++ b/src/dotty/tools/dotc/typer/VarianceChecker.scala @@ -132,11 +132,11 @@ class VarianceChecker()(implicit ctx: Context) { case defn: MemberDef if skip => ctx.debuglog(s"Skipping variance check of ${sym.showDcl}") case tree: TypeDef => - checkVariance(sym, tree.envelope) + checkVariance(sym, tree.pos) case tree: ValDef => - checkVariance(sym, tree.envelope) + checkVariance(sym, tree.pos) case DefDef(_, tparams, vparamss, _, _) => - checkVariance(sym, tree.envelope) + checkVariance(sym, tree.pos) tparams foreach traverse vparamss foreach (_ foreach traverse) case Template(_, _, _, body) => -- cgit v1.2.3