diff --git a/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala b/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala index a2d178e70c49..275a5614e47f 100644 --- a/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala +++ b/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala @@ -12,7 +12,7 @@ import SymDenotations._ import Contexts._ import Types._ import Symbols._ -import dotty.tools.dotc.util.Positions.Position +import dotty.tools.dotc.util.SourcePosition import Decorators._ import StdNames.nme @@ -47,10 +47,10 @@ object CollectEntryPoints{ def hasJavaMainMethod(sym: Symbol): Boolean = (toDenot(sym).info member nme.main).alternatives exists(x => isJavaMainMethod(x.symbol)) - def fail(msg: String, pos: Position = sym.pos) = { - ctx.warning( sym.name + - s" has a main method with parameter type Array[String], but ${toDenot(sym).fullName} will not be a runnable program.\n Reason: $msg", - sourcePos(sym.pos) + def fail(msg: String, pos: SourcePosition = sym.sourcePos) = { + ctx.warning( + i"""${sym.name} has a main method with parameter type Array[String], but ${sym.fullName} will not be a runnable program. + |Reason: $msg""", sym.sourcePos // TODO: make this next claim true, if possible // by generating valid main methods as static in module classes // not sure what the jvm allows here @@ -92,11 +92,11 @@ object CollectEntryPoints{ fail("main methods cannot be generic.") case MethodTpe(paramNames, paramTypes, resultType) => if (resultType :: paramTypes exists (_.typeSymbol.isAbstractType)) - fail("main methods cannot refer to type parameters or abstract types.", m.symbol.pos) + fail("main methods cannot refer to type parameters or abstract types.", m.symbol.sourcePos) else - isJavaMainMethod(m.symbol) || fail("main method must have exact signature (Array[String])Unit", m.symbol.pos) + isJavaMainMethod(m.symbol) || fail("main method must have exact signature (Array[String])Unit", m.symbol.sourcePos) case tp => - fail(s"don't know what this is: $tp", m.symbol.pos) + fail(s"don't know what this is: $tp", m.symbol.sourcePos) } } } diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 781885faec65..6fe8caa9af2b 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -21,7 +21,8 @@ import Types._ import Symbols._ import Phases._ -import dotty.tools.dotc.util.Positions +import dotty.tools.dotc.util +import dotty.tools.dotc.util.Spans import Decorators._ import tpd._ @@ -41,7 +42,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma type CompilationUnit = dotc.CompilationUnit type Constant = Constants.Constant type Literal = tpd.Literal - type Position = Positions.Position + type Position = Spans.Span type Name = Names.Name type ClassDef = tpd.TypeDef type TypeDef = tpd.TypeDef @@ -77,7 +78,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma type Closure = tpd.Closure val NoSymbol: Symbol = Symbols.NoSymbol - val NoPosition: Position = Positions.NoPosition + val NoPosition: Position = Spans.NoSpan val EmptyTree: Tree = tpd.EmptyTree @@ -380,16 +381,17 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma ctx.requiredModule(className) } - def debuglog(msg: => String): Unit = ctx.debuglog(msg) def informProgress(msg: String): Unit = ctx.informProgress(msg) def log(msg: => String): Unit = ctx.log(msg) - def error(pos: Position, msg: String): Unit = ctx.error(msg, pos) - def warning(pos: Position, msg: String): Unit = ctx.warning(msg, pos) + def error(pos: Position, msg: String): Unit = ctx.error(msg, sourcePos(pos)) + def warning(pos: Position, msg: String): Unit = ctx.warning(msg, sourcePos(pos)) def abort(msg: String): Nothing = { ctx.error(msg) throw new RuntimeException(msg) } + def sourcePos(pos: Position)(implicit ctx: Context): util.SourcePosition = + ctx.source.atSpan(pos) def emitAsmp: Option[String] = None @@ -502,7 +504,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma i"""|compiler bug: created invalid generic signature for $sym in ${sym.denot.owner.showFullName} |signature: $sig |if this is reproducible, please report bug at https://github.com/lampepfl/dotty/issues - """.trim, sym.pos) + """.trim, sym.sourcePos) } } @@ -587,7 +589,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma implicit def treeHelper(a: Tree): TreeHelper = new TreeHelper { def symbol: Symbol = a.symbol - def pos: Position = a.pos + def pos: Position = a.span def isEmpty: Boolean = a.isEmpty @@ -809,7 +811,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def moduleSuffix: String = "" // todo: validate that names already have $ suffix def outputDirectory: AbstractFile = DottyBackendInterface.this.outputDirectory - def pos: Position = sym.pos + def pos: Position = sym.span def throwsAnnotations: List[Symbol] = Nil @@ -1105,7 +1107,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def _1: Type = field.tpe match { case JavaArrayType(elem) => elem case _ => - ctx.error(s"JavaSeqArray with type ${field.tpe} reached backend: $field", field.pos) + error(field.span, s"JavaSeqArray with type ${field.tpe} reached backend: $field") UnspecifiedErrorType } def _2: List[Tree] = field.elems diff --git a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala index fe5d3c08aa8a..daabf824cead 100644 --- a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala +++ b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala @@ -163,7 +163,7 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter else (dupClassSym, classSymbol) ctx.atPhase(ctx.typerPhase) { implicit ctx => ctx.warning(s"${cl1.show} differs only in case from ${cl2.showLocated}. " + - "Such classes will overwrite one another on case-insensitive filesystems.", cl1.pos) + "Such classes will overwrite one another on case-insensitive filesystems.", cl1.sourcePos) } } } diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 48c363ee65e0..18a7a88e0b24 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -129,7 +129,7 @@ class JSCodeGen()(implicit ctx: Context) { /* Finally, we emit true code for the remaining class defs. */ for (td <- allTypeDefs) { val sym = td.symbol - implicit val pos: Position = sym.pos + implicit val pos: Position = sym.span /* Do not actually emit code for primitive types nor scala.Array. */ val isPrimitive = @@ -197,7 +197,7 @@ class JSCodeGen()(implicit ctx: Context) { */ private def genScalaClass(td: TypeDef): js.ClassDef = { val sym = td.symbol.asClass - implicit val pos: Position = sym.pos + implicit val pos: Position = sym.span assert(!sym.is(Trait), "genScalaClass() must be called only for normal classes: "+sym) @@ -321,7 +321,7 @@ class JSCodeGen()(implicit ctx: Context) { */ private def genRawJSClassData(td: TypeDef): js.ClassDef = { val sym = td.symbol.asClass - implicit val pos: Position = sym.pos + implicit val pos: Position = sym.span val classIdent = encodeClassFullNameIdent(sym) val kind = { @@ -357,7 +357,7 @@ class JSCodeGen()(implicit ctx: Context) { */ private def genInterface(td: TypeDef): js.ClassDef = { val sym = td.symbol.asClass - implicit val pos: Position = sym.pos + implicit val pos: Position = sym.span val classIdent = encodeClassFullNameIdent(sym) @@ -413,7 +413,7 @@ class JSCodeGen()(implicit ctx: Context) { // Non-method term members are fields classSym.info.decls.filter(f => !f.is(Method) && f.isTerm).map({ f => - implicit val pos = f.pos + implicit val pos = f.span val name = /*if (isExposed(f)) js.StringLiteral(jsNameOf(f)) @@ -484,7 +484,7 @@ class JSCodeGen()(implicit ctx: Context) { * Other (normal) methods are emitted with `genMethodBody()`. */ private def genMethodWithCurrentLocalNameScope(dd: DefDef): Option[js.MethodDef] = { - implicit val pos = dd.pos + implicit val pos = dd.span val sym = dd.symbol val vparamss = dd.vparamss val rhs = dd.rhs @@ -506,7 +506,7 @@ class JSCodeGen()(implicit ctx: Context) { val methodName: js.PropertyName = encodeMethodSym(sym) def jsParams = for (param <- params) yield { - implicit val pos = param.pos + implicit val pos = param.span js.ParamDef(encodeLocalSym(param), toIRType(param.info), mutable = false, rest = false) } @@ -579,13 +579,13 @@ class JSCodeGen()(implicit ctx: Context) { private def genMethodDef(static: Boolean, methodName: js.PropertyName, paramsSyms: List[Symbol], resultIRType: jstpe.Type, tree: Tree, optimizerHints: OptimizerHints): js.MethodDef = { - implicit val pos = tree.pos + implicit val pos = tree.span ctx.debuglog("genMethod " + methodName.encodedName) ctx.debuglog("") val jsParams = for (param <- paramsSyms) yield { - implicit val pos = param.pos + implicit val pos = param.span js.ParamDef(encodeLocalSym(param), toIRType(param.info), mutable = false, rest = false) } @@ -598,7 +598,7 @@ class JSCodeGen()(implicit ctx: Context) { js.MethodDef(static, methodName, jsParams, resultIRType, Some(genBody()))( optimizerHints, None) /*} else { - assert(!static, tree.pos) + assert(!static, tree.span) withScopedVars( thisLocalVarIdent := Some(freshLocalIdent("this")) @@ -639,7 +639,7 @@ class JSCodeGen()(implicit ctx: Context) { private def genExpr(tree: Tree): js.Tree = { val result = genStatOrExpr(tree, isStat = false) assert(result.tpe != jstpe.NoType, - s"genExpr($tree) returned a tree with type NoType at pos ${tree.pos}") + s"genExpr($tree) returned a tree with type NoType at pos ${tree.span}") result } @@ -649,7 +649,7 @@ class JSCodeGen()(implicit ctx: Context) { * is transformed into an equivalent portion of the JS AST. */ private def genStatOrExpr(tree: Tree, isStat: Boolean): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span ctx.debuglog(" " + tree) ctx.debuglog("") @@ -660,7 +660,7 @@ class JSCodeGen()(implicit ctx: Context) { /* Must have been eliminated by the tail call transform performed * by genMethodBody(). */ assert(name != nme.THIS, - s"ValDef(_, nme.THIS, _, _) found at ${tree.pos}") + s"ValDef(_, nme.THIS, _, _) found at ${tree.span}") val sym = tree.symbol val rhs = tree.rhs @@ -719,7 +719,7 @@ class JSCodeGen()(implicit ctx: Context) { "Trying to access the this of another class: " + "tree.symbol = " + tree.symbol + ", class symbol = " + currentClassSym.get + - " pos:" + pos) + " span:" + pos) genLoadModule(tree.symbol) } @@ -856,7 +856,7 @@ class JSCodeGen()(implicit ctx: Context) { case _ => throw new FatalError("Unexpected tree in genExpr: " + - tree + "/" + tree.getClass + " at: " + (tree.pos: Position)) + tree + "/" + tree.getClass + " at: " + (tree.span: Position)) } } // end of genStatOrExpr() @@ -897,7 +897,7 @@ class JSCodeGen()(implicit ctx: Context) { * primitives, JS calls, etc. They are further dispatched in here. */ private def genApply(tree: Apply, isStat: Boolean): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span val args = tree.args val sym = tree.fun.symbol @@ -944,7 +944,7 @@ class JSCodeGen()(implicit ctx: Context) { * irrelevant. */ private def genSuperCall(tree: Apply, isStat: Boolean): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span val Apply(fun @ Select(sup @ Super(_, mix), _), args) = tree val sym = fun.symbol @@ -955,7 +955,7 @@ class JSCodeGen()(implicit ctx: Context) { genJSSuperCall(tree, isStat) } else*/ { val superCall = genApplyMethodStatically( - genThis()(sup.pos), sym, genActualArgs(sym, args)) + genThis()(sup.span), sym, genActualArgs(sym, args)) // Initialize the module instance just after the super constructor call. if (isStaticModule(currentClassSym) && !isModuleInitialized && @@ -980,7 +980,7 @@ class JSCodeGen()(implicit ctx: Context) { * * regular new */ private def genApplyNew(tree: Apply): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span val Apply(fun @ Select(New(tpt), nme.CONSTRUCTOR), args) = tree val ctor = fun.symbol @@ -1038,7 +1038,7 @@ class JSCodeGen()(implicit ctx: Context) { private def genPrimitiveOp(tree: Apply, isStat: Boolean): js.Tree = { import scala.tools.nsc.backend.ScalaPrimitivesOps._ - implicit val pos = tree.pos + implicit val pos = tree.span val Apply(fun, args) = tree val receiver = qualifierOf(fun) @@ -1078,7 +1078,7 @@ class JSCodeGen()(implicit ctx: Context) { private def genSimpleUnaryOp(tree: Apply, arg: Tree, code: Int): js.Tree = { import scala.tools.nsc.backend.ScalaPrimitivesOps._ - implicit val pos = tree.pos + implicit val pos = tree.span val resultIRType = toIRType(tree.tpe) val genArg = adaptPrimitive(genExpr(arg), resultIRType) @@ -1120,7 +1120,7 @@ class JSCodeGen()(implicit ctx: Context) { import scala.tools.nsc.backend.ScalaPrimitivesOps._ import js.UnaryOp._ - implicit val pos = tree.pos + implicit val pos = tree.span val lhsIRType = toIRType(lhs.tpe) val rhsIRType = toIRType(rhs.tpe) @@ -1423,7 +1423,7 @@ class JSCodeGen()(implicit ctx: Context) { */ private def genStringConcat(tree: Apply, receiver: Tree, args: List[Tree]): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span val arg = args.head @@ -1450,7 +1450,7 @@ class JSCodeGen()(implicit ctx: Context) { /** Gen JS code for a call to Any.## */ private def genScalaHash(tree: Apply, receiver: Tree): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span genModuleApplyMethod(defn.ScalaRuntimeModule.requiredMethod(nme.hash_), List(genExpr(receiver))) @@ -1460,7 +1460,7 @@ class JSCodeGen()(implicit ctx: Context) { private def genArrayOp(tree: Tree, code: Int): js.Tree = { import scala.tools.nsc.backend.ScalaPrimitivesOps._ - implicit val pos = tree.pos + implicit val pos = tree.span val Apply(fun, args) = tree val arrayObj = qualifierOf(fun) @@ -1512,7 +1512,7 @@ class JSCodeGen()(implicit ctx: Context) { // common case for which there is no side-effect nor NPE genArg case _ => - implicit val pos = tree.pos + implicit val pos = tree.span /* TODO Check for a null receiver? * In theory, it's UB, but that decision should be left for link time. */ @@ -1522,7 +1522,7 @@ class JSCodeGen()(implicit ctx: Context) { /** Gen JS code for a coercion */ private def genCoercion(tree: Apply, receiver: Tree, code: Int): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span val source = genExpr(receiver) val resultType = toIRType(tree.tpe) @@ -1531,7 +1531,7 @@ class JSCodeGen()(implicit ctx: Context) { /** Gen a call to the special `throw` method. */ private def genThrow(tree: Apply, args: List[Tree]): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span val exception = args.head val genException = genExpr(exception) js.Throw { @@ -1555,7 +1555,7 @@ class JSCodeGen()(implicit ctx: Context) { * * Regular method call */ private def genNormalApply(tree: Apply, isStat: Boolean): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span val fun = tree.fun match { case fun: Ident => desugarIdent(fun).get @@ -1601,14 +1601,14 @@ class JSCodeGen()(implicit ctx: Context) { jsSuperClassValue: Option[js.Tree] = None)( implicit pos: Position): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span def noSpread = !args.exists(_.isInstanceOf[js.JSSpread]) val argc = args.size // meaningful only for methods that don't have varargs def requireNotSuper(): Unit = { if (jsSuperClassValue.isDefined) - ctx.error("Illegal super call in Scala.js-defined JS class", tree.pos) + ctx.error("Illegal super call in Scala.js-defined JS class", tree.sourcePos) } def requireNotSpread(arg: js.TreeOrJSSpread): js.Tree = @@ -1759,7 +1759,7 @@ class JSCodeGen()(implicit ctx: Context) { * primitive instead.) */ private def genTypeApply(tree: TypeApply): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span val TypeApply(fun, targs) = tree @@ -1787,7 +1787,7 @@ class JSCodeGen()(implicit ctx: Context) { /** Gen JS code for a Java Seq literal. */ private def genJavaSeqLiteral(tree: JavaSeqLiteral): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span val genElems = tree.elems.map(genExpr) val arrayTypeRef = toTypeRef(tree.tpe).asInstanceOf[jstpe.ArrayTypeRef] @@ -1836,7 +1836,7 @@ class JSCodeGen()(implicit ctx: Context) { * available in the `body`. */ private def genClosure(tree: Closure): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span val Closure(env, call, functionalInterface) = tree val envSize = env.size @@ -1852,7 +1852,7 @@ class JSCodeGen()(implicit ctx: Context) { val allCaptureValues = qualifier :: env val formalAndActualCaptures = allCaptureValues.map { value => - implicit val pos = value.pos + implicit val pos = value.span val formalIdent = value match { case Ident(name) => freshLocalIdent(name.toString) case This(_) => freshLocalIdent("this") @@ -1975,7 +1975,7 @@ class JSCodeGen()(implicit ctx: Context) { /** Gen JS code for an isInstanceOf test (for reference types only) */ private def genIsInstanceOf(tree: Tree, value: js.Tree, to: Type): js.Tree = { - implicit val pos = tree.pos + implicit val pos = tree.span val sym = to.widenDealias.typeSymbol if (sym == defn.ObjectClass) { @@ -1984,7 +1984,7 @@ class JSCodeGen()(implicit ctx: Context) { if (sym.is(Trait)) { ctx.error( s"isInstanceOf[${sym.fullName}] not supported because it is a JS trait", - tree.pos) + tree.sourcePos) js.BooleanLiteral(true) } else { js.Unbox(js.JSBinaryOp( @@ -2193,7 +2193,7 @@ class JSCodeGen()(implicit ctx: Context) { * to perform the conversion to js.Array, then wrap in a Spread * operator. */ - implicit val pos = arg.pos + implicit val pos = arg.span val jsArrayArg = genModuleApplyMethod( jsdefn.Runtime_toJSVarArgs, List(genExpr(arg))) @@ -2210,7 +2210,7 @@ class JSCodeGen()(implicit ctx: Context) { */ private def tryGenRepeatedParamAsJSArray(arg: Tree, handleNil: Boolean): Option[List[js.Tree]] = { - implicit val pos = arg.pos + implicit val pos = arg.span // Given a method `def foo(args: T*)` arg match { diff --git a/compiler/src/dotty/tools/backend/sjs/JSPositions.scala b/compiler/src/dotty/tools/backend/sjs/JSPositions.scala index 0e2bae540d97..46c4509229b3 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSPositions.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSPositions.scala @@ -2,8 +2,8 @@ package dotty.tools.backend.sjs import dotty.tools.dotc.core._ import Contexts._ -import dotty.tools.dotc.util.Positions -import Positions.Position +import dotty.tools.dotc.util.Spans +import Spans.Span import org.scalajs.ir @@ -11,11 +11,11 @@ import org.scalajs.ir class JSPositions()(implicit ctx: Context) { /** Implicit conversion from dotty Position to ir.Position. */ - implicit def pos2irPos(pos: Position): ir.Position = { - if (!pos.exists) ir.Position.NoPosition + implicit def pos2irPos(span: Span): ir.Position = { + if (!span.exists) ir.Position.NoPosition else { val source = pos2irPosCache.toIRSource(ctx.compilationUnit.source) - val sourcePos = ctx.compilationUnit.source.atPos(pos) + val sourcePos = ctx.compilationUnit.source.atSpan(span) // dotty positions are 1-based but IR positions are 0-based ir.Position(source, sourcePos.line-1, sourcePos.column-1) } @@ -23,8 +23,8 @@ class JSPositions()(implicit ctx: Context) { /** Implicitly materializes an ir.Position from an implicit dotty Position. */ implicit def implicitPos2irPos( - implicit pos: Position): ir.Position = { - pos2irPos(pos) + implicit span: Span): ir.Position = { + pos2irPos(span) } private[this] object pos2irPosCache { // scalastyle:ignore diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index 00527db565a8..bce33813fa70 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -9,8 +9,9 @@ import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.SymDenotations.ClassDenotation import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.transform.SymUtils._ +import util.{NoSource, SourceFile} -class CompilationUnit(val source: SourceFile) { +class CompilationUnit protected (val source: SourceFile) { override def toString: String = source.toString @@ -34,12 +35,12 @@ class CompilationUnit(val source: SourceFile) { object CompilationUnit { - /** Make a compilation unit for top class `clsd` with the contends of the `unpickled` */ - def mkCompilationUnit(clsd: ClassDenotation, unpickled: Tree, forceTrees: Boolean)(implicit ctx: Context): CompilationUnit = - mkCompilationUnit(SourceFile(clsd.symbol.associatedFile, Array.empty), unpickled, forceTrees) + /** Make a compilation unit for top class `clsd` with the contents of the `unpickled` tree */ + def apply(clsd: ClassDenotation, unpickled: Tree, forceTrees: Boolean)(implicit ctx: Context): CompilationUnit = + apply(new SourceFile(clsd.symbol.associatedFile, Array.empty[Char]), unpickled, forceTrees) /** Make a compilation unit, given picked bytes and unpickled tree */ - def mkCompilationUnit(source: SourceFile, unpickled: Tree, forceTrees: Boolean)(implicit ctx: Context): CompilationUnit = { + def apply(source: SourceFile, unpickled: Tree, forceTrees: Boolean)(implicit ctx: Context): CompilationUnit = { assert(!unpickled.isEmpty, unpickled) val unit1 = new CompilationUnit(source) unit1.tpdTree = unpickled @@ -51,6 +52,20 @@ object CompilationUnit { unit1 } + def apply(source: SourceFile)(implicit ctx: Context): CompilationUnit = { + val src = + if (source.file.isDirectory) { + ctx.error(s"expected file, received directory '${source.file.path}'") + NoSource + } + else if (!source.file.exists) { + ctx.error(s"not found: ${source.file.path}") + NoSource + } + else source + new CompilationUnit(source) + } + /** Force the tree to be loaded */ private class Force extends TreeTraverser { var needsStaging = false diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index 9067693e1168..a58ee0723107 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -99,22 +99,8 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint /** Actions that need to be performed at the end of the current compilation run */ private[this] var finalizeActions = mutable.ListBuffer[() => Unit]() - def getSource(fileName: String): SourceFile = { - val f = new PlainFile(io.Path(fileName)) - if (f.isDirectory) { - ctx.error(s"expected file, received directory '$fileName'") - NoSource - } - else if (f.exists) - ctx.getSource(f) - else { - ctx.error(s"not found: $fileName") - NoSource - } - } - def compile(fileNames: List[String]): Unit = try { - val sources = fileNames map getSource + val sources = fileNames.map(ctx.getSource(_)) compileSources(sources) } catch { case NonFatal(ex) => @@ -130,7 +116,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint */ def compileSources(sources: List[SourceFile]): Unit = if (sources forall (_.exists)) { - units = sources map (new CompilationUnit(_)) + units = sources.map(CompilationUnit(_)) compileUnits() } @@ -206,7 +192,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint def lateCompile(file: AbstractFile, typeCheck: Boolean)(implicit ctx: Context): Unit = if (!files.contains(file) && !lateFiles.contains(file)) { lateFiles += file - val unit = new CompilationUnit(getSource(file.path)) + val unit = CompilationUnit(ctx.getSource(file.path)) def process()(implicit ctx: Context) = { unit.untpdTree = if (unit.isJava) new JavaParser(unit.source).parse() @@ -254,7 +240,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint } def compile(sourceCode: String): Unit = { - val virtualFile = new VirtualFile(sourceCode) // use source code as name as it's used for equals + val virtualFile = new VirtualFile(sourceCode) val writer = new BufferedWriter(new OutputStreamWriter(virtualFile.output, "UTF-8")) // buffering is still advised by javadoc writer.write(sourceCode) writer.close() diff --git a/compiler/src/dotty/tools/dotc/ast/CheckTrees.scala.disabled b/compiler/src/dotty/tools/dotc/ast/CheckTrees.scala.disabled index 255619f35d18..ea8a8709b00f 100644 --- a/compiler/src/dotty/tools/dotc/ast/CheckTrees.scala.disabled +++ b/compiler/src/dotty/tools/dotc/ast/CheckTrees.scala.disabled @@ -3,7 +3,7 @@ package dotc package ast import core._ -import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._ +import util.Spans._, Types._, Contexts._, Constants._, Names._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ // TODO: revise, integrate in a checking phase. diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index c6706e3e2368..3f835bbb96e2 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -3,15 +3,16 @@ package dotc package ast import core._ -import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ +import util.Spans._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ import Symbols._, StdNames._, Trees._ import Decorators._, transform.SymUtils._ import NameKinds.{UniqueName, EvidenceParamName, DefaultGetterName} import typer.FrontEnd -import util.Property +import util.{Property, SourceFile} import collection.mutable.ListBuffer import reporting.diagnostic.messages._ import reporting.trace +import annotation.constructorOnly import scala.annotation.internal.sharable @@ -42,15 +43,15 @@ object desugar { // ----- DerivedTypeTrees ----------------------------------- - class SetterParamTree extends DerivedTypeTree { + class SetterParamTree(implicit @constructorOnly src: SourceFile) extends DerivedTypeTree { def derivedTree(sym: Symbol)(implicit ctx: Context): tpd.TypeTree = tpd.TypeTree(sym.info.resultType) } - class TypeRefTree extends DerivedTypeTree { + class TypeRefTree(implicit @constructorOnly src: SourceFile) extends DerivedTypeTree { def derivedTree(sym: Symbol)(implicit ctx: Context): tpd.TypeTree = tpd.TypeTree(sym.typeRef) } - class TermRefTree extends DerivedTypeTree { + class TermRefTree(implicit @constructorOnly src: SourceFile) extends DerivedTypeTree { def derivedTree(sym: Symbol)(implicit ctx: Context): tpd.Tree = tpd.ref(sym) } @@ -58,7 +59,7 @@ object desugar { * @param suffix String difference between existing parameter (call it `P`) and parameter owning the * DerivedTypeTree (call it `O`). We have: `O.name == P.name + suffix`. */ - class DerivedFromParamTree(suffix: String) extends DerivedTypeTree { + class DerivedFromParamTree(suffix: String)(implicit @constructorOnly src: SourceFile) extends DerivedTypeTree { /** Make sure that for all enclosing module classes their companion classes * are completed. Reason: We need the constructor of such companion classes to @@ -109,10 +110,10 @@ object desugar { } /** A type definition copied from `tdef` with a rhs typetree derived from it */ - def derivedTypeParam(tdef: TypeDef, suffix: String = ""): TypeDef = + def derivedTypeParam(tdef: TypeDef, suffix: String = "")(implicit ctx: Context): TypeDef = cpy.TypeDef(tdef)( name = tdef.name ++ suffix, - rhs = new DerivedFromParamTree(suffix).withPos(tdef.rhs.pos).watching(tdef) + rhs = new DerivedFromParamTree(suffix).withSpan(tdef.rhs.span).watching(tdef) ) /** A derived type definition watching `sym` */ @@ -120,9 +121,9 @@ object desugar { TypeDef(sym.name, new DerivedFromParamTree("").watching(sym)).withFlags(TypeParam) /** A value definition copied from `vdef` with a tpt typetree derived from it */ - def derivedTermParam(vdef: ValDef): ValDef = + def derivedTermParam(vdef: ValDef)(implicit ctx: Context): ValDef = cpy.ValDef(vdef)( - tpt = new DerivedFromParamTree("") withPos vdef.tpt.pos watching vdef) + tpt = new DerivedFromParamTree("").withSpan(vdef.tpt.span).watching(vdef)) // ----- Desugar methods ------------------------------------------------- @@ -350,10 +351,10 @@ object desugar { val constrVparamss = if (originalVparamss.isEmpty) { // ensure parameter list is non-empty if (isCaseClass && originalTparams.isEmpty) - ctx.error(CaseClassMissingParamList(cdef), cdef.namePos) + ctx.error(CaseClassMissingParamList(cdef), cdef.sourcePos.withSpan(cdef.nameSpan)) ListOfNil } else if (isCaseClass && originalVparamss.head.exists(_.mods.is(Implicit))) { - ctx.error("Case classes should have a non-implicit parameter list", cdef.namePos) + ctx.error("Case classes should have a non-implicit parameter list", cdef.sourcePos.withSpan(cdef.nameSpan)) ListOfNil } else originalVparamss.nestedMap(toDefParam) @@ -397,7 +398,7 @@ object desugar { def appliedTypeTree(tycon: Tree, args: List[Tree]) = (if (args.isEmpty) tycon else AppliedTypeTree(tycon, args)) - .withPos(cdef.pos.startPos) + .withSpan(cdef.span.startPos) def isHK(tparam: Tree): Boolean = tparam match { case TypeDef(_, LambdaTypeTree(tparams, body)) => true @@ -432,7 +433,7 @@ object desugar { appliedRef(enumClassRef) else { ctx.error(i"explicit extends clause needed because both enum case and enum class have type parameters" - , cdef.pos.startPos) + , cdef.sourcePos.startPos) appliedTypeTree(enumClassRef, constrTparams map (_ => anyRef)) } @@ -563,7 +564,7 @@ object desugar { ModuleDef( className.toTermName, Template(emptyConstructor, parentTpt :: Nil, EmptyValDef, defs)) .withMods(companionMods | Synthetic)) - .withPos(cdef.pos).toList + .withSpan(cdef.span).toList val companionMembers = defaultGetters ::: eqInstances ::: enumCases @@ -636,15 +637,15 @@ object desugar { if (!isImplicit) Nil else if (ctx.owner is Package) { - ctx.error(TopLevelImplicitClass(cdef), cdef.pos) + ctx.error(TopLevelImplicitClass(cdef), cdef.sourcePos) Nil } else if (isCaseClass) { - ctx.error(ImplicitCaseClass(cdef), cdef.pos) + ctx.error(ImplicitCaseClass(cdef), cdef.sourcePos) Nil } else if (arity != 1) { - ctx.error(ImplicitClassPrimaryConstructorArity(), cdef.pos) + ctx.error(ImplicitClassPrimaryConstructorArity(), cdef.sourcePos) Nil } else @@ -652,7 +653,7 @@ object desugar { // we can reuse the constructor parameters; no derived params are needed. DefDef(className.toTermName, constrTparams, constrVparamss, classTypeRef, creatorExpr) .withMods(companionMods | Synthetic | Implicit) - .withPos(cdef.pos) :: Nil + .withSpan(cdef.span) :: Nil val self1 = { val selfType = if (self.tpt.isEmpty) classTypeRef else self.tpt @@ -703,23 +704,23 @@ object desugar { if (mods is Package) PackageDef(Ident(moduleName), cpy.ModuleDef(mdef)(nme.PACKAGE, impl).withMods(mods &~ Package) :: Nil) else if (isEnumCase) - expandEnumModule(moduleName, impl, mods, mdef.pos) + expandEnumModule(moduleName, impl, mods, mdef.span) else { val clsName = moduleName.moduleClassName val clsRef = Ident(clsName) val modul = ValDef(moduleName, clsRef, New(clsRef, Nil)) .withMods(mods.toTermFlags & RetainedModuleValFlags | ModuleValCreationFlags) - .withPos(mdef.pos.startPos) + .withSpan(mdef.span.startPos) val ValDef(selfName, selfTpt, _) = impl.self val selfMods = impl.self.mods - if (!selfTpt.isEmpty) ctx.error(ObjectMayNotHaveSelfType(mdef), impl.self.pos) + if (!selfTpt.isEmpty) ctx.error(ObjectMayNotHaveSelfType(mdef), impl.self.sourcePos) val clsSelf = ValDef(selfName, SingletonTypeTree(Ident(moduleName)), impl.self.rhs) .withMods(selfMods) - .withPos(impl.self.pos orElse impl.pos.startPos) + .withSpan(impl.self.span.orElse(impl.span.startPos)) val clsTmpl = cpy.Template(impl)(self = clsSelf, body = impl.body) val cls = TypeDef(clsName, clsTmpl) .withMods(mods.toTypeFlags & RetainedModuleClassFlags | ModuleClassCreationFlags) - Thicket(modul, classDef(cls).withPos(mdef.pos)) + Thicket(modul, classDef(cls).withSpan(mdef.span)) } } @@ -739,7 +740,7 @@ object desugar { */ def opaqueAlias(tdef: TypeDef)(implicit ctx: Context): Tree = if (tdef.rhs.isInstanceOf[TypeBoundsTree]) { - ctx.error(em"opaque type ${tdef.name} must be an alias type", tdef.pos) + ctx.error(em"opaque type ${tdef.name} must be an alias type", tdef.sourcePos) tdef.withFlags(tdef.mods.flags &~ Opaque) } else { @@ -772,7 +773,7 @@ object desugar { val name = mdef.name if (ctx.owner == defn.ScalaPackageClass && defn.reservedScalaClassNames.contains(name.toTypeName)) { def kind = if (name.isTypeName) "class" else "object" - ctx.error(em"illegal redefinition of standard $kind $name", mdef.pos) + ctx.error(em"illegal redefinition of standard $kind $name", mdef.sourcePos) name.errorName } else name @@ -792,7 +793,7 @@ object desugar { pats map { case id: Ident => expandSimpleEnumCase(id.name.asTermName, mods, - Position(pdef.pos.start, id.pos.end, id.pos.start)) + Span(pdef.span.start, id.span.end, id.span.start)) } else { val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt)) @@ -841,7 +842,7 @@ object desugar { mods & Lazy | Synthetic | (if (ctx.owner.isClass) PrivateLocal else EmptyFlags) val firstDef = ValDef(tmpName, TypeTree(), matchExpr) - .withPos(pat.pos.union(rhs.pos)).withMods(patMods) + .withSpan(pat.span.union(rhs.span)).withMods(patMods) def selector(n: Int) = Select(Ident(tmpName), nme.selectorName(n)) val restDefs = for (((named, tpt), n) <- vars.zipWithIndex) @@ -855,7 +856,7 @@ object desugar { /** Expand variable identifier x to x @ _ */ def patternVar(tree: Tree)(implicit ctx: Context): Bind = { val Ident(name) = tree - Bind(name, Ident(nme.WILDCARD)).withPos(tree.pos) + Bind(name, Ident(nme.WILDCARD)).withSpan(tree.span) } def defTree(tree: Tree)(implicit ctx: Context): Tree = tree match { @@ -878,7 +879,7 @@ object desugar { def block(tree: Block)(implicit ctx: Context): Block = tree.expr match { case EmptyTree => cpy.Block(tree)(tree.stats, - unitLiteral withPos (if (tree.stats.isEmpty) tree.pos else tree.pos.endPos)) + unitLiteral.withSpan(if (tree.stats.isEmpty) tree.span else tree.span.endPos)) case _ => tree } @@ -893,19 +894,19 @@ object desugar { case Assign(Ident(name), rhs) => cpy.NamedArg(arg)(name, rhs) case _ => arg } - def makeOp(fn: Tree, arg: Tree, selectPos: Position) = { + def makeOp(fn: Tree, arg: Tree, selectPos: Span) = { val args: List[Tree] = arg match { case Parens(arg) => assignToNamedArg(arg) :: Nil case Tuple(args) => args.mapConserve(assignToNamedArg) case _ => arg :: Nil } - Apply(Select(fn, op.name).withPos(selectPos), args) + Apply(Select(fn, op.name).withSpan(selectPos), args) } if (isLeftAssoc(op.name)) - makeOp(left, right, Position(left.pos.start, op.pos.end, op.pos.start)) + makeOp(left, right, Span(left.span.start, op.span.end, op.span.start)) else - makeOp(right, left, Position(op.pos.start, right.pos.end)) + makeOp(right, left, Span(op.span.start, right.span.end)) } /** Translate tuple expressions of arity <= 22 @@ -932,10 +933,14 @@ object desugar { * def $anonfun(params) = body * Closure($anonfun) */ - def makeClosure(params: List[ValDef], body: Tree, tpt: Tree = TypeTree(), isImplicit: Boolean)(implicit ctx: Context): Block = + def makeClosure(params: List[ValDef], body: Tree, tpt: Tree = null, isImplicit: Boolean)(implicit ctx: Context): Block = { + val span = params.headOption.fold(body.span)(_.span.union(body.span)) Block( - DefDef(nme.ANON_FUN, Nil, params :: Nil, tpt, body).withMods(synthetic | Artifact), - Closure(Nil, Ident(nme.ANON_FUN), if (isImplicit) ImplicitEmptyTree else EmptyTree)) + DefDef(nme.ANON_FUN, Nil, params :: Nil, if (tpt == null) TypeTree() else tpt, body) + .withSpan(span) + .withMods(synthetic | Artifact), + Closure(Nil, Ident(nme.ANON_FUN), if (isImplicit) ImplicitEmptyTree else EmptyTree)).withSpan(span) + } /** If `nparams` == 1, expand partial function * @@ -983,7 +988,7 @@ object desugar { val vdefs = params.zipWithIndex.map{ case (param, idx) => - DefDef(param.name, Nil, Nil, TypeTree(), selector(idx)).withPos(param.pos) + DefDef(param.name, Nil, Nil, TypeTree(), selector(idx)).withSpan(param.span) } Function(param :: Nil, Block(vdefs, body)) } @@ -1019,15 +1024,15 @@ object desugar { 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)) + .withSpan(original.span.withPoint(named.span.start)) val mayNeedSetter = valDef(vdef) mayNeedSetter } - private def derivedDefDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers) = + private def derivedDefDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit src: SourceFile) = DefDef(named.name.asTermName, Nil, Nil, tpt, rhs) .withMods(mods) - .withPos(original.pos.withPoint(named.pos.start)) + .withSpan(original.span.withPoint(named.span.start)) /** Main desugaring method */ def apply(tree: Tree)(implicit ctx: Context): Tree = { @@ -1277,7 +1282,7 @@ object desugar { finalizer) } } - desugared.withPos(tree.pos) + desugared.withSpan(tree.span) } /** Create a class definition with the same info as the refined type given by `parent` @@ -1364,7 +1369,7 @@ object desugar { elems foreach collect case Alternative(trees) => for (tree <- trees; (vble, _) <- getVariables(tree)) - ctx.error(IllegalVariableInPatternAlternative(), vble.pos) + ctx.error(IllegalVariableInPatternAlternative(), vble.sourcePos) case Annotated(arg, _) => collect(arg) case InterpolatedString(_, segments) => @@ -1388,5 +1393,6 @@ object desugar { buf.toList } - private class IrrefutableGenFrom(pat: Tree, expr: Tree) extends GenFrom(pat, expr) + private class IrrefutableGenFrom(pat: Tree, expr: Tree)(implicit @constructorOnly src: SourceFile) + extends GenFrom(pat, expr) } diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index 69b0bf780b75..6e280e892671 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -3,10 +3,10 @@ package dotc package ast import core._ -import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ +import util.Spans._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ import Symbols._, StdNames._, Trees._ import Decorators._ -import util.Property +import util.{Property, SourceFile} import typer.ErrorReporting._ import scala.annotation.internal.sharable @@ -44,7 +44,7 @@ object DesugarEnums { * It is an error if a type parameter is non-variant, or if its approximation * refers to pther type parameters. */ - def interpolatedEnumParent(pos: Position)(implicit ctx: Context): Tree = { + def interpolatedEnumParent(span: Span)(implicit ctx: Context): Tree = { val tparams = enumClass.typeParams def isGround(tp: Type) = tp.subst(tparams, tparams.map(_ => NoType)) eq tp val targs = tparams map { tparam => @@ -57,10 +57,10 @@ object DesugarEnums { if (tparam.variance == 0) "is non variant" else "has bounds that depend on a type parameter in the same parameter list" errorType(i"""cannot determine type argument for enum parent $enumClass, - |type parameter $tparam $problem""", pos) + |type parameter $tparam $problem""", ctx.source.atSpan(span)) } } - TypeTree(enumClass.typeRef.appliedTo(targs)).withPos(pos) + TypeTree(enumClass.typeRef.appliedTo(targs)).withSpan(span) } /** A type tree referring to `enumClass` */ @@ -73,7 +73,8 @@ object DesugarEnums { else if (isEnumCase(cdef)) cdef.withMods(cdef.mods.withFlags(cdef.mods.flags | Final)) else cdef - private def valuesDot(name: String) = Select(Ident(nme.DOLLAR_VALUES), name.toTermName) + private def valuesDot(name: String)(implicit src: SourceFile) = + Select(Ident(nme.DOLLAR_VALUES), name.toTermName) private def registerCall(implicit ctx: Context): List[Tree] = if (enumClass.typeParams.nonEmpty) Nil else Apply(valuesDot("register"), This(EmptyTypeIdent) :: Nil) :: Nil @@ -194,11 +195,11 @@ object DesugarEnums { } /** Expand a module definition representing a parameterless enum case */ - def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = { + def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, span: Span)(implicit ctx: Context): Tree = { assert(impl.body.isEmpty) if (!enumClass.exists) EmptyTree else if (impl.parents.isEmpty) - expandSimpleEnumCase(name, mods, pos) + expandSimpleEnumCase(name, mods, span) else { def toStringMeth = DefDef(nme.toString_, Nil, Nil, TypeTree(defn.StringType), Literal(Constant(name.toString))) @@ -206,22 +207,22 @@ object DesugarEnums { val (tagMeth, scaffolding) = enumTagMeth(CaseKind.Object) val impl1 = cpy.Template(impl)(body = List(tagMeth, toStringMeth) ++ registerCall) val vdef = ValDef(name, TypeTree(), New(impl1)).withMods(mods | Final) - flatTree(scaffolding ::: vdef :: Nil).withPos(pos) + flatTree(scaffolding ::: vdef :: Nil).withSpan(span) } } /** Expand a simple enum case */ - def expandSimpleEnumCase(name: TermName, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = + def expandSimpleEnumCase(name: TermName, mods: Modifiers, span: Span)(implicit ctx: Context): Tree = if (!enumClass.exists) EmptyTree else if (enumClass.typeParams.nonEmpty) { - val parent = interpolatedEnumParent(pos) + val parent = interpolatedEnumParent(span) val impl = Template(emptyConstructor, parent :: Nil, EmptyValDef, Nil) - expandEnumModule(name, impl, mods, pos) + expandEnumModule(name, impl, mods, span) } else { val (tag, scaffolding) = nextEnumTag(CaseKind.Simple) val creator = Apply(Ident(nme.DOLLAR_NEW), List(Literal(Constant(tag)), Literal(Constant(name.toString)))) val vdef = ValDef(name, enumClassRef, creator).withMods(mods | Final) - flatTree(scaffolding ::: vdef :: Nil).withPos(pos) + flatTree(scaffolding ::: vdef :: Nil).withSpan(span) } } diff --git a/compiler/src/dotty/tools/dotc/ast/NavigateAST.scala b/compiler/src/dotty/tools/dotc/ast/NavigateAST.scala index f180b34e3aa3..9fa11c8bf80d 100644 --- a/compiler/src/dotty/tools/dotc/ast/NavigateAST.scala +++ b/compiler/src/dotty/tools/dotc/ast/NavigateAST.scala @@ -3,10 +3,11 @@ package ast import core.Contexts.Context import core.Decorators._ -import util.Positions._ +import util.Spans._ import Trees.{MemberDef, DefTree, WithLazyField} /** Utility functions to go from typed to untyped ASTs */ +// TODO: Handle trees with mixed source files object NavigateAST { /** The untyped tree corresponding to typed tree `tree` in the compilation @@ -19,9 +20,9 @@ object NavigateAST { case _ => val loosePath = untypedPath(tree, exactMatch = false) throw new - Error(i"""no untyped tree for $tree, pos = ${tree.pos} + Error(i"""no untyped tree for $tree, pos = ${tree.sourcePos} |best matching path =\n$loosePath%\n====\n% - |path positions = ${loosePath.map(_.pos)}""") + |path positions = ${loosePath.map(_.sourcePos)}""") } /** The reverse path of untyped trees starting with a tree that closest matches @@ -39,39 +40,40 @@ object NavigateAST { def untypedPath(tree: tpd.Tree, exactMatch: Boolean = false)(implicit ctx: Context): List[Positioned] = tree match { case tree: MemberDef[_] => - untypedPath(tree.pos) match { + untypedPath(tree.span) match { case path @ (last: DefTree[_]) :: _ => path case path if !exactMatch => path case _ => Nil } case _ => - untypedPath(tree.pos) match { - case (path @ last :: _) if last.pos == tree.pos || !exactMatch => path + untypedPath(tree.span) match { + case (path @ last :: _) if last.span == tree.span || !exactMatch => path case _ => Nil } } /** The reverse part of the untyped root of the compilation unit of `ctx` to - * position `pos`. + * the given `span`. */ - def untypedPath(pos: Position)(implicit ctx: Context): List[Positioned] = - pathTo(pos, ctx.compilationUnit.untpdTree) + def untypedPath(span: Span)(implicit ctx: Context): List[Positioned] = + pathTo(span, ctx.compilationUnit.untpdTree) - /** The reverse path from node `from` to the node that closest encloses position `pos`, + /** The reverse path from node `from` to the node that closest encloses `span`, * or `Nil` if no such path exists. If a non-empty path is returned it starts with - * the node closest enclosing `pos` and ends with `from`. + * the node closest enclosing `span` and ends with `from`. * * @param skipZeroExtent If true, skip over zero-extent nodes in the search. These nodes * do not correspond to code the user wrote since their start and * end point are the same, so this is useful when trying to reconcile * nodes with source code. */ - def pathTo(pos: Position, from: Positioned, skipZeroExtent: Boolean = false)(implicit ctx: Context): List[Positioned] = { + def pathTo(span: Span, from: Positioned, skipZeroExtent: Boolean = false)(implicit ctx: Context): List[Positioned] = { def childPath(it: Iterator[Any], path: List[Positioned]): List[Positioned] = { while (it.hasNext) { val path1 = it.next() match { case p: Positioned => singlePath(p, path) + case m: untpd.Modifiers => childPath(m.productIterator, path) case xs: List[_] => childPath(xs.iterator, path) case _ => path } @@ -80,7 +82,7 @@ object NavigateAST { path } def singlePath(p: Positioned, path: List[Positioned]): List[Positioned] = - if (p.pos.exists && !(skipZeroExtent && p.pos.isZeroExtent) && p.pos.contains(pos)) { + if (p.span.exists && !(skipZeroExtent && p.span.isZeroExtent) && p.span.contains(span)) { // FIXME: We shouldn't be manually forcing trees here, we should replace // our usage of `productIterator` by something in `Positioned` that takes // care of low-level details like this for us. diff --git a/compiler/src/dotty/tools/dotc/ast/Positioned.scala b/compiler/src/dotty/tools/dotc/ast/Positioned.scala index 55144d460145..f764366302da 100644 --- a/compiler/src/dotty/tools/dotc/ast/Positioned.scala +++ b/compiler/src/dotty/tools/dotc/ast/Positioned.scala @@ -1,151 +1,135 @@ -package dotty.tools.dotc +package dotty.tools +package dotc package ast -import util.Positions._ +import util.Spans._ +import util.{SourceFile, NoSource, SourcePosition} import core.Contexts.Context import core.Decorators._ import core.Flags.{JavaDefined, Extension} import core.StdNames.nme +import annotation.constructorOnly +import annotation.internal.sharable /** A base class for things that have positions (currently: modifiers and trees) */ -abstract class Positioned extends Product { +abstract class Positioned(implicit @constructorOnly src: SourceFile) extends Product with Cloneable { - private[this] var curPos: Position = _ + private[this] var myUniqueId: Int = _ + private[this] var mySpan: Span = _ - setPos(initialPos) - - /** The item's position. + /** A unique identifier. Among other things, used for determining the source file + * component of the position. */ - def pos: Position = curPos + def uniqueId: Int = myUniqueId - /** Destructively update `curPos` to given position. Also, set any missing - * positions in children. - */ - protected def setPos(pos: Position): Unit = { - setPosUnchecked(pos) - if (pos.exists) setChildPositions(pos.toSynthetic) + def uniqueId_=(id: Int): Unit = { + //assert(id != 2523, this) + myUniqueId = id } - /** 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 - * destructively and the item itself is returned. - */ - def withPos(pos: Position): this.type = { - val newpd = (if (pos == curPos || curPos.isSynthetic) this else clone.asInstanceOf[Positioned]) - newpd.setPos(pos) - newpd.asInstanceOf[this.type] - } + /** The span part of the item's position */ + def span: Span = mySpan - def withPos(posd: Positioned): this.type = - if (posd == null) this else withPos(posd.pos) + def span_=(span: Span): Unit = { + mySpan = span + } - /** This item with a position that's the union of the given `pos` and the - * current position. - */ - def addPos(pos: Position): this.type = withPos(pos union this.pos) + uniqueId = src.nextId + span = envelope(src) - /** Set position of this tree only, without performing - * any checks of consistency with - or updates of - other positions. - * Called from Unpickler when entering positions. - */ - private[dotc] def setPosUnchecked(pos: Position): Unit = curPos = pos + def source: SourceFile = SourceFile.fromId(uniqueId) + def sourcePos(implicit ctx: Context): SourcePosition = source.atSpan(span) - /** If any children of this node do not have positions, - * fit their positions between the positions of the known subtrees - * and transitively visit their children. - * The method is likely time-critical because it is invoked on any node - * we create, so we want to avoid object allocations in the common case. - * The method is naturally expressed as two mutually (tail-)recursive - * functions, one which computes the next element to consider or terminates if there - * is none and the other which propagates the position information to that element. - * But since mutual tail recursion is not supported in Scala, we express it instead - * as a while loop with a termination by return in the middle. + /** A positioned item like this one with given `span`. + * If the positioned item is source-derived, a clone is returned. + * If the positioned item is synthetic, the position is updated + * destructively and the item itself is returned. */ - private def setChildPositions(pos: Position): Unit = { - var n = productArity // subnodes are analyzed right to left - var elems: List[Any] = Nil // children in lists still to be considered, from right to left - var end = pos.end // the last defined offset, fill in positions up to this offset - var outstanding: List[Positioned] = Nil // nodes that need their positions filled once a start position - // is known, from left to right. - def fillIn(ps: List[Positioned], start: Int, end: Int): Unit = ps match { - case p :: ps1 => - // If a tree has no position or a zero-extent position, it should be - // synthetic. We can preserve this invariant by always setting a - // zero-extent position for these trees here. - if (!p.pos.exists || p.pos.isZeroExtent) { - p.setPos(Position(start, start)) - fillIn(ps1, start, end) - } else { - p.setPos(Position(start, end)) - fillIn(ps1, end, end) + def withSpan(span: Span): this.type = + if (span == mySpan) this + else { + val newpd: this.type = + if (mySpan.isSynthetic) { + if (!mySpan.exists && span.exists) + envelope(source, span.startPos) // fill in children spans + this } - case nil => + else cloneIn(source) + newpd.span = span + newpd } - while (true) { - var nextChild: Any = null // the next child to be considered - if (elems.nonEmpty) { - nextChild = elems.head - elems = elems.tail - } - else if (n > 0) { - n = n - 1 - nextChild = productElement(n) - } - else { - fillIn(outstanding, pos.start, end) - return - } - nextChild match { - case p: Positioned => - if (p.pos.exists) { - fillIn(outstanding, p.pos.end, end) - outstanding = Nil - end = p.pos.start - } - else outstanding = p :: outstanding - case xs: List[_] => - elems = elems ::: xs.reverse - case _ => - } - } - } - /** The initial, synthetic position. This is usually the union of all positioned children's positions. + /** The union of startSpan and the spans of all positioned children that + * have the same source as this node, except that Inlined nodes only + * consider their `call` child. + * + * Side effect: Any descendants without spans have but with the same source as this + * node have their span set to the end position of the envelope of all children to + * the left, or, if that one does not exist, to the start position of the envelope + * of all children to the right. */ - def initialPos: Position = { - var n = productArity - var pos = NoPosition - while (n > 0) { - n -= 1 - productElement(n) match { - case p: Positioned => pos = pos union p.pos - case xs: List[_] => pos = unionPos(pos, xs) - case _ => + def envelope(src: SourceFile, startSpan: Span = NoSpan): Span = this match { + case Trees.Inlined(call, _, _) => + call.span + case _ => + def include(span: Span, x: Any): Span = x match { + case p: Positioned => + if (p.source != src) span + else if (p.span.exists) span.union(p.span) + else if (span.exists) { + if (span.end != MaxOffset) + p.span = p.envelope(src, span.endPos) + span + } + else // No span available to assign yet, signal this by returning a span with MaxOffset end + Span(MaxOffset, MaxOffset) + case m: untpd.Modifiers => + include(include(span, m.mods), m.annotations) + case y :: ys => + include(include(span, y), ys) + case _ => span } - } - pos.toSynthetic + val limit = productArity + def includeChildren(span: Span, n: Int): Span = + if (n < limit) includeChildren(include(span, productElement(n)), n + 1) + else span + val span1 = includeChildren(startSpan, 0) + val span2 = + if (!span1.exists || span1.end != MaxOffset) + span1 + else if (span1.start == MaxOffset) + // No positioned child was found + NoSpan + else { + ///println(s"revisit $uniqueId with $span1") + // We have some children left whose span could not be assigned. + // Go through it again with the known start position. + includeChildren(span1.startPos, 0) + } + span2.toSynthetic } - private def unionPos(pos: Position, xs: List[_]): Position = xs match { - case (p: Positioned) :: xs1 => unionPos(pos union p.pos, xs1) - case (xs0: List[_]) :: xs1 => unionPos(unionPos(pos, xs0), xs1) - case _ :: xs1 => unionPos(pos, xs1) - case _ => pos + /** Clone this node but assign it a fresh id which marks it as a node in `file`. */ + def cloneIn(src: SourceFile): this.type = { + val newpd: this.type = clone.asInstanceOf[this.type] + newpd.uniqueId = src.nextId + newpd } def contains(that: Positioned): Boolean = { def isParent(x: Any): Boolean = x match { case x: Positioned => - x contains that + x.contains(that) + case m: untpd.Modifiers => + m.mods.exists(isParent) || m.annotations.exists(isParent) case xs: List[_] => - xs exists isParent + xs.exists(isParent) case _ => false } (this eq that) || - (this.pos contains that.pos) && { + (this.span contains that.span) && { var n = productArity var found = false while (!found && n > 0) { @@ -157,24 +141,24 @@ abstract class Positioned extends Product { } /** Check that all positioned items in this tree satisfy the following conditions: - * - Parent positions contain child positions + * - Parent spans contain child spans * - If item is a non-empty tree, it has a position */ def checkPos(nonOverlapping: Boolean)(implicit ctx: Context): Unit = try { import untpd._ var lastPositioned: Positioned = null - var lastPos = NoPosition + var lastSpan = NoSpan def check(p: Any): Unit = p match { case p: Positioned => - assert(pos contains p.pos, - s"""position error, parent position does not contain child position - |parent = $this, - |parent position = $pos, - |child = $p, - |child position = ${p.pos}""".stripMargin) + assert(span contains p.span, + i"""position error, parent span does not contain child span + |parent = $this # $uniqueId, + |parent span = $span, + |child = $p # ${p.uniqueId}, + |child span = ${p.span}""".stripMargin) p match { case tree: Tree if !tree.isEmpty => - assert(tree.pos.exists, + assert(tree.span.exists, s"position error: position not set for $tree # ${tree.uniqueId}") case _ => } @@ -186,18 +170,21 @@ abstract class Positioned extends Product { if lastPositioned.isInstanceOf[ValDef] && !p.isInstanceOf[ValDef] => // ignore transition from last wildcard parameter to body case _ => - assert(!lastPos.exists || !p.pos.exists || lastPos.end <= p.pos.start, - s"""position error, child positions overlap or in wrong order - |parent = $this - |1st child = $lastPositioned - |1st child position = $lastPos - |2nd child = $p - |2nd child position = ${p.pos}""".stripMargin) + assert(!lastSpan.exists || !p.span.exists || lastSpan.end <= p.span.start, + i"""position error, child positions overlap or in wrong order + |parent = $this + |1st child = $lastPositioned + |1st child span = $lastSpan + |2nd child = $p + |2nd child span = ${p.span}""".stripMargin) } lastPositioned = p - lastPos = p.pos + lastSpan = p.span } p.checkPos(nonOverlapping) + case m: untpd.Modifiers => + m.annotations.foreach(check) + m.mods.foreach(check) case xs: List[_] => xs.foreach(check) case _ => diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 7db82df9e723..c6c70ceb3a05 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -500,11 +500,11 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => val tree1 = ConstFold(tree) tree1.tpe.widenTermRefExpr match { case ConstantType(value) => - if (isIdempotentExpr(tree1)) Literal(value) + if (isIdempotentExpr(tree1)) Literal(value).withSpan(tree.span) else tree1 match { case Select(qual, _) if tree1.tpe.isInstanceOf[ConstantType] => // it's a primitive unary operator; Simplify `pre.op` to `{ pre; v }` where `v` is the value of `pre.op` - Block(qual :: Nil, Literal(value)) + Block(qual :: Nil, Literal(value)).withSpan(tree.span) case _ => tree1 } @@ -555,7 +555,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => * apply of a function class? */ def isSyntheticApply(tree: Tree): Boolean = tree match { - case Select(qual, nme.apply) => tree.pos.end == qual.pos.end + case Select(qual, nme.apply) => tree.span.end == qual.span.end case _ => false } @@ -665,11 +665,11 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => * if no such path exists. * Pre: `sym` must have a position. */ - def defPath(sym: Symbol, root: Tree)(implicit ctx: Context): List[Tree] = trace.onDebug(s"defpath($sym with position ${sym.pos}, ${root.show})") { - require(sym.pos.exists) + def defPath(sym: Symbol, root: Tree)(implicit ctx: Context): List[Tree] = trace.onDebug(s"defpath($sym with position ${sym.span}, ${root.show})") { + require(sym.span.exists) object accum extends TreeAccumulator[List[Tree]] { def apply(x: List[Tree], tree: Tree)(implicit ctx: Context): List[Tree] = { - if (tree.pos.contains(sym.pos)) + if (tree.span.contains(sym.span)) if (definedSym(tree) == sym) tree :: x else { val x1 = foldOver(x, tree) @@ -718,7 +718,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => * tree must be reachable from come tree stored in an enclosing context. */ def definingStats(sym: Symbol)(implicit ctx: Context): List[Tree] = - if (!sym.pos.exists || (ctx eq NoContext) || ctx.compilationUnit == null) Nil + if (!sym.span.exists || (ctx eq NoContext) || ctx.compilationUnit == null) Nil else defPath(sym, ctx.compilationUnit.tpdTree) match { case defn :: encl :: _ => def verify(stats: List[Tree]) = diff --git a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala index 25269c17e863..43643465f762 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -89,7 +89,7 @@ class TreeTypeMap( case tree1 => tree1.withType(mapType(tree1.tpe)) match { case id: Ident if tpd.needsSelect(id.tpe) => - ref(id.tpe.asInstanceOf[TermRef]).withPos(id.pos) + ref(id.tpe.asInstanceOf[TermRef]).withSpan(id.span) case ddef @ DefDef(name, tparams, vparamss, tpt, _) => val (tmap1, tparams1) = transformDefs(ddef.tparams) val (tmap2, vparamss1) = tmap1.transformVParamss(vparamss) @@ -122,7 +122,7 @@ class TreeTypeMap( val expr1 = tmap.transform(expr) cpy.Labeled(labeled)(bind1, expr1) case Hole(n, args) => - Hole(n, args.mapConserve(transform)).withPos(tree.pos).withType(mapType(tree.tpe)) + Hole(n, args.mapConserve(transform)).withSpan(tree.span).withType(mapType(tree.tpe)) case tree1 => super.transform(tree1) } diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 603e95af29ef..af9415dca57d 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -3,16 +3,18 @@ package dotc package ast import core._ -import Types._, Names._, NameOps._, Flags._, util.Positions._, Contexts._, Constants._ +import Types._, Names._, NameOps._, Flags._, util.Spans._, Contexts._, Constants._ import SymDenotations._, Symbols._, Denotations._, StdNames._, Comments._ import language.higherKinds import collection.mutable.ListBuffer import printing.Printer import printing.Texts.Text -import util.{Stats, Attachment, Property} +import util.{Stats, Attachment, Property, SourceFile, NoSource, SourcePosition} import config.Config import annotation.internal.sharable import annotation.unchecked.uncheckedVariance +import annotation.constructorOnly +import Decorators._ object Trees { @@ -30,8 +32,6 @@ object Trees { /** Property key for trees with documentation strings attached */ val DocComment: Property.StickyKey[Comments.Comment] = new Property.StickyKey - @sharable private[this] var nextId = 0 // for debugging - type LazyTree = AnyRef /* really: Tree | Lazy[Tree] */ type LazyTreeList = AnyRef /* really: List[Tree] | Lazy[List[Tree]] */ @@ -51,26 +51,18 @@ object Trees { * - Type checking an untyped tree should remove all embedded `TypedSplice` * nodes. */ - abstract class Tree[-T >: Untyped] extends Positioned - with Product - with Attachment.Container - with printing.Showable - with Cloneable { + abstract class Tree[-T >: Untyped](implicit @constructorOnly src: SourceFile) + extends Positioned + with Product + with Attachment.Container + with printing.Showable { if (Stats.enabled) ntrees += 1 - private def nxId = { - nextId += 1 - //assert(nextId != 199, this) - nextId - } - - /** A unique identifier for this tree. Used for debugging, and potentially - * tracking presentation compiler interactions. + /** This tree, widened to `Positioned`. Used to make clear we only need the + * position, typically for error reporting. */ - @sharable private var myUniqueId: Int = nxId - - def uniqueId: Int = myUniqueId + final def posd: Positioned = this /** The type constructor at the root of the tree */ type ThisTree[T >: Untyped] <: Tree[T] @@ -97,7 +89,7 @@ object Trees { /** Copy `tpe` attribute from tree `from` into this tree, independently * whether it is null or not. final def copyAttr[U >: Untyped](from: Tree[U]): ThisTree[T] = { - val t1 = this.withPos(from.pos) + val t1 = this.withSpan(from.span) val t2 = if (from.myTpe != null) t1.withType(from.myTpe.asInstanceOf[Type]) else t1 @@ -141,7 +133,7 @@ object Trees { val tree = (if (myTpe == null || (myTpe.asInstanceOf[AnyRef] eq tpe.asInstanceOf[AnyRef])) this - else clone).asInstanceOf[Tree[Type]] + else cloneIn(source)).asInstanceOf[Tree[Type]] tree overwriteType tpe tree.asInstanceOf[ThisTree[Type]] } @@ -237,12 +229,6 @@ object Trees { override def hashCode(): Int = uniqueId // for debugging; was: System.identityHashCode(this) override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] - - override def clone: Tree[T] = { - val tree = super.clone.asInstanceOf[Tree[T]] - tree.myUniqueId = nxId - tree - } } class UnAssignedTypeException[T >: Untyped](tree: Tree[T]) extends RuntimeException { @@ -276,7 +262,7 @@ object Trees { } /** Tree's denotation can be derived from its type */ - abstract class DenotingTree[-T >: Untyped] extends Tree[T] { + abstract class DenotingTree[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends Tree[T] { type ThisTree[-T >: Untyped] <: DenotingTree[T] override def denot(implicit ctx: Context): Denotation = typeOpt match { case tpe: NamedType => tpe.denot @@ -293,7 +279,7 @@ object Trees { /** Tree's denot/isType/isTerm properties come from a subtree * identified by `forwardTo`. */ - abstract class ProxyTree[-T >: Untyped] extends Tree[T] { + abstract class ProxyTree[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends Tree[T] { type ThisTree[-T >: Untyped] <: ProxyTree[T] def forwardTo: Tree[T] override def denot(implicit ctx: Context): Denotation = forwardTo.denot @@ -302,13 +288,13 @@ object Trees { } /** Tree has a name */ - abstract class NameTree[-T >: Untyped] extends DenotingTree[T] { + abstract class NameTree[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends DenotingTree[T] { type ThisTree[-T >: Untyped] <: NameTree[T] def name: Name } /** Tree refers by name to a denotation */ - abstract class RefTree[-T >: Untyped] extends NameTree[T] { + abstract class RefTree[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends NameTree[T] { type ThisTree[-T >: Untyped] <: RefTree[T] def qualifier: Tree[T] override def isType: Boolean = name.isTypeName @@ -327,7 +313,7 @@ object Trees { * The envelope of a MemberDef contains the whole definition and has its point * on the opening keyword (or the next token after that if keyword is missing). */ - abstract class MemberDef[-T >: Untyped] extends NameTree[T] with DefTree[T] { + abstract class MemberDef[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends NameTree[T] with DefTree[T] { type ThisTree[-T >: Untyped] <: MemberDef[T] private[this] var myMods: untpd.Modifiers = null @@ -338,7 +324,7 @@ object Trees { def rawComment: Option[Comment] = getAttachment(DocComment) def withMods(mods: untpd.Modifiers): ThisTree[Untyped] = { - val tree = if (myMods == null || (myMods == mods)) this else clone.asInstanceOf[MemberDef[Untyped]] + val tree = if (myMods == null || (myMods == mods)) this else cloneIn(source) tree.setMods(mods) tree.asInstanceOf[ThisTree[Untyped]] } @@ -357,19 +343,19 @@ object Trees { * This is a point position if the definition is synthetic, or a range position * if the definition comes from source. * It might also be that the definition does not have a position (for instance when synthesized by - * a calling chain from `viewExists`), in that case the return position is NoPosition. + * a calling chain from `viewExists`), in that case the return position is NoSpan. */ - def namePos: Position = - if (pos.exists) { - val point = pos.point - if (rawMods.is(Synthetic) || name.toTermName == nme.ERROR) Position(point) - else Position(point, point + name.stripModuleClassSuffix.lastPart.length, point) + def nameSpan: Span = + if (span.exists) { + val point = span.point + if (rawMods.is(Synthetic) || name.toTermName == nme.ERROR) Span(point) + else Span(point, point + name.stripModuleClassSuffix.lastPart.length, point) } - else pos + else span } /** A ValDef or DefDef tree */ - trait ValOrDefDef[-T >: Untyped] extends MemberDef[T] with WithLazyField[Tree[T]] { + abstract class ValOrDefDef[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends MemberDef[T] with WithLazyField[Tree[T]] { def name: TermName def tpt: Tree[T] def unforcedRhs: LazyTree = unforced @@ -379,7 +365,7 @@ object Trees { // ----------- Tree case classes ------------------------------------ /** name */ - case class Ident[-T >: Untyped] private[ast] (name: Name) + case class Ident[-T >: Untyped] private[ast] (name: Name)(implicit @constructorOnly src: SourceFile) extends RefTree[T] { type ThisTree[-T >: Untyped] = Ident[T] def qualifier: Tree[T] = genericEmptyTree @@ -388,31 +374,31 @@ object Trees { def isBackquoted: Boolean = false } - class BackquotedIdent[-T >: Untyped] private[ast] (name: Name) + class BackquotedIdent[-T >: Untyped]private[ast] (name: Name)(implicit @constructorOnly src: SourceFile) extends Ident[T](name) { override def isBackquoted: Boolean = true override def toString: String = s"BackquotedIdent($name)" } - class SearchFailureIdent[-T >: Untyped] private[ast] (name: Name) + class SearchFailureIdent[-T >: Untyped] private[ast] (name: Name)(implicit @constructorOnly src: SourceFile) extends Ident[T](name) { override def toString: String = s"SearchFailureIdent($name)" } /** qualifier.name, or qualifier#name, if qualifier is a type */ - case class Select[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name) + case class Select[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name)(implicit @constructorOnly src: SourceFile) extends RefTree[T] { type ThisTree[-T >: Untyped] = Select[T] } - class SelectWithSig[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name, val sig: Signature) + class SelectWithSig[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name, val sig: Signature)(implicit @constructorOnly src: SourceFile) extends Select[T](qualifier, name) { override def toString: String = s"SelectWithSig($qualifier, $name, $sig)" } /** qual.this */ - case class This[-T >: Untyped] private[ast] (qual: untpd.Ident) + case class This[-T >: Untyped] private[ast] (qual: untpd.Ident)(implicit @constructorOnly src: SourceFile) 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. @@ -427,13 +413,13 @@ object Trees { } /** C.super[mix], where qual = C.this */ - case class Super[-T >: Untyped] private[ast] (qual: Tree[T], mix: untpd.Ident) + case class Super[-T >: Untyped] private[ast] (qual: Tree[T], mix: untpd.Ident)(implicit @constructorOnly src: SourceFile) extends ProxyTree[T] with TermTree[T] { type ThisTree[-T >: Untyped] = Super[T] def forwardTo: Tree[T] = qual } - abstract class GenericApply[-T >: Untyped] extends ProxyTree[T] with TermTree[T] { + abstract class GenericApply[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends ProxyTree[T] with TermTree[T] { type ThisTree[-T >: Untyped] <: GenericApply[T] val fun: Tree[T] val args: List[Tree[T]] @@ -441,50 +427,50 @@ object Trees { } /** fun(args) */ - case class Apply[-T >: Untyped] private[ast] (fun: Tree[T], args: List[Tree[T]]) + case class Apply[-T >: Untyped] private[ast] (fun: Tree[T], args: List[Tree[T]])(implicit @constructorOnly src: SourceFile) extends GenericApply[T] { type ThisTree[-T >: Untyped] = Apply[T] } /** fun[args] */ - case class TypeApply[-T >: Untyped] private[ast] (fun: Tree[T], args: List[Tree[T]]) + case class TypeApply[-T >: Untyped] private[ast] (fun: Tree[T], args: List[Tree[T]])(implicit @constructorOnly src: SourceFile) extends GenericApply[T] { type ThisTree[-T >: Untyped] = TypeApply[T] } /** const */ - case class Literal[-T >: Untyped] private[ast] (const: Constant) - extends TermTree[T] { + case class Literal[-T >: Untyped] private[ast] (const: Constant)(implicit @constructorOnly src: SourceFile) + extends Tree[T] with TermTree[T] { type ThisTree[-T >: Untyped] = Literal[T] } /** new tpt, but no constructor call */ - case class New[-T >: Untyped] private[ast] (tpt: Tree[T]) - extends TermTree[T] { + case class New[-T >: Untyped] private[ast] (tpt: Tree[T])(implicit @constructorOnly src: SourceFile) + extends Tree[T] with TermTree[T] { type ThisTree[-T >: Untyped] = New[T] } /** expr : tpt */ - case class Typed[-T >: Untyped] private[ast] (expr: Tree[T], tpt: Tree[T]) + case class Typed[-T >: Untyped] private[ast] (expr: Tree[T], tpt: Tree[T])(implicit @constructorOnly src: SourceFile) extends ProxyTree[T] with TermTree[T] { type ThisTree[-T >: Untyped] = Typed[T] def forwardTo: Tree[T] = expr } /** name = arg, in a parameter list */ - case class NamedArg[-T >: Untyped] private[ast] (name: Name, arg: Tree[T]) + case class NamedArg[-T >: Untyped] private[ast] (name: Name, arg: Tree[T])(implicit @constructorOnly src: SourceFile) extends Tree[T] { type ThisTree[-T >: Untyped] = NamedArg[T] } /** name = arg, outside a parameter list */ - case class Assign[-T >: Untyped] private[ast] (lhs: Tree[T], rhs: Tree[T]) + case class Assign[-T >: Untyped] private[ast] (lhs: Tree[T], rhs: Tree[T])(implicit @constructorOnly src: SourceFile) extends TermTree[T] { type ThisTree[-T >: Untyped] = Assign[T] } /** { stats; expr } */ - case class Block[-T >: Untyped] private[ast] (stats: List[Tree[T]], expr: Tree[T]) + case class Block[-T >: Untyped] private[ast] (stats: List[Tree[T]], expr: Tree[T])(implicit @constructorOnly src: SourceFile) extends Tree[T] { type ThisTree[-T >: Untyped] = Block[T] override def isType: Boolean = expr.isType @@ -492,12 +478,12 @@ object Trees { } /** if cond then thenp else elsep */ - case class If[-T >: Untyped] private[ast] (cond: Tree[T], thenp: Tree[T], elsep: Tree[T]) + case class If[-T >: Untyped] private[ast] (cond: Tree[T], thenp: Tree[T], elsep: Tree[T])(implicit @constructorOnly src: SourceFile) extends TermTree[T] { type ThisTree[-T >: Untyped] = If[T] def isInline = false } - class InlineIf[T >: Untyped] private[ast] (cond: Tree[T], thenp: Tree[T], elsep: Tree[T]) + class InlineIf[T >: Untyped] private[ast] (cond: Tree[T], thenp: Tree[T], elsep: Tree[T])(implicit @constructorOnly src: SourceFile) extends If(cond, thenp, elsep) { override def isInline = true override def toString = s"InlineIf($cond, $thenp, $elsep)" @@ -512,32 +498,32 @@ object Trees { * of the closure is a function type, otherwise it is the type * given in `tpt`, which must be a SAM type. */ - case class Closure[-T >: Untyped] private[ast] (env: List[Tree[T]], meth: Tree[T], tpt: Tree[T]) + case class Closure[-T >: Untyped] private[ast] (env: List[Tree[T]], meth: Tree[T], tpt: Tree[T])(implicit @constructorOnly src: SourceFile) extends TermTree[T] { type ThisTree[-T >: Untyped] = Closure[T] } /** selector match { cases } */ - case class Match[-T >: Untyped] private[ast] (selector: Tree[T], cases: List[CaseDef[T]]) + case class Match[-T >: Untyped] private[ast] (selector: Tree[T], cases: List[CaseDef[T]])(implicit @constructorOnly src: SourceFile) extends TermTree[T] { assert(cases.nonEmpty) type ThisTree[-T >: Untyped] = Match[T] def isInline = false } - class InlineMatch[T >: Untyped] private[ast] (selector: Tree[T], cases: List[CaseDef[T]]) + class InlineMatch[T >: Untyped] private[ast] (selector: Tree[T], cases: List[CaseDef[T]])(implicit @constructorOnly src: SourceFile) extends Match(selector, cases) { override def isInline = true override def toString = s"InlineMatch($selector, $cases)" } /** case pat if guard => body; only appears as child of a Match */ - case class CaseDef[-T >: Untyped] private[ast] (pat: Tree[T], guard: Tree[T], body: Tree[T]) + case class CaseDef[-T >: Untyped] private[ast] (pat: Tree[T], guard: Tree[T], body: Tree[T])(implicit @constructorOnly src: SourceFile) extends Tree[T] { type ThisTree[-T >: Untyped] = CaseDef[T] } /** label[tpt]: { expr } */ - case class Labeled[-T >: Untyped] private[ast] (bind: Bind[T], expr: Tree[T]) + case class Labeled[-T >: Untyped] private[ast] (bind: Bind[T], expr: Tree[T])(implicit @constructorOnly src: SourceFile) extends NameTree[T] { type ThisTree[-T >: Untyped] = Labeled[T] def name: Name = bind.name @@ -548,13 +534,13 @@ object Trees { * After program transformations this is not necessarily the enclosing method, because * closures can intervene. */ - case class Return[-T >: Untyped] private[ast] (expr: Tree[T], from: Tree[T] = genericEmptyTree) + case class Return[-T >: Untyped] private[ast] (expr: Tree[T], from: Tree[T] = genericEmptyTree)(implicit @constructorOnly src: SourceFile) extends TermTree[T] { type ThisTree[-T >: Untyped] = Return[T] } /** while (cond) { body } */ - case class WhileDo[-T >: Untyped] private[ast] (cond: Tree[T], body: Tree[T]) + case class WhileDo[-T >: Untyped] private[ast] (cond: Tree[T], body: Tree[T])(implicit @constructorOnly src: SourceFile) extends TermTree[T] { type ThisTree[-T >: Untyped] = WhileDo[T] } @@ -578,7 +564,7 @@ object Trees { * * Match(EmptyTree, $anonfun(x)>) */ - case class Try[-T >: Untyped] private[ast] (expr: Tree[T], cases: List[CaseDef[T]], finalizer: Tree[T]) + case class Try[-T >: Untyped] private[ast] (expr: Tree[T], cases: List[CaseDef[T]], finalizer: Tree[T])(implicit @constructorOnly src: SourceFile) extends TermTree[T] { type ThisTree[-T >: Untyped] = Try[T] } @@ -586,13 +572,13 @@ object Trees { /** Seq(elems) * @param tpt The element type of the sequence. */ - case class SeqLiteral[-T >: Untyped] private[ast] (elems: List[Tree[T]], elemtpt: Tree[T]) + case class SeqLiteral[-T >: Untyped] private[ast] (elems: List[Tree[T]], elemtpt: Tree[T])(implicit @constructorOnly src: SourceFile) extends Tree[T] { type ThisTree[-T >: Untyped] = SeqLiteral[T] } /** Array(elems) */ - class JavaSeqLiteral[T >: Untyped] private[ast] (elems: List[Tree[T]], elemtpt: Tree[T]) + class JavaSeqLiteral[T >: Untyped] private[ast] (elems: List[Tree[T]], elemtpt: Tree[T])(implicit @constructorOnly src: SourceFile) extends SeqLiteral(elems, elemtpt) { override def toString: String = s"JavaSeqLiteral($elems, $elemtpt)" } @@ -613,14 +599,13 @@ object Trees { * different context: `bindings` represent the arguments to the inlined * call, whereas `expansion` represents the body of the inlined function. */ - case class Inlined[-T >: Untyped] private[ast] (call: tpd.Tree, bindings: List[MemberDef[T]], expansion: Tree[T]) + case class Inlined[-T >: Untyped] private[ast] (call: tpd.Tree, bindings: List[MemberDef[T]], expansion: Tree[T])(implicit @constructorOnly src: SourceFile) extends Tree[T] { type ThisTree[-T >: Untyped] = Inlined[T] - override def initialPos: Position = call.pos } /** A type tree that represents an existing or inferred type */ - case class TypeTree[-T >: Untyped] () + case class TypeTree[-T >: Untyped]()(implicit @constructorOnly src: SourceFile) extends DenotingTree[T] with TypTree[T] { type ThisTree[-T >: Untyped] = TypeTree[T] override def isEmpty: Boolean = !hasType @@ -631,66 +616,66 @@ object Trees { /** A type tree that defines a new type variable. Its type is always a TypeVar. * Every TypeVar is created as the type of one TypeVarBinder. */ - class TypeVarBinder[-T >: Untyped] extends TypeTree[T] + class TypeVarBinder[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends TypeTree[T] /** ref.type */ - case class SingletonTypeTree[-T >: Untyped] private[ast] (ref: Tree[T]) + case class SingletonTypeTree[-T >: Untyped] private[ast] (ref: Tree[T])(implicit @constructorOnly src: SourceFile) extends DenotingTree[T] with TypTree[T] { type ThisTree[-T >: Untyped] = SingletonTypeTree[T] } /** left & right */ - case class AndTypeTree[-T >: Untyped] private[ast] (left: Tree[T], right: Tree[T]) + case class AndTypeTree[-T >: Untyped] private[ast] (left: Tree[T], right: Tree[T])(implicit @constructorOnly src: SourceFile) extends TypTree[T] { type ThisTree[-T >: Untyped] = AndTypeTree[T] } /** left | right */ - case class OrTypeTree[-T >: Untyped] private[ast] (left: Tree[T], right: Tree[T]) + case class OrTypeTree[-T >: Untyped] private[ast] (left: Tree[T], right: Tree[T])(implicit @constructorOnly src: SourceFile) extends TypTree[T] { type ThisTree[-T >: Untyped] = OrTypeTree[T] } /** tpt { refinements } */ - case class RefinedTypeTree[-T >: Untyped] private[ast] (tpt: Tree[T], refinements: List[Tree[T]]) + case class RefinedTypeTree[-T >: Untyped] private[ast] (tpt: Tree[T], refinements: List[Tree[T]])(implicit @constructorOnly src: SourceFile) extends ProxyTree[T] with TypTree[T] { type ThisTree[-T >: Untyped] = RefinedTypeTree[T] def forwardTo: Tree[T] = tpt } /** tpt[args] */ - case class AppliedTypeTree[-T >: Untyped] private[ast] (tpt: Tree[T], args: List[Tree[T]]) + case class AppliedTypeTree[-T >: Untyped] private[ast] (tpt: Tree[T], args: List[Tree[T]])(implicit @constructorOnly src: SourceFile) extends ProxyTree[T] with TypTree[T] { type ThisTree[-T >: Untyped] = AppliedTypeTree[T] def forwardTo: Tree[T] = tpt } /** [typeparams] -> tpt */ - case class LambdaTypeTree[-T >: Untyped] private[ast] (tparams: List[TypeDef[T]], body: Tree[T]) + case class LambdaTypeTree[-T >: Untyped] private[ast] (tparams: List[TypeDef[T]], body: Tree[T])(implicit @constructorOnly src: SourceFile) extends TypTree[T] { type ThisTree[-T >: Untyped] = LambdaTypeTree[T] } /** [bound] selector match { cases } */ - case class MatchTypeTree[-T >: Untyped] private[ast] (bound: Tree[T], selector: Tree[T], cases: List[CaseDef[T]]) + case class MatchTypeTree[-T >: Untyped] private[ast] (bound: Tree[T], selector: Tree[T], cases: List[CaseDef[T]])(implicit @constructorOnly src: SourceFile) extends TypTree[T] { type ThisTree[-T >: Untyped] = MatchTypeTree[T] } /** => T */ - case class ByNameTypeTree[-T >: Untyped] private[ast] (result: Tree[T]) + case class ByNameTypeTree[-T >: Untyped] private[ast] (result: Tree[T])(implicit @constructorOnly src: SourceFile) extends TypTree[T] { type ThisTree[-T >: Untyped] = ByNameTypeTree[T] } /** >: lo <: hi */ - case class TypeBoundsTree[-T >: Untyped] private[ast] (lo: Tree[T], hi: Tree[T]) + case class TypeBoundsTree[-T >: Untyped] private[ast] (lo: Tree[T], hi: Tree[T])(implicit @constructorOnly src: SourceFile) extends TypTree[T] { type ThisTree[-T >: Untyped] = TypeBoundsTree[T] } /** name @ body */ - case class Bind[-T >: Untyped] private[ast] (name: Name, body: Tree[T]) + case class Bind[-T >: Untyped] private[ast] (name: Name, body: Tree[T])(implicit @constructorOnly src: SourceFile) extends NameTree[T] with DefTree[T] with PatternTree[T] { type ThisTree[-T >: Untyped] = Bind[T] override def isType: Boolean = name.isTypeName @@ -698,7 +683,7 @@ object Trees { } /** tree_1 | ... | tree_n */ - case class Alternative[-T >: Untyped] private[ast] (trees: List[Tree[T]]) + case class Alternative[-T >: Untyped] private[ast] (trees: List[Tree[T]])(implicit @constructorOnly src: SourceFile) extends PatternTree[T] { type ThisTree[-T >: Untyped] = Alternative[T] } @@ -717,13 +702,13 @@ object Trees { * val result = fun(sel)(implicits) * if (result.isDefined) "match patterns against result" */ - case class UnApply[-T >: Untyped] private[ast] (fun: Tree[T], implicits: List[Tree[T]], patterns: List[Tree[T]]) + case class UnApply[-T >: Untyped] private[ast] (fun: Tree[T], implicits: List[Tree[T]], patterns: List[Tree[T]])(implicit @constructorOnly src: SourceFile) extends PatternTree[T] { type ThisTree[-T >: Untyped] = UnApply[T] } /** mods val name: tpt = rhs */ - case class ValDef[-T >: Untyped] private[ast] (name: TermName, tpt: Tree[T], private var preRhs: LazyTree) + case class ValDef[-T >: Untyped] private[ast] (name: TermName, tpt: Tree[T], private var preRhs: LazyTree)(implicit @constructorOnly src: SourceFile) extends ValOrDefDef[T] { type ThisTree[-T >: Untyped] = ValDef[T] assert(isEmpty || tpt != genericEmptyTree) @@ -733,7 +718,7 @@ object Trees { /** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */ case class DefDef[-T >: Untyped] private[ast] (name: TermName, tparams: List[TypeDef[T]], - vparamss: List[List[ValDef[T]]], tpt: Tree[T], private var preRhs: LazyTree) + vparamss: List[List[ValDef[T]]], tpt: Tree[T], private var preRhs: LazyTree)(implicit @constructorOnly src: SourceFile) extends ValOrDefDef[T] { type ThisTree[-T >: Untyped] = DefDef[T] assert(tpt != genericEmptyTree) @@ -746,7 +731,7 @@ object Trees { * mods type name = rhs or * mods type name >: lo <: hi, if rhs = TypeBoundsTree(lo, hi) & (lo ne hi) */ - case class TypeDef[-T >: Untyped] private[ast] (name: TypeName, rhs: Tree[T]) + case class TypeDef[-T >: Untyped] private[ast] (name: TypeName, rhs: Tree[T])(implicit @constructorOnly src: SourceFile) extends MemberDef[T] { type ThisTree[-T >: Untyped] = TypeDef[T] @@ -755,7 +740,7 @@ object Trees { } /** extends parents { self => body } */ - case class Template[-T >: Untyped] private[ast] (constr: DefDef[T], parents: List[Tree[T]], self: ValDef[T], private var preBody: LazyTreeList) + case class Template[-T >: Untyped] private[ast] (constr: DefDef[T], parents: List[Tree[T]], self: ValDef[T], private var preBody: LazyTreeList)(implicit @constructorOnly src: SourceFile) extends DefTree[T] with WithLazyField[List[Tree[T]]] { type ThisTree[-T >: Untyped] = Template[T] def unforcedBody: LazyTreeList = unforced @@ -768,20 +753,20 @@ object Trees { * where a selector is either an untyped `Ident`, `name` or * an untyped thicket consisting of `name` and `rename`. */ - case class Import[-T >: Untyped] private[ast] (expr: Tree[T], selectors: List[Tree[Untyped]]) + case class Import[-T >: Untyped] private[ast] (expr: Tree[T], selectors: List[Tree[Untyped]])(implicit @constructorOnly src: SourceFile) extends DenotingTree[T] { type ThisTree[-T >: Untyped] = Import[T] } /** package pid { stats } */ - case class PackageDef[-T >: Untyped] private[ast] (pid: RefTree[T], stats: List[Tree[T]]) + case class PackageDef[-T >: Untyped] private[ast] (pid: RefTree[T], stats: List[Tree[T]])(implicit @constructorOnly src: SourceFile) extends ProxyTree[T] { type ThisTree[-T >: Untyped] = PackageDef[T] def forwardTo: RefTree[T] = pid } /** arg @annot */ - case class Annotated[-T >: Untyped] private[ast] (arg: Tree[T], annot: Tree[T]) + case class Annotated[-T >: Untyped] private[ast] (arg: Tree[T], annot: Tree[T])(implicit @constructorOnly src: SourceFile) extends ProxyTree[T] { type ThisTree[-T >: Untyped] = Annotated[T] def forwardTo: Tree[T] = arg @@ -789,8 +774,8 @@ object Trees { trait WithoutTypeOrPos[-T >: Untyped] extends Tree[T] { override def withTypeUnchecked(tpe: Type): ThisTree[Type] = this.asInstanceOf[ThisTree[Type]] - override def pos: Position = NoPosition - override def setPos(pos: Position): Unit = {} + override def span: Span = NoSpan + override def span_=(span: Span): Unit = {} } /** Temporary class that results from translation of ModuleDefs @@ -798,34 +783,43 @@ object Trees { * The contained trees will be integrated when transformed with * a `transform(List[Tree])` call. */ - case class Thicket[-T >: Untyped](trees: List[Tree[T]]) + case class Thicket[-T >: Untyped](trees: List[Tree[T]])(implicit @constructorOnly src: SourceFile) extends Tree[T] with WithoutTypeOrPos[T] { myTpe = NoType.asInstanceOf[T] - type ThisTree[-T >: Untyped] = Thicket[T] - override def isEmpty: Boolean = trees.isEmpty - override def toList: List[Tree[T]] = flatten(trees) - override def toString: String = if (isEmpty) "EmptyTree" else "Thicket(" + trees.mkString(", ") + ")" - override def withPos(pos: Position): this.type = { - val newTrees = trees.mapConserve(_.withPos(pos)) + + def mapElems(op: Tree[T] => Tree[T] @uncheckedVariance): Thicket[T] = { + val newTrees = trees.mapConserve(op) if (trees eq newTrees) this else - new Thicket[T](newTrees).asInstanceOf[this.type] + Thicket[T](newTrees)(source).asInstanceOf[this.type] } - override def pos: Position = (NoPosition /: trees) ((pos, t) => pos union t.pos) + override def foreachInThicket(op: Tree[T] => Unit): Unit = trees foreach (_.foreachInThicket(op)) + + override def isEmpty: Boolean = trees.isEmpty + override def toList: List[Tree[T]] = flatten(trees) + override def toString: String = if (isEmpty) "EmptyTree" else "Thicket(" + trees.mkString(", ") + ")" + override def span: Span = (NoSpan /: trees) ((span, t) => span union t.span) + + override def withSpan(span: Span): this.type = + mapElems(_.withSpan(span)).asInstanceOf[this.type] + } + + class EmptyTree[T >: Untyped] extends Thicket(Nil)(NoSource) { + // assert(uniqueId != 1492) } class EmptyValDef[T >: Untyped] extends ValDef[T]( - nme.WILDCARD, genericEmptyTree[T], genericEmptyTree[T]) with WithoutTypeOrPos[T] { + nme.WILDCARD, genericEmptyTree[T], genericEmptyTree[T])(NoSource) with WithoutTypeOrPos[T] { myTpe = NoType.asInstanceOf[T] override def isEmpty: Boolean = true setMods(untpd.Modifiers(PrivateLocal)) } - @sharable val theEmptyTree: Thicket[Type] = Thicket(Nil) + @sharable val theEmptyTree: EmptyTree[Type] = new EmptyTree[Type] @sharable val theEmptyValDef: EmptyValDef[Type] = new EmptyValDef[Type] def genericEmptyValDef[T >: Untyped]: ValDef[T] = theEmptyValDef.asInstanceOf[ValDef[T]] @@ -950,15 +944,15 @@ object Trees { @sharable val EmptyTree: Thicket = genericEmptyTree @sharable val EmptyValDef: ValDef = genericEmptyValDef - @sharable val ImplicitEmptyTree: Thicket = Thicket(Nil) // an empty tree marking an implicit closure + @sharable val ImplicitEmptyTree: Thicket = new EmptyTree // an empty tree marking an implicit closure // ----- Auxiliary creation methods ------------------ - def Thicket(trees: List[Tree]): Thicket = new Thicket(trees) + def Thicket(trees: List[Tree])(implicit src: SourceFile): Thicket = new Thicket(trees) def Thicket(): Thicket = EmptyTree - def Thicket(x1: Tree, x2: Tree): Thicket = Thicket(x1 :: x2 :: Nil) - def Thicket(x1: Tree, x2: Tree, x3: Tree): Thicket = Thicket(x1 :: x2 :: x3 :: Nil) - def flatTree(xs: List[Tree]): Tree = flatten(xs) match { + def Thicket(x1: Tree, x2: Tree)(implicit src: SourceFile): Thicket = Thicket(x1 :: x2 :: Nil) + def Thicket(x1: Tree, x2: Tree, x3: Tree)(implicit src: SourceFile): Thicket = Thicket(x1 :: x2 :: x3 :: Nil) + def flatTree(xs: List[Tree])(implicit src: SourceFile): Tree = flatten(xs) match { case x :: Nil => x case ys => Thicket(ys) } @@ -979,194 +973,195 @@ object Trees { protected def postProcess(tree: Tree, copied: untpd.MemberDef): copied.ThisTree[T] protected def finalize(tree: Tree, copied: untpd.Tree): copied.ThisTree[T] = - postProcess(tree, copied.withPos(tree.pos).withAttachmentsFrom(tree)) + postProcess(tree, copied.withSpan(tree.span).withAttachmentsFrom(tree)) protected def finalize(tree: Tree, copied: untpd.MemberDef): copied.ThisTree[T] = - postProcess(tree, copied.withPos(tree.pos).withAttachmentsFrom(tree)) + postProcess(tree, copied.withSpan(tree.span).withAttachmentsFrom(tree)) - def Ident(tree: Tree)(name: Name): Ident = tree match { + def Ident(tree: Tree)(name: Name)(implicit ctx: Context): Ident = tree match { case tree: BackquotedIdent => if (name == tree.name) tree - else finalize(tree, new BackquotedIdent(name)) + else finalize(tree, new BackquotedIdent(name)(tree.source)) case tree: Ident if name == tree.name => tree - case _ => finalize(tree, untpd.Ident(name)) + case _ => finalize(tree, untpd.Ident(name)(tree.source)) } def Select(tree: Tree)(qualifier: Tree, name: Name)(implicit ctx: Context): Select = tree match { case tree: SelectWithSig => if ((qualifier eq tree.qualifier) && (name == tree.name)) tree - else finalize(tree, new SelectWithSig(qualifier, name, tree.sig)) + else finalize(tree, new SelectWithSig(qualifier, name, tree.sig)(tree.source)) case tree: Select if (qualifier eq tree.qualifier) && (name == tree.name) => tree - case _ => finalize(tree, untpd.Select(qualifier, name)) + case _ => finalize(tree, untpd.Select(qualifier, name)(tree.source)) } /** Copy Ident or Select trees */ def Ref(tree: RefTree)(name: Name)(implicit ctx: Context): RefTree = tree match { case Ident(_) => Ident(tree)(name) case Select(qual, _) => Select(tree)(qual, name) } - def This(tree: Tree)(qual: untpd.Ident): This = tree match { + def This(tree: Tree)(qual: untpd.Ident)(implicit ctx: Context): This = tree match { case tree: This if qual eq tree.qual => tree - case _ => finalize(tree, untpd.This(qual)) + case _ => finalize(tree, untpd.This(qual)(tree.source)) } - def Super(tree: Tree)(qual: Tree, mix: untpd.Ident): Super = tree match { + def Super(tree: Tree)(qual: Tree, mix: untpd.Ident)(implicit ctx: Context): Super = tree match { case tree: Super if (qual eq tree.qual) && (mix eq tree.mix) => tree - case _ => finalize(tree, untpd.Super(qual, mix)) + case _ => finalize(tree, untpd.Super(qual, mix)(tree.source)) } def Apply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): Apply = tree match { case tree: Apply if (fun eq tree.fun) && (args eq tree.args) => tree - case _ => finalize(tree, untpd.Apply(fun, args)) + case _ => finalize(tree, untpd.Apply(fun, args)(tree.source)) } def TypeApply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = tree match { case tree: TypeApply if (fun eq tree.fun) && (args eq tree.args) => tree - case _ => finalize(tree, untpd.TypeApply(fun, args)) + case _ => finalize(tree, untpd.TypeApply(fun, args)(tree.source)) } def Literal(tree: Tree)(const: Constant)(implicit ctx: Context): Literal = tree match { case tree: Literal if const == tree.const => tree - case _ => finalize(tree, untpd.Literal(const)) + case _ => finalize(tree, untpd.Literal(const)(tree.source)) } def New(tree: Tree)(tpt: Tree)(implicit ctx: Context): New = tree match { case tree: New if tpt eq tree.tpt => tree - case _ => finalize(tree, untpd.New(tpt)) + case _ => finalize(tree, untpd.New(tpt)(tree.source)) } def Typed(tree: Tree)(expr: Tree, tpt: Tree)(implicit ctx: Context): Typed = tree match { case tree: Typed if (expr eq tree.expr) && (tpt eq tree.tpt) => tree - case _ => finalize(tree, untpd.Typed(expr, tpt)) + case tree => finalize(tree, untpd.Typed(expr, tpt)(tree.source)) + //.ensuring(res => res.uniqueId != 1471, s"source = $tree, ${tree.uniqueId}") } def NamedArg(tree: Tree)(name: Name, arg: Tree)(implicit ctx: Context): NamedArg = tree match { case tree: NamedArg if (name == tree.name) && (arg eq tree.arg) => tree - case _ => finalize(tree, untpd.NamedArg(name, arg)) + case _ => finalize(tree, untpd.NamedArg(name, arg)(tree.source)) } def Assign(tree: Tree)(lhs: Tree, rhs: Tree)(implicit ctx: Context): Assign = tree match { case tree: Assign if (lhs eq tree.lhs) && (rhs eq tree.rhs) => tree - case _ => finalize(tree, untpd.Assign(lhs, rhs)) + case _ => finalize(tree, untpd.Assign(lhs, rhs)(tree.source)) } def Block(tree: Tree)(stats: List[Tree], expr: Tree)(implicit ctx: Context): Block = tree match { case tree: Block if (stats eq tree.stats) && (expr eq tree.expr) => tree - case _ => finalize(tree, untpd.Block(stats, expr)) + case _ => finalize(tree, untpd.Block(stats, expr)(tree.source)) } def If(tree: Tree)(cond: Tree, thenp: Tree, elsep: Tree)(implicit ctx: Context): If = tree match { case tree: If if (cond eq tree.cond) && (thenp eq tree.thenp) && (elsep eq tree.elsep) => tree - case tree: InlineIf => finalize(tree, untpd.InlineIf(cond, thenp, elsep)) - case _ => finalize(tree, untpd.If(cond, thenp, elsep)) + case tree: InlineIf => finalize(tree, untpd.InlineIf(cond, thenp, elsep)(tree.source)) + case _ => finalize(tree, untpd.If(cond, thenp, elsep)(tree.source)) } def Closure(tree: Tree)(env: List[Tree], meth: Tree, tpt: Tree)(implicit ctx: Context): Closure = tree match { case tree: Closure if (env eq tree.env) && (meth eq tree.meth) && (tpt eq tree.tpt) => tree - case _ => finalize(tree, untpd.Closure(env, meth, tpt)) + case _ => finalize(tree, untpd.Closure(env, meth, tpt)(tree.source)) } def Match(tree: Tree)(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = tree match { case tree: Match if (selector eq tree.selector) && (cases eq tree.cases) => tree - case tree: InlineMatch => finalize(tree, untpd.InlineMatch(selector, cases)) - case _ => finalize(tree, untpd.Match(selector, cases)) + case tree: InlineMatch => finalize(tree, untpd.InlineMatch(selector, cases)(tree.source)) + case _ => finalize(tree, untpd.Match(selector, cases)(tree.source)) } def CaseDef(tree: Tree)(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef = tree match { case tree: CaseDef if (pat eq tree.pat) && (guard eq tree.guard) && (body eq tree.body) => tree - case _ => finalize(tree, untpd.CaseDef(pat, guard, body)) + case _ => finalize(tree, untpd.CaseDef(pat, guard, body)(tree.source)) } def Labeled(tree: Tree)(bind: Bind, expr: Tree)(implicit ctx: Context): Labeled = tree match { case tree: Labeled if (bind eq tree.bind) && (expr eq tree.expr) => tree - case _ => finalize(tree, untpd.Labeled(bind, expr)) + case _ => finalize(tree, untpd.Labeled(bind, expr)(tree.source)) } def Return(tree: Tree)(expr: Tree, from: Tree)(implicit ctx: Context): Return = tree match { case tree: Return if (expr eq tree.expr) && (from eq tree.from) => tree - case _ => finalize(tree, untpd.Return(expr, from)) + case _ => finalize(tree, untpd.Return(expr, from)(tree.source)) } def WhileDo(tree: Tree)(cond: Tree, body: Tree)(implicit ctx: Context): WhileDo = tree match { case tree: WhileDo if (cond eq tree.cond) && (body eq tree.body) => tree - case _ => finalize(tree, untpd.WhileDo(cond, body)) + case _ => finalize(tree, untpd.WhileDo(cond, body)(tree.source)) } def Try(tree: Tree)(expr: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = tree match { case tree: Try if (expr eq tree.expr) && (cases eq tree.cases) && (finalizer eq tree.finalizer) => tree - case _ => finalize(tree, untpd.Try(expr, cases, finalizer)) + case _ => finalize(tree, untpd.Try(expr, cases, finalizer)(tree.source)) } def SeqLiteral(tree: Tree)(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): SeqLiteral = tree match { case tree: JavaSeqLiteral => if ((elems eq tree.elems) && (elemtpt eq tree.elemtpt)) tree else finalize(tree, new JavaSeqLiteral(elems, elemtpt)) case tree: SeqLiteral if (elems eq tree.elems) && (elemtpt eq tree.elemtpt) => tree - case _ => finalize(tree, untpd.SeqLiteral(elems, elemtpt)) + case _ => finalize(tree, untpd.SeqLiteral(elems, elemtpt)(tree.source)) } def Inlined(tree: Tree)(call: tpd.Tree, bindings: List[MemberDef], expansion: Tree)(implicit ctx: Context): Inlined = tree match { case tree: Inlined if (call eq tree.call) && (bindings eq tree.bindings) && (expansion eq tree.expansion) => tree - case _ => finalize(tree, untpd.Inlined(call, bindings, expansion)) + case _ => finalize(tree, untpd.Inlined(call, bindings, expansion)(tree.source)) } - def SingletonTypeTree(tree: Tree)(ref: Tree): SingletonTypeTree = tree match { + def SingletonTypeTree(tree: Tree)(ref: Tree)(implicit ctx: Context): SingletonTypeTree = tree match { case tree: SingletonTypeTree if ref eq tree.ref => tree - case _ => finalize(tree, untpd.SingletonTypeTree(ref)) + case _ => finalize(tree, untpd.SingletonTypeTree(ref)(tree.source)) } - def AndTypeTree(tree: Tree)(left: Tree, right: Tree): AndTypeTree = tree match { + def AndTypeTree(tree: Tree)(left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = tree match { case tree: AndTypeTree if (left eq tree.left) && (right eq tree.right) => tree - case _ => finalize(tree, untpd.AndTypeTree(left, right)) + case _ => finalize(tree, untpd.AndTypeTree(left, right)(tree.source)) } - def OrTypeTree(tree: Tree)(left: Tree, right: Tree): OrTypeTree = tree match { + def OrTypeTree(tree: Tree)(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = tree match { case tree: OrTypeTree if (left eq tree.left) && (right eq tree.right) => tree - case _ => finalize(tree, untpd.OrTypeTree(left, right)) + case _ => finalize(tree, untpd.OrTypeTree(left, right)(tree.source)) } - def RefinedTypeTree(tree: Tree)(tpt: Tree, refinements: List[Tree]): RefinedTypeTree = tree match { + def RefinedTypeTree(tree: Tree)(tpt: Tree, refinements: List[Tree])(implicit ctx: Context): RefinedTypeTree = tree match { case tree: RefinedTypeTree if (tpt eq tree.tpt) && (refinements eq tree.refinements) => tree - case _ => finalize(tree, untpd.RefinedTypeTree(tpt, refinements)) + case _ => finalize(tree, untpd.RefinedTypeTree(tpt, refinements)(tree.source)) } - def AppliedTypeTree(tree: Tree)(tpt: Tree, args: List[Tree]): AppliedTypeTree = tree match { + def AppliedTypeTree(tree: Tree)(tpt: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = tree match { case tree: AppliedTypeTree if (tpt eq tree.tpt) && (args eq tree.args) => tree - case _ => finalize(tree, untpd.AppliedTypeTree(tpt, args)) + case _ => finalize(tree, untpd.AppliedTypeTree(tpt, args)(tree.source)) } - def LambdaTypeTree(tree: Tree)(tparams: List[TypeDef], body: Tree): LambdaTypeTree = tree match { + def LambdaTypeTree(tree: Tree)(tparams: List[TypeDef], body: Tree)(implicit ctx: Context): LambdaTypeTree = tree match { case tree: LambdaTypeTree if (tparams eq tree.tparams) && (body eq tree.body) => tree - case _ => finalize(tree, untpd.LambdaTypeTree(tparams, body)) + case _ => finalize(tree, untpd.LambdaTypeTree(tparams, body)(tree.source)) } - def MatchTypeTree(tree: Tree)(bound: Tree, selector: Tree, cases: List[CaseDef]): MatchTypeTree = tree match { + def MatchTypeTree(tree: Tree)(bound: Tree, selector: Tree, cases: List[CaseDef])(implicit ctx: Context): MatchTypeTree = tree match { case tree: MatchTypeTree if (bound eq tree.bound) && (selector eq tree.selector) && (cases eq tree.cases) => tree - case _ => finalize(tree, untpd.MatchTypeTree(bound, selector, cases)) + case _ => finalize(tree, untpd.MatchTypeTree(bound, selector, cases)(tree.source)) } - def ByNameTypeTree(tree: Tree)(result: Tree): ByNameTypeTree = tree match { + def ByNameTypeTree(tree: Tree)(result: Tree)(implicit ctx: Context): ByNameTypeTree = tree match { case tree: ByNameTypeTree if result eq tree.result => tree - case _ => finalize(tree, untpd.ByNameTypeTree(result)) + case _ => finalize(tree, untpd.ByNameTypeTree(result)(tree.source)) } - def TypeBoundsTree(tree: Tree)(lo: Tree, hi: Tree): TypeBoundsTree = tree match { + def TypeBoundsTree(tree: Tree)(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = tree match { case tree: TypeBoundsTree if (lo eq tree.lo) && (hi eq tree.hi) => tree - case _ => finalize(tree, untpd.TypeBoundsTree(lo, hi)) + case _ => finalize(tree, untpd.TypeBoundsTree(lo, hi)(tree.source)) } - def Bind(tree: Tree)(name: Name, body: Tree): Bind = tree match { + def Bind(tree: Tree)(name: Name, body: Tree)(implicit ctx: Context): Bind = tree match { case tree: Bind if (name eq tree.name) && (body eq tree.body) => tree - case _ => finalize(tree, untpd.Bind(name, body)) + case _ => finalize(tree, untpd.Bind(name, body)(tree.source)) } - def Alternative(tree: Tree)(trees: List[Tree]): Alternative = tree match { + def Alternative(tree: Tree)(trees: List[Tree])(implicit ctx: Context): Alternative = tree match { case tree: Alternative if trees eq tree.trees => tree - case _ => finalize(tree, untpd.Alternative(trees)) + case _ => finalize(tree, untpd.Alternative(trees)(tree.source)) } - def UnApply(tree: Tree)(fun: Tree, implicits: List[Tree], patterns: List[Tree]): UnApply = tree match { + def UnApply(tree: Tree)(fun: Tree, implicits: List[Tree], patterns: List[Tree])(implicit ctx: Context): UnApply = tree match { case tree: UnApply if (fun eq tree.fun) && (implicits eq tree.implicits) && (patterns eq tree.patterns) => tree - case _ => finalize(tree, untpd.UnApply(fun, implicits, patterns)) + case _ => finalize(tree, untpd.UnApply(fun, implicits, patterns)(tree.source)) } - def ValDef(tree: Tree)(name: TermName, tpt: Tree, rhs: LazyTree): ValDef = tree match { + def ValDef(tree: Tree)(name: TermName, tpt: Tree, rhs: LazyTree)(implicit ctx: Context): ValDef = tree match { case tree: ValDef if (name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree - case _ => finalize(tree, untpd.ValDef(name, tpt, rhs)) + case _ => finalize(tree, untpd.ValDef(name, tpt, rhs)(tree.source)) } - def DefDef(tree: Tree)(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree): DefDef = tree match { + def DefDef(tree: Tree)(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(implicit ctx: Context): DefDef = tree match { case tree: DefDef if (name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree - case _ => finalize(tree, untpd.DefDef(name, tparams, vparamss, tpt, rhs)) + case _ => finalize(tree, untpd.DefDef(name, tparams, vparamss, tpt, rhs)(tree.source)) } - def TypeDef(tree: Tree)(name: TypeName, rhs: Tree): TypeDef = tree match { + def TypeDef(tree: Tree)(name: TypeName, rhs: Tree)(implicit ctx: Context): TypeDef = tree match { case tree: TypeDef if (name == tree.name) && (rhs eq tree.rhs) => tree - case _ => finalize(tree, untpd.TypeDef(name, rhs)) + case _ => finalize(tree, untpd.TypeDef(name, rhs)(tree.source)) } - def Template(tree: Tree)(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList): Template = tree match { + def Template(tree: Tree)(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList)(implicit ctx: Context): Template = tree match { case tree: Template if (constr eq tree.constr) && (parents eq tree.parents) && (self eq tree.self) && (body eq tree.unforcedBody) => tree - case _ => finalize(tree, untpd.Template(constr, parents, self, body)) + case _ => finalize(tree, untpd.Template(constr, parents, self, body)(tree.source)) } - def Import(tree: Tree)(expr: Tree, selectors: List[untpd.Tree]): Import = tree match { + def Import(tree: Tree)(expr: Tree, selectors: List[untpd.Tree])(implicit ctx: Context): Import = tree match { case tree: Import if (expr eq tree.expr) && (selectors eq tree.selectors) => tree - case _ => finalize(tree, untpd.Import(expr, selectors)) + case _ => finalize(tree, untpd.Import(expr, selectors)(tree.source)) } - def PackageDef(tree: Tree)(pid: RefTree, stats: List[Tree]): PackageDef = tree match { + def PackageDef(tree: Tree)(pid: RefTree, stats: List[Tree])(implicit ctx: Context): PackageDef = tree match { case tree: PackageDef if (pid eq tree.pid) && (stats eq tree.stats) => tree - case _ => finalize(tree, untpd.PackageDef(pid, stats)) + case _ => finalize(tree, untpd.PackageDef(pid, stats)(tree.source)) } def Annotated(tree: Tree)(arg: Tree, annot: Tree)(implicit ctx: Context): Annotated = tree match { case tree: Annotated if (arg eq tree.arg) && (annot eq tree.annot) => tree - case _ => finalize(tree, untpd.Annotated(arg, annot)) + case _ => finalize(tree, untpd.Annotated(arg, annot)(tree.source)) } - def Thicket(tree: Tree)(trees: List[Tree]): Thicket = tree match { + def Thicket(tree: Tree)(trees: List[Tree])(implicit ctx: Context): Thicket = tree match { case tree: Thicket if trees eq tree.trees => tree - case _ => finalize(tree, untpd.Thicket(trees)) + case _ => finalize(tree, untpd.Thicket(trees)(tree.source)) } // Copier methods with default arguments; these demand that the original tree @@ -1179,15 +1174,15 @@ object Trees { CaseDef(tree: Tree)(pat, guard, body) def Try(tree: Try)(expr: Tree = tree.expr, cases: List[CaseDef] = tree.cases, finalizer: Tree = tree.finalizer)(implicit ctx: Context): Try = Try(tree: Tree)(expr, cases, finalizer) - def UnApply(tree: UnApply)(fun: Tree = tree.fun, implicits: List[Tree] = tree.implicits, patterns: List[Tree] = tree.patterns): UnApply = + def UnApply(tree: UnApply)(fun: Tree = tree.fun, implicits: List[Tree] = tree.implicits, patterns: List[Tree] = tree.patterns)(implicit ctx: Context): UnApply = UnApply(tree: Tree)(fun, implicits, patterns) - def ValDef(tree: ValDef)(name: TermName = tree.name, tpt: Tree = tree.tpt, rhs: LazyTree = tree.unforcedRhs): ValDef = + def ValDef(tree: ValDef)(name: TermName = tree.name, tpt: Tree = tree.tpt, rhs: LazyTree = tree.unforcedRhs)(implicit ctx: Context): ValDef = ValDef(tree: Tree)(name, tpt, rhs) - def DefDef(tree: DefDef)(name: TermName = tree.name, tparams: List[TypeDef] = tree.tparams, vparamss: List[List[ValDef]] = tree.vparamss, tpt: Tree = tree.tpt, rhs: LazyTree = tree.unforcedRhs): DefDef = + def DefDef(tree: DefDef)(name: TermName = tree.name, tparams: List[TypeDef] = tree.tparams, vparamss: List[List[ValDef]] = tree.vparamss, tpt: Tree = tree.tpt, rhs: LazyTree = tree.unforcedRhs)(implicit ctx: Context): DefDef = DefDef(tree: Tree)(name, tparams, vparamss, tpt, rhs) - def TypeDef(tree: TypeDef)(name: TypeName = tree.name, rhs: Tree = tree.rhs): TypeDef = + def TypeDef(tree: TypeDef)(name: TypeName = tree.name, rhs: Tree = tree.rhs)(implicit ctx: Context): TypeDef = TypeDef(tree: Tree)(name, rhs) - def Template(tree: Template)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody): Template = + def Template(tree: Template)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody)(implicit ctx: Context): Template = Template(tree: Tree)(constr, parents, self, body) } @@ -1203,112 +1198,114 @@ object Trees { abstract class TreeMap(val cpy: TreeCopier = inst.cpy) { self => - def transform(tree: Tree)(implicit ctx: Context): Tree = { - Stats.record(s"TreeMap.transform $getClass") - Stats.record("TreeMap.transform total") - def localCtx = - if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx - - if (skipTransform(tree)) tree - else tree match { - case Ident(name) => - tree - case Select(qualifier, name) => - cpy.Select(tree)(transform(qualifier), name) - case This(qual) => - tree - case Super(qual, mix) => - cpy.Super(tree)(transform(qual), mix) - case Apply(fun, args) => - cpy.Apply(tree)(transform(fun), transform(args)) - case TypeApply(fun, args) => - cpy.TypeApply(tree)(transform(fun), transform(args)) - case Literal(const) => - tree - case New(tpt) => - cpy.New(tree)(transform(tpt)) - case Typed(expr, tpt) => - cpy.Typed(tree)(transform(expr), transform(tpt)) - case NamedArg(name, arg) => - cpy.NamedArg(tree)(name, transform(arg)) - case Assign(lhs, rhs) => - cpy.Assign(tree)(transform(lhs), transform(rhs)) - case Block(stats, expr) => - cpy.Block(tree)(transformStats(stats), transform(expr)) - case If(cond, thenp, elsep) => - cpy.If(tree)(transform(cond), transform(thenp), transform(elsep)) - case Closure(env, meth, tpt) => - cpy.Closure(tree)(transform(env), transform(meth), transform(tpt)) - case Match(selector, cases) => - cpy.Match(tree)(transform(selector), transformSub(cases)) - case CaseDef(pat, guard, body) => - cpy.CaseDef(tree)(transform(pat), transform(guard), transform(body)) - case Labeled(bind, expr) => - cpy.Labeled(tree)(transformSub(bind), transform(expr)) - case Return(expr, from) => - cpy.Return(tree)(transform(expr), transformSub(from)) - case WhileDo(cond, body) => - cpy.WhileDo(tree)(transform(cond), transform(body)) - case Try(block, cases, finalizer) => - cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer)) - case SeqLiteral(elems, elemtpt) => - cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt)) - case Inlined(call, bindings, expansion) => - cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(inlineContext(call))) - case TypeTree() => - tree - case SingletonTypeTree(ref) => - cpy.SingletonTypeTree(tree)(transform(ref)) - case AndTypeTree(left, right) => - cpy.AndTypeTree(tree)(transform(left), transform(right)) - case OrTypeTree(left, right) => - cpy.OrTypeTree(tree)(transform(left), transform(right)) - case RefinedTypeTree(tpt, refinements) => - cpy.RefinedTypeTree(tree)(transform(tpt), transformSub(refinements)) - case AppliedTypeTree(tpt, args) => - cpy.AppliedTypeTree(tree)(transform(tpt), transform(args)) - case LambdaTypeTree(tparams, body) => - implicit val ctx = localCtx - cpy.LambdaTypeTree(tree)(transformSub(tparams), transform(body)) - case MatchTypeTree(bound, selector, cases) => - cpy.MatchTypeTree(tree)(transform(bound), transform(selector), transformSub(cases)) - case ByNameTypeTree(result) => - cpy.ByNameTypeTree(tree)(transform(result)) - case TypeBoundsTree(lo, hi) => - cpy.TypeBoundsTree(tree)(transform(lo), transform(hi)) - case Bind(name, body) => - cpy.Bind(tree)(name, transform(body)) - case Alternative(trees) => - cpy.Alternative(tree)(transform(trees)) - case UnApply(fun, implicits, patterns) => - cpy.UnApply(tree)(transform(fun), transform(implicits), transform(patterns)) - case EmptyValDef => - tree - case tree @ ValDef(name, tpt, _) => - implicit val ctx = localCtx - val tpt1 = transform(tpt) - val rhs1 = transform(tree.rhs) - cpy.ValDef(tree)(name, tpt1, rhs1) - case tree @ DefDef(name, tparams, vparamss, tpt, _) => - implicit val ctx = localCtx - cpy.DefDef(tree)(name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt), transform(tree.rhs)) - case tree @ TypeDef(name, rhs) => - implicit val ctx = localCtx - cpy.TypeDef(tree)(name, transform(rhs)) - case tree @ Template(constr, parents, self, _) => - cpy.Template(tree)(transformSub(constr), transform(parents), transformSub(self), transformStats(tree.body)) - case Import(expr, selectors) => - cpy.Import(tree)(transform(expr), selectors) - case PackageDef(pid, stats) => - cpy.PackageDef(tree)(transformSub(pid), transformStats(stats)(localCtx)) - case Annotated(arg, annot) => - cpy.Annotated(tree)(transform(arg), transform(annot)) - case Thicket(trees) => - val trees1 = transform(trees) - if (trees1 eq trees) tree else Thicket(trees1) - case _ => - transformMoreCases(tree) - } + def transform(tree: Tree)(implicit ctx: Context): Tree = + if (tree.source != ctx.source && tree.source.exists) + transform(tree)(ctx.withSource(tree.source)) + else { + Stats.record(s"TreeMap.transform/$getClass") + def localCtx = + if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx + + if (skipTransform(tree)) tree + else tree match { + case Ident(name) => + tree + case Select(qualifier, name) => + cpy.Select(tree)(transform(qualifier), name) + case This(qual) => + tree + case Super(qual, mix) => + cpy.Super(tree)(transform(qual), mix) + case Apply(fun, args) => + cpy.Apply(tree)(transform(fun), transform(args)) + case TypeApply(fun, args) => + cpy.TypeApply(tree)(transform(fun), transform(args)) + case Literal(const) => + tree + case New(tpt) => + cpy.New(tree)(transform(tpt)) + case Typed(expr, tpt) => + cpy.Typed(tree)(transform(expr), transform(tpt)) + case NamedArg(name, arg) => + cpy.NamedArg(tree)(name, transform(arg)) + case Assign(lhs, rhs) => + cpy.Assign(tree)(transform(lhs), transform(rhs)) + case Block(stats, expr) => + cpy.Block(tree)(transformStats(stats), transform(expr)) + case If(cond, thenp, elsep) => + cpy.If(tree)(transform(cond), transform(thenp), transform(elsep)) + case Closure(env, meth, tpt) => + cpy.Closure(tree)(transform(env), transform(meth), transform(tpt)) + case Match(selector, cases) => + cpy.Match(tree)(transform(selector), transformSub(cases)) + case CaseDef(pat, guard, body) => + cpy.CaseDef(tree)(transform(pat), transform(guard), transform(body)) + case Labeled(bind, expr) => + cpy.Labeled(tree)(transformSub(bind), transform(expr)) + case Return(expr, from) => + cpy.Return(tree)(transform(expr), transformSub(from)) + case WhileDo(cond, body) => + cpy.WhileDo(tree)(transform(cond), transform(body)) + case Try(block, cases, finalizer) => + cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer)) + case SeqLiteral(elems, elemtpt) => + cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt)) + case Inlined(call, bindings, expansion) => + cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(inlineContext(call))) + case TypeTree() => + tree + case SingletonTypeTree(ref) => + cpy.SingletonTypeTree(tree)(transform(ref)) + case AndTypeTree(left, right) => + cpy.AndTypeTree(tree)(transform(left), transform(right)) + case OrTypeTree(left, right) => + cpy.OrTypeTree(tree)(transform(left), transform(right)) + case RefinedTypeTree(tpt, refinements) => + cpy.RefinedTypeTree(tree)(transform(tpt), transformSub(refinements)) + case AppliedTypeTree(tpt, args) => + cpy.AppliedTypeTree(tree)(transform(tpt), transform(args)) + case LambdaTypeTree(tparams, body) => + implicit val ctx = localCtx + cpy.LambdaTypeTree(tree)(transformSub(tparams), transform(body)) + case MatchTypeTree(bound, selector, cases) => + cpy.MatchTypeTree(tree)(transform(bound), transform(selector), transformSub(cases)) + case ByNameTypeTree(result) => + cpy.ByNameTypeTree(tree)(transform(result)) + case TypeBoundsTree(lo, hi) => + cpy.TypeBoundsTree(tree)(transform(lo), transform(hi)) + case Bind(name, body) => + cpy.Bind(tree)(name, transform(body)) + case Alternative(trees) => + cpy.Alternative(tree)(transform(trees)) + case UnApply(fun, implicits, patterns) => + cpy.UnApply(tree)(transform(fun), transform(implicits), transform(patterns)) + case EmptyValDef => + tree + case tree @ ValDef(name, tpt, _) => + implicit val ctx = localCtx + val tpt1 = transform(tpt) + val rhs1 = transform(tree.rhs) + cpy.ValDef(tree)(name, tpt1, rhs1) + case tree @ DefDef(name, tparams, vparamss, tpt, _) => + implicit val ctx = localCtx + cpy.DefDef(tree)(name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt), transform(tree.rhs)) + case tree @ TypeDef(name, rhs) => + implicit val ctx = localCtx + cpy.TypeDef(tree)(name, transform(rhs)) + case tree @ Template(constr, parents, self, _) => + cpy.Template(tree)(transformSub(constr), transform(parents), transformSub(self), transformStats(tree.body)) + case Import(expr, selectors) => + cpy.Import(tree)(transform(expr), selectors) + case PackageDef(pid, stats) => + cpy.PackageDef(tree)(transformSub(pid), transformStats(stats)(localCtx)) + case Annotated(arg, annot) => + cpy.Annotated(tree)(transform(arg), transform(annot)) + case Thicket(trees) => + val trees1 = transform(trees) + if (trees1 eq trees) tree else Thicket(trees1) + case _ => + transformMoreCases(tree) + } } def transformStats(trees: List[Tree])(implicit ctx: Context): List[Tree] = @@ -1331,105 +1328,107 @@ object Trees { def apply(x: X, tree: Tree)(implicit ctx: Context): X def apply(x: X, trees: Traversable[Tree])(implicit ctx: Context): X = (x /: trees)(apply) - def foldOver(x: X, tree: Tree)(implicit ctx: Context): X = { - Stats.record(s"TreeAccumulator.foldOver $getClass") - Stats.record("TreeAccumulator.foldOver total") - def localCtx = - if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx - tree match { - case Ident(name) => - x - case Select(qualifier, name) => - this(x, qualifier) - case This(qual) => - x - case Super(qual, mix) => - this(x, qual) - case Apply(fun, args) => - this(this(x, fun), args) - case TypeApply(fun, args) => - this(this(x, fun), args) - case Literal(const) => - x - case New(tpt) => - this(x, tpt) - case Typed(expr, tpt) => - this(this(x, expr), tpt) - case NamedArg(name, arg) => - this(x, arg) - case Assign(lhs, rhs) => - this(this(x, lhs), rhs) - case Block(stats, expr) => - this(this(x, stats), expr) - case If(cond, thenp, elsep) => - this(this(this(x, cond), thenp), elsep) - case Closure(env, meth, tpt) => - this(this(this(x, env), meth), tpt) - case Match(selector, cases) => - this(this(x, selector), cases) - case CaseDef(pat, guard, body) => - this(this(this(x, pat), guard), body) - case Labeled(bind, expr) => - this(this(x, bind), expr) - case Return(expr, from) => - this(this(x, expr), from) - case WhileDo(cond, body) => - this(this(x, cond), body) - case Try(block, handler, finalizer) => - this(this(this(x, block), handler), finalizer) - case SeqLiteral(elems, elemtpt) => - this(this(x, elems), elemtpt) - case Inlined(call, bindings, expansion) => - this(this(x, bindings), expansion)(inlineContext(call)) - case TypeTree() => - x - case SingletonTypeTree(ref) => - this(x, ref) - case AndTypeTree(left, right) => - this(this(x, left), right) - case OrTypeTree(left, right) => - this(this(x, left), right) - case RefinedTypeTree(tpt, refinements) => - this(this(x, tpt), refinements) - case AppliedTypeTree(tpt, args) => - this(this(x, tpt), args) - case LambdaTypeTree(tparams, body) => - implicit val ctx = localCtx - this(this(x, tparams), body) - case MatchTypeTree(bound, selector, cases) => - this(this(this(x, bound), selector), cases) - case ByNameTypeTree(result) => - this(x, result) - case TypeBoundsTree(lo, hi) => - this(this(x, lo), hi) - case Bind(name, body) => - this(x, body) - case Alternative(trees) => - this(x, trees) - case UnApply(fun, implicits, patterns) => - this(this(this(x, fun), implicits), patterns) - case tree @ ValDef(name, tpt, _) => - implicit val ctx = localCtx - this(this(x, tpt), tree.rhs) - case tree @ DefDef(name, tparams, vparamss, tpt, _) => - implicit val ctx = localCtx - this(this((this(x, tparams) /: vparamss)(apply), tpt), tree.rhs) - case TypeDef(name, rhs) => - implicit val ctx = localCtx - this(x, rhs) - case tree @ Template(constr, parents, self, _) => - this(this(this(this(x, constr), parents), self), tree.body) - case Import(expr, selectors) => - this(x, expr) - case PackageDef(pid, stats) => - this(this(x, pid), stats)(localCtx) - case Annotated(arg, annot) => - this(this(x, arg), annot) - case Thicket(ts) => - this(x, ts) - case _ => - foldMoreCases(x, tree) - } + def foldOver(x: X, tree: Tree)(implicit ctx: Context): X = + if (tree.source != ctx.source && tree.source.exists) + foldOver(x, tree)(ctx.withSource(tree.source)) + else { + Stats.record(s"TreeAccumulator.foldOver/$getClass") + def localCtx = + if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx + tree match { + case Ident(name) => + x + case Select(qualifier, name) => + this(x, qualifier) + case This(qual) => + x + case Super(qual, mix) => + this(x, qual) + case Apply(fun, args) => + this(this(x, fun), args) + case TypeApply(fun, args) => + this(this(x, fun), args) + case Literal(const) => + x + case New(tpt) => + this(x, tpt) + case Typed(expr, tpt) => + this(this(x, expr), tpt) + case NamedArg(name, arg) => + this(x, arg) + case Assign(lhs, rhs) => + this(this(x, lhs), rhs) + case Block(stats, expr) => + this(this(x, stats), expr) + case If(cond, thenp, elsep) => + this(this(this(x, cond), thenp), elsep) + case Closure(env, meth, tpt) => + this(this(this(x, env), meth), tpt) + case Match(selector, cases) => + this(this(x, selector), cases) + case CaseDef(pat, guard, body) => + this(this(this(x, pat), guard), body) + case Labeled(bind, expr) => + this(this(x, bind), expr) + case Return(expr, from) => + this(this(x, expr), from) + case WhileDo(cond, body) => + this(this(x, cond), body) + case Try(block, handler, finalizer) => + this(this(this(x, block), handler), finalizer) + case SeqLiteral(elems, elemtpt) => + this(this(x, elems), elemtpt) + case Inlined(call, bindings, expansion) => + this(this(x, bindings), expansion)(inlineContext(call)) + case TypeTree() => + x + case SingletonTypeTree(ref) => + this(x, ref) + case AndTypeTree(left, right) => + this(this(x, left), right) + case OrTypeTree(left, right) => + this(this(x, left), right) + case RefinedTypeTree(tpt, refinements) => + this(this(x, tpt), refinements) + case AppliedTypeTree(tpt, args) => + this(this(x, tpt), args) + case LambdaTypeTree(tparams, body) => + implicit val ctx = localCtx + this(this(x, tparams), body) + case MatchTypeTree(bound, selector, cases) => + this(this(this(x, bound), selector), cases) + case ByNameTypeTree(result) => + this(x, result) + case TypeBoundsTree(lo, hi) => + this(this(x, lo), hi) + case Bind(name, body) => + this(x, body) + case Alternative(trees) => + this(x, trees) + case UnApply(fun, implicits, patterns) => + this(this(this(x, fun), implicits), patterns) + case tree @ ValDef(name, tpt, _) => + implicit val ctx = localCtx + this(this(x, tpt), tree.rhs) + case tree @ DefDef(name, tparams, vparamss, tpt, _) => + implicit val ctx = localCtx + this(this((this(x, tparams) /: vparamss)(apply), tpt), tree.rhs) + case TypeDef(name, rhs) => + implicit val ctx = localCtx + this(x, rhs) + case tree @ Template(constr, parents, self, _) => + this(this(this(this(x, constr), parents), self), tree.body) + case Import(expr, selectors) => + this(x, expr) + case PackageDef(pid, stats) => + this(this(x, pid), stats)(localCtx) + case Annotated(arg, annot) => + this(this(x, arg), annot) + case Thicket(ts) => + this(x, ts) + case _ => + foldMoreCases(x, tree) + } } def foldMoreCases(x: X, tree: Tree)(implicit ctx: Context): X = { diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 3fce069dd475..4bec4ee635d8 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -7,7 +7,7 @@ import dotty.tools.dotc.typer.ProtoTypes.FunProtoTyped import transform.SymUtils._ import transform.TypeUtils._ import core._ -import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._, NameOps._ +import util.Spans._, Types._, Contexts._, Constants._, Names._, Flags._, NameOps._ import Symbols._, StdNames._, Annotations._, Trees._, Symbols._ import Decorators._, DenotTransformers._ import collection.mutable @@ -204,7 +204,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { ta.assignType(untpd.ValDef(sym.name, TypeTree(sym.info), rhs), sym) def SyntheticValDef(name: TermName, rhs: Tree)(implicit ctx: Context): ValDef = - ValDef(ctx.newSymbol(ctx.owner, name, Synthetic, rhs.tpe.widen, coord = rhs.pos), rhs) + ValDef(ctx.newSymbol(ctx.owner, name, Synthetic, rhs.tpe.widen, coord = rhs.span), rhs) def DefDef(sym: TermSymbol, tparams: List[TypeSymbol], vparamss: List[List[TermSymbol]], resultType: Type, rhs: Tree)(implicit ctx: Context): DefDef = @@ -314,7 +314,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { if (parents.head.classSymbol.is(Trait)) parents.head.parents.head :: parents else parents val cls = ctx.newNormalizedClassSymbol(owner, tpnme.ANON_CLASS, Synthetic | Final, parents1, - coord = fns.map(_.pos).reduceLeft(_ union _)) + coord = fns.map(_.span).reduceLeft(_ union _)) val constr = ctx.newConstructor(cls, Synthetic, Nil, Nil).entered def forwarder(fn: TermSymbol, name: TermName) = { val fwdMeth = fn.copy(cls, name, Synthetic | Method | Final).entered.asTerm @@ -401,16 +401,16 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { * kind for the given element type in `elemTpe`. No type arguments or * `length` arguments are given. */ - def newArray(elemTpe: Type, returnTpe: Type, pos: Position, dims: JavaSeqLiteral)(implicit ctx: Context): Tree = { + def newArray(elemTpe: Type, returnTpe: Type, span: Span, dims: JavaSeqLiteral)(implicit ctx: Context): Tree = { val elemClass = elemTpe.classSymbol def newArr = - ref(defn.DottyArraysModule).select(defn.newArrayMethod).withPos(pos) + ref(defn.DottyArraysModule).select(defn.newArrayMethod).withSpan(span) if (!ctx.erasedTypes) { assert(!TypeErasure.isGeneric(elemTpe)) //needs to be done during typer. See Applications.convertNewGenericArray - newArr.appliedToTypeTrees(TypeTree(returnTpe) :: Nil).appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withPos(pos) + newArr.appliedToTypeTrees(TypeTree(returnTpe) :: Nil).appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withSpan(span) } else // after erasure - newArr.appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withPos(pos) + newArr.appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withSpan(span) } /** The wrapped array method name for an array of type elemtp */ @@ -1012,7 +1012,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { tree else { ctx.warning(i"conversion from ${tree.tpe.widen} to ${numericCls.typeRef} will always fail at runtime.") - Throw(New(defn.ClassCastExceptionClass.typeRef, Nil)) withPos tree.pos + Throw(New(defn.ClassCastExceptionClass.typeRef, Nil)).withSpan(tree.span) } } @@ -1134,10 +1134,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** The source file where the symbol of the `inline` method referred to by `call` * is defined */ - def sourceFile(call: Tree)(implicit ctx: Context): SourceFile = { - val file = call.symbol.sourceFile - if (file != null && file.exists) ctx.getSource(file) else NoSource - } + def sourceFile(call: Tree)(implicit ctx: Context): SourceFile = call.symbol.source /** Desugar identifier into a select node. Return the tree itself if not possible */ def desugarIdent(tree: Ident)(implicit ctx: Context): Tree = { @@ -1204,7 +1201,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { // Give a zero-extent position to the qualifier to prevent it from being included several // times in results in the language server. val noPosExpr = focusPositions(imp.expr) - val selectTree = Select(noPosExpr, sym.name).withPos(id.pos) + val selectTree = Select(noPosExpr, sym.name).withSpan(id.span) rename match { case None => selectTree :: Nil @@ -1213,7 +1210,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { // node with the new name and the type of the real symbol. val name = if (sym.name.isTypeName) rename.name.toTypeName else rename.name val actual = Select(noPosExpr, sym.name) - val renameTree = Select(noPosExpr, name).withPos(rename.pos).withType(actual.tpe) + val renameTree = Select(noPosExpr, name).withSpan(rename.span).withType(actual.tpe) selectTree :: renameTree :: Nil } } @@ -1236,7 +1233,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { private def focusPositions(tree: Tree)(implicit ctx: Context): Tree = { val transformer = new tpd.TreeMap { override def transform(tree: Tree)(implicit ctx: Context): Tree = { - super.transform(tree).withPos(tree.pos.focus) + super.transform(tree).withSpan(tree.span.focus) } } transformer.transform(tree) diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index f56cdea95bc5..26d95104a1ac 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -5,16 +5,16 @@ package ast import core._ import Types._, Contexts._, Constants._, Names._, Flags._ import Symbols._, StdNames._, Trees._ -import util.Property +import util.{Property, SourceFile, NoSource} import language.higherKinds - -import scala.annotation.internal.sharable +import annotation.constructorOnly +import annotation.internal.sharable object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { // ----- Tree cases that exist in untyped form only ------------------ - trait OpTree extends Tree { + abstract class OpTree(implicit @constructorOnly src: SourceFile) extends Tree { def op: Ident override def isTerm: Boolean = op.name.isTermName override def isType: Boolean = op.name.isTypeName @@ -23,7 +23,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { /** A typed subtree of an untyped tree needs to be wrapped in a TypedSplice * @param owner The current owner at the time the tree was defined */ - abstract case class TypedSplice(splice: tpd.Tree)(val owner: Symbol) extends ProxyTree { + abstract case class TypedSplice(splice: tpd.Tree)(val owner: Symbol)(implicit @constructorOnly src: SourceFile) extends ProxyTree { def forwardTo: tpd.Tree = splice } @@ -33,30 +33,32 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { } /** mods object name impl */ - case class ModuleDef(name: TermName, impl: Template) + case class ModuleDef(name: TermName, impl: Template)(implicit @constructorOnly src: SourceFile) extends MemberDef { type ThisTree[-T >: Untyped] <: Trees.NameTree[T] with Trees.MemberDef[T] with ModuleDef def withName(name: Name)(implicit ctx: Context): ModuleDef = cpy.ModuleDef(this)(name.toTermName, impl) } - case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree) extends TermTree + case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree)(implicit @constructorOnly src: SourceFile) extends Tree with TermTree - case class SymbolLit(str: String) extends TermTree + case class SymbolLit(str: String)(implicit @constructorOnly src: SourceFile) extends TermTree /** An interpolated string * @param segments a list of two element tickets consisting of string literal and argument tree, * possibly with a simple string literal as last element of the list */ - case class InterpolatedString(id: TermName, segments: List[Tree]) extends TermTree + case class InterpolatedString(id: TermName, segments: List[Tree])(implicit @constructorOnly src: SourceFile) + extends TermTree /** A function type */ - case class Function(args: List[Tree], body: Tree) extends Tree { + case class Function(args: List[Tree], body: Tree)(implicit @constructorOnly src: SourceFile) extends Tree { override def isTerm: Boolean = body.isTerm override def isType: Boolean = body.isType } /** A function type with `implicit` or `erased` modifiers */ - class FunctionWithMods(args: List[Tree], body: Tree, val mods: Modifiers) extends Function(args, body) + class FunctionWithMods(args: List[Tree], body: Tree, val mods: Modifiers)(implicit @constructorOnly src: SourceFile) + extends Function(args, body) /** A function created from a wildcard expression * @param placeholderParams a list of definitions of synthetic parameters. @@ -65,39 +67,40 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { * This is equivalent to Function, except that forms a special case for the overlapping * positions tests. */ - class WildcardFunction(placeholderParams: List[ValDef], body: Tree) extends Function(placeholderParams, body) + class WildcardFunction(placeholderParams: List[ValDef], body: Tree)(implicit @constructorOnly src: SourceFile) + extends Function(placeholderParams, body) - case class InfixOp(left: Tree, op: Ident, right: Tree) extends OpTree - case class PostfixOp(od: Tree, op: Ident) extends OpTree - case class PrefixOp(op: Ident, od: Tree) extends OpTree { + case class InfixOp(left: Tree, op: Ident, right: Tree)(implicit @constructorOnly src: SourceFile) extends OpTree + case class PostfixOp(od: Tree, op: Ident)(implicit @constructorOnly src: SourceFile) extends OpTree + case class PrefixOp(op: Ident, od: Tree)(implicit @constructorOnly src: SourceFile) extends OpTree { override def isType: Boolean = op.isType override def isTerm: Boolean = op.isTerm } - case class Parens(t: Tree) extends ProxyTree { + case class Parens(t: Tree)(implicit @constructorOnly src: SourceFile) extends ProxyTree { def forwardTo: Tree = t } - case class Tuple(trees: List[Tree]) extends Tree { + case class Tuple(trees: List[Tree])(implicit @constructorOnly src: SourceFile) extends Tree { override def isTerm: Boolean = trees.isEmpty || trees.head.isTerm override def isType: Boolean = !isTerm } - case class Throw(expr: Tree) extends TermTree - case class Quote(expr: Tree) extends TermTree - case class DoWhile(body: Tree, cond: Tree) extends TermTree - case class ForYield(enums: List[Tree], expr: Tree) extends TermTree - case class ForDo(enums: List[Tree], body: Tree) extends TermTree - case class GenFrom(pat: Tree, expr: Tree) extends Tree - case class GenAlias(pat: Tree, expr: Tree) extends Tree - case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree]) extends TypTree - case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree) extends DefTree - case class DependentTypeTree(tp: List[Symbol] => Type) extends Tree - - @sharable object EmptyTypeIdent extends Ident(tpnme.EMPTY) with WithoutTypeOrPos[Untyped] { + case class Throw(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree + case class Quote(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree + case class DoWhile(body: Tree, cond: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree + case class ForYield(enums: List[Tree], expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree + case class ForDo(enums: List[Tree], body: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree + case class GenFrom(pat: Tree, expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree + case class GenAlias(pat: Tree, expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree + case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree])(implicit @constructorOnly src: SourceFile) extends TypTree + case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree)(implicit @constructorOnly src: SourceFile) extends DefTree + case class DependentTypeTree(tp: List[Symbol] => Type)(implicit @constructorOnly src: SourceFile) extends Tree + + @sharable object EmptyTypeIdent extends Ident(tpnme.EMPTY)(NoSource) with WithoutTypeOrPos[Untyped] { override def isEmpty: Boolean = true } /** A block generated by the XML parser, only treated specially by * `Positioned#checkPos` */ - class XMLBlock(stats: List[Tree], expr: Tree) extends Block(stats, expr) + class XMLBlock(stats: List[Tree], expr: Tree)(implicit @constructorOnly src: SourceFile) extends Block(stats, expr) // ----- Modifiers ----------------------------------------------------- /** Mod is intended to record syntactic information about modifiers, it's @@ -105,39 +108,40 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { * * For any query about semantic information, check `flags` instead. */ - sealed abstract class Mod(val flags: FlagSet) extends Positioned + sealed abstract class Mod(val flags: FlagSet)(implicit @constructorOnly src: SourceFile) + extends Positioned object Mod { - case class Private() extends Mod(Flags.Private) + case class Private()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Private) - case class Protected() extends Mod(Flags.Protected) + case class Protected()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Protected) - case class Var() extends Mod(Flags.Mutable) + case class Var()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Mutable) - case class Implicit() extends Mod(Flags.ImplicitCommon) + case class Implicit()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.ImplicitCommon) - case class Erased() extends Mod(Flags.Erased) + case class Erased()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Erased) - case class Final() extends Mod(Flags.Final) + case class Final()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Final) - case class Sealed() extends Mod(Flags.Sealed) + case class Sealed()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Sealed) - case class Opaque() extends Mod(Flags.Opaque) + case class Opaque()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Opaque) - case class Override() extends Mod(Flags.Override) + case class Override()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Override) - case class Abstract() extends Mod(Flags.Abstract) + case class Abstract()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Abstract) - case class Lazy() extends Mod(Flags.Lazy) + case class Lazy()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Lazy) - case class Inline() extends Mod(Flags.Inline) + case class Inline()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Inline) - case class Enum() extends Mod(Flags.Enum) + case class Enum()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Enum) } /** Modifiers and annotations for definitions - * - * @param flags The set flags + * + * @param flags The set flags * @param privateWithin If a private or protected has is followed by a * qualifier [q], the name q, "" as a typename otherwise. * @param annotations The annotations preceding the modifiers @@ -146,7 +150,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { flags: FlagSet = EmptyFlags, privateWithin: TypeName = tpnme.EMPTY, annotations: List[Tree] = Nil, - mods: List[Mod] = Nil) extends Positioned with Cloneable { + mods: List[Mod] = Nil) { def is(fs: FlagSet): Boolean = flags is fs def is(fc: FlagConjunction): Boolean = flags is fc @@ -211,7 +215,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { /** A type tree that gets its type from some other tree's symbol. Enters the * type tree in the References attachment of the `from` tree as a side effect. */ - abstract class DerivedTypeTree extends TypeTree { + abstract class DerivedTypeTree(implicit @constructorOnly src: SourceFile) extends TypeTree { private[this] var myWatched: Tree = EmptyTree @@ -255,54 +259,54 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { // ------ Creation methods for untyped only ----------------- - def Ident(name: Name): Ident = new Ident(name) - def BackquotedIdent(name: Name): BackquotedIdent = new BackquotedIdent(name) - def SearchFailureIdent(name: Name): SearchFailureIdent = new SearchFailureIdent(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: 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) - def New(tpt: Tree): New = new New(tpt) - def Typed(expr: Tree, tpt: Tree): Typed = new Typed(expr, tpt) - def NamedArg(name: Name, arg: Tree): NamedArg = new NamedArg(name, arg) - def Assign(lhs: Tree, rhs: Tree): Assign = new Assign(lhs, rhs) - def Block(stats: List[Tree], expr: Tree): Block = new Block(stats, expr) - def If(cond: Tree, thenp: Tree, elsep: Tree): If = new If(cond, thenp, elsep) - def InlineIf(cond: Tree, thenp: Tree, elsep: Tree): If = new InlineIf(cond, thenp, elsep) - def Closure(env: List[Tree], meth: Tree, tpt: Tree): Closure = new Closure(env, meth, tpt) - def Match(selector: Tree, cases: List[CaseDef]): Match = new Match(selector, cases) - def InlineMatch(selector: Tree, cases: List[CaseDef]): Match = new InlineMatch(selector, cases) - def CaseDef(pat: Tree, guard: Tree, body: Tree): CaseDef = new CaseDef(pat, guard, body) - def Labeled(bind: Bind, expr: Tree): Labeled = new Labeled(bind, expr) - def Return(expr: Tree, from: Tree): Return = new Return(expr, from) - def WhileDo(cond: Tree, body: Tree): WhileDo = new WhileDo(cond, body) - def Try(expr: Tree, cases: List[CaseDef], finalizer: Tree): Try = new Try(expr, cases, finalizer) - def SeqLiteral(elems: List[Tree], elemtpt: Tree): SeqLiteral = new SeqLiteral(elems, elemtpt) - def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree): JavaSeqLiteral = new JavaSeqLiteral(elems, elemtpt) - def Inlined(call: tpd.Tree, bindings: List[MemberDef], expansion: Tree): Inlined = new Inlined(call, bindings, expansion) - def TypeTree(): TypeTree = new TypeTree() - def SingletonTypeTree(ref: Tree): SingletonTypeTree = new SingletonTypeTree(ref) - def AndTypeTree(left: Tree, right: Tree): AndTypeTree = new AndTypeTree(left, right) - def OrTypeTree(left: Tree, right: Tree): OrTypeTree = new OrTypeTree(left, right) - def RefinedTypeTree(tpt: Tree, refinements: List[Tree]): RefinedTypeTree = new RefinedTypeTree(tpt, refinements) - def AppliedTypeTree(tpt: Tree, args: List[Tree]): AppliedTypeTree = new AppliedTypeTree(tpt, args) - def LambdaTypeTree(tparams: List[TypeDef], body: Tree): LambdaTypeTree = new LambdaTypeTree(tparams, body) - def MatchTypeTree(bound: Tree, selector: Tree, cases: List[CaseDef]): MatchTypeTree = new MatchTypeTree(bound, selector, cases) - def ByNameTypeTree(result: Tree): ByNameTypeTree = new ByNameTypeTree(result) - def TypeBoundsTree(lo: Tree, hi: Tree): TypeBoundsTree = new TypeBoundsTree(lo, hi) - def Bind(name: Name, body: Tree): Bind = new Bind(name, body) - def Alternative(trees: List[Tree]): Alternative = new Alternative(trees) - def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree]): UnApply = new UnApply(fun, implicits, patterns) - def ValDef(name: TermName, tpt: Tree, rhs: LazyTree): ValDef = new ValDef(name, tpt, rhs) - def DefDef(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree): DefDef = new DefDef(name, tparams, vparamss, tpt, rhs) - def TypeDef(name: TypeName, rhs: Tree): TypeDef = new TypeDef(name, rhs) - def Template(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList): Template = new Template(constr, parents, self, body) - def Import(expr: Tree, selectors: List[Tree]): Import = new Import(expr, selectors) - def PackageDef(pid: RefTree, stats: List[Tree]): PackageDef = new PackageDef(pid, stats) - def Annotated(arg: Tree, annot: Tree): Annotated = new Annotated(arg, annot) + def Ident(name: Name)(implicit src: SourceFile): Ident = new Ident(name) + def BackquotedIdent(name: Name)(implicit src: SourceFile): BackquotedIdent = new BackquotedIdent(name) + def SearchFailureIdent(name: Name)(implicit src: SourceFile): SearchFailureIdent = new SearchFailureIdent(name) + def Select(qualifier: Tree, name: Name)(implicit src: SourceFile): Select = new Select(qualifier, name) + def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit src: SourceFile): Select = new SelectWithSig(qualifier, name, sig) + def This(qual: Ident)(implicit src: SourceFile): This = new This(qual) + def Super(qual: Tree, mix: Ident)(implicit src: SourceFile): Super = new Super(qual, mix) + def Apply(fun: Tree, args: List[Tree])(implicit src: SourceFile): Apply = new Apply(fun, args) + def TypeApply(fun: Tree, args: List[Tree])(implicit src: SourceFile): TypeApply = new TypeApply(fun, args) + def Literal(const: Constant)(implicit src: SourceFile): Literal = new Literal(const) + def New(tpt: Tree)(implicit src: SourceFile): New = new New(tpt) + def Typed(expr: Tree, tpt: Tree)(implicit src: SourceFile): Typed = new Typed(expr, tpt) + def NamedArg(name: Name, arg: Tree)(implicit src: SourceFile): NamedArg = new NamedArg(name, arg) + def Assign(lhs: Tree, rhs: Tree)(implicit src: SourceFile): Assign = new Assign(lhs, rhs) + def Block(stats: List[Tree], expr: Tree)(implicit src: SourceFile): Block = new Block(stats, expr) + def If(cond: Tree, thenp: Tree, elsep: Tree)(implicit src: SourceFile): If = new If(cond, thenp, elsep) + def InlineIf(cond: Tree, thenp: Tree, elsep: Tree)(implicit src: SourceFile): If = new InlineIf(cond, thenp, elsep) + def Closure(env: List[Tree], meth: Tree, tpt: Tree)(implicit src: SourceFile): Closure = new Closure(env, meth, tpt) + def Match(selector: Tree, cases: List[CaseDef])(implicit src: SourceFile): Match = new Match(selector, cases) + def InlineMatch(selector: Tree, cases: List[CaseDef])(implicit src: SourceFile): Match = new InlineMatch(selector, cases) + def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit src: SourceFile): CaseDef = new CaseDef(pat, guard, body) + def Labeled(bind: Bind, expr: Tree)(implicit src: SourceFile): Labeled = new Labeled(bind, expr) + def Return(expr: Tree, from: Tree)(implicit src: SourceFile): Return = new Return(expr, from) + def WhileDo(cond: Tree, body: Tree)(implicit src: SourceFile): WhileDo = new WhileDo(cond, body) + def Try(expr: Tree, cases: List[CaseDef], finalizer: Tree)(implicit src: SourceFile): Try = new Try(expr, cases, finalizer) + def SeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit src: SourceFile): SeqLiteral = new SeqLiteral(elems, elemtpt) + def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit src: SourceFile): JavaSeqLiteral = new JavaSeqLiteral(elems, elemtpt) + def Inlined(call: tpd.Tree, bindings: List[MemberDef], expansion: Tree)(implicit src: SourceFile): Inlined = new Inlined(call, bindings, expansion) + def TypeTree()(implicit src: SourceFile): TypeTree = new TypeTree() + def SingletonTypeTree(ref: Tree)(implicit src: SourceFile): SingletonTypeTree = new SingletonTypeTree(ref) + def AndTypeTree(left: Tree, right: Tree)(implicit src: SourceFile): AndTypeTree = new AndTypeTree(left, right) + def OrTypeTree(left: Tree, right: Tree)(implicit src: SourceFile): OrTypeTree = new OrTypeTree(left, right) + def RefinedTypeTree(tpt: Tree, refinements: List[Tree])(implicit src: SourceFile): RefinedTypeTree = new RefinedTypeTree(tpt, refinements) + def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit src: SourceFile): AppliedTypeTree = new AppliedTypeTree(tpt, args) + def LambdaTypeTree(tparams: List[TypeDef], body: Tree)(implicit src: SourceFile): LambdaTypeTree = new LambdaTypeTree(tparams, body) + def MatchTypeTree(bound: Tree, selector: Tree, cases: List[CaseDef])(implicit src: SourceFile): MatchTypeTree = new MatchTypeTree(bound, selector, cases) + def ByNameTypeTree(result: Tree)(implicit src: SourceFile): ByNameTypeTree = new ByNameTypeTree(result) + def TypeBoundsTree(lo: Tree, hi: Tree)(implicit src: SourceFile): TypeBoundsTree = new TypeBoundsTree(lo, hi) + def Bind(name: Name, body: Tree)(implicit src: SourceFile): Bind = new Bind(name, body) + def Alternative(trees: List[Tree])(implicit src: SourceFile): Alternative = new Alternative(trees) + def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree])(implicit src: SourceFile): UnApply = new UnApply(fun, implicits, patterns) + def ValDef(name: TermName, tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): ValDef = new ValDef(name, tpt, rhs) + def DefDef(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): DefDef = new DefDef(name, tparams, vparamss, tpt, rhs) + def TypeDef(name: TypeName, rhs: Tree)(implicit src: SourceFile): TypeDef = new TypeDef(name, rhs) + def Template(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList)(implicit src: SourceFile): Template = new Template(constr, parents, self, body) + def Import(expr: Tree, selectors: List[Tree])(implicit src: SourceFile): Import = new Import(expr, selectors) + def PackageDef(pid: RefTree, stats: List[Tree])(implicit src: SourceFile): PackageDef = new PackageDef(pid, stats) + def Annotated(arg: Tree, annot: Tree)(implicit src: SourceFile): Annotated = new Annotated(arg, annot) // ------ Additional creation methods for untyped only ----------------- @@ -321,7 +325,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { (tycon, targs) case TypedSplice(tpt1: tpd.Tree) => val argTypes = tpt1.tpe.dealias.argTypesLo - def wrap(tpe: Type) = TypeTree(tpe).withPos(tpt.pos) + def wrap(tpe: Type) = TypeTree(tpe).withSpan(tpt.span) (tpt, argTypes.map(wrap)) case _ => (tpt, Nil) @@ -331,32 +335,32 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { ensureApplied((prefix /: argss)(Apply(_, _))) } - def Block(stat: Tree, expr: Tree): Block = + def Block(stat: Tree, expr: Tree)(implicit src: SourceFile): Block = Block(stat :: Nil, expr) - def Apply(fn: Tree, arg: Tree): Apply = + def Apply(fn: Tree, arg: Tree)(implicit src: SourceFile): Apply = Apply(fn, arg :: Nil) - def ensureApplied(tpt: Tree): Tree = tpt match { + def ensureApplied(tpt: Tree)(implicit src: SourceFile): Tree = tpt match { case _: Apply => tpt case _ => Apply(tpt, Nil) } - def AppliedTypeTree(tpt: Tree, arg: Tree): AppliedTypeTree = + def AppliedTypeTree(tpt: Tree, arg: Tree)(implicit src: SourceFile): AppliedTypeTree = AppliedTypeTree(tpt, arg :: Nil) def TypeTree(tpe: Type)(implicit ctx: Context): TypedSplice = TypedSplice(TypeTree().withTypeUnchecked(tpe)) - def unitLiteral: Literal = Literal(Constant(())) + def unitLiteral(implicit src: SourceFile): Literal = Literal(Constant(())) def ref(tp: NamedType)(implicit ctx: Context): Tree = TypedSplice(tpd.ref(tp)) - def rootDot(name: Name): Select = Select(Ident(nme.ROOTPKG), name) - def scalaDot(name: Name): Select = Select(rootDot(nme.scala_), name) - def scalaUnit: Select = scalaDot(tpnme.Unit) - def scalaAny: Select = scalaDot(tpnme.Any) - def javaDotLangDot(name: Name): Select = Select(Select(Ident(nme.java), nme.lang), name) + def rootDot(name: Name)(implicit src: SourceFile): Select = Select(Ident(nme.ROOTPKG), name) + def scalaDot(name: Name)(implicit src: SourceFile): Select = Select(rootDot(nme.scala_), name) + def scalaUnit(implicit src: SourceFile): Select = scalaDot(tpnme.Unit) + def scalaAny(implicit src: SourceFile): Select = scalaDot(tpnme.Any) + def javaDotLangDot(name: Name)(implicit src: SourceFile): Select = Select(Select(Ident(nme.java), nme.lang), name) def makeConstructor(tparams: List[TypeDef], vparamss: List[List[ValDef]], rhs: Tree = EmptyTree)(implicit ctx: Context): DefDef = DefDef(nme.CONSTRUCTOR, tparams, vparamss, TypeTree(), rhs) @@ -380,8 +384,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = EmptyModifiers)(implicit ctx: Context): ValDef = ValDef(pname, tpe, EmptyTree).withMods(mods | Param) - def makeSyntheticParameter(n: Int = 1, tpt: Tree = TypeTree())(implicit ctx: Context): ValDef = - ValDef(nme.syntheticParamName(n), tpt, EmptyTree).withFlags(SyntheticTermParam) + def makeSyntheticParameter(n: Int = 1, tpt: Tree = null)(implicit ctx: Context): ValDef = + ValDef(nme.syntheticParamName(n), if (tpt == null) TypeTree() else tpt, EmptyTree) + .withFlags(SyntheticTermParam) def lambdaAbstract(tparams: List[TypeDef], tpt: Tree)(implicit ctx: Context): Tree = if (tparams.isEmpty) tpt else LambdaTypeTree(tparams, tpt) @@ -421,86 +426,86 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { } }.asInstanceOf[copied.ThisTree[Untyped]] - def ModuleDef(tree: Tree)(name: TermName, impl: Template): ModuleDef = tree match { + def ModuleDef(tree: Tree)(name: TermName, impl: Template)(implicit ctx: Context): ModuleDef = tree match { case tree: ModuleDef if (name eq tree.name) && (impl eq tree.impl) => tree - case _ => finalize(tree, untpd.ModuleDef(name, impl)) + case _ => finalize(tree, untpd.ModuleDef(name, impl)(tree.source)) } - def ParsedTry(tree: Tree)(expr: Tree, handler: Tree, finalizer: Tree): TermTree = tree match { + def ParsedTry(tree: Tree)(expr: Tree, handler: Tree, finalizer: Tree)(implicit ctx: Context): TermTree = tree match { case tree: ParsedTry if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree - case _ => finalize(tree, untpd.ParsedTry(expr, handler, finalizer)) + case _ => finalize(tree, untpd.ParsedTry(expr, handler, finalizer)(tree.source)) } - def SymbolLit(tree: Tree)(str: String): TermTree = tree match { + def SymbolLit(tree: Tree)(str: String)(implicit ctx: Context): TermTree = tree match { case tree: SymbolLit if str == tree.str => tree - case _ => finalize(tree, untpd.SymbolLit(str)) + case _ => finalize(tree, untpd.SymbolLit(str)(tree.source)) } - def InterpolatedString(tree: Tree)(id: TermName, segments: List[Tree]): TermTree = tree match { + def InterpolatedString(tree: Tree)(id: TermName, segments: List[Tree])(implicit ctx: Context): TermTree = tree match { case tree: InterpolatedString if (id eq tree.id) && (segments eq tree.segments) => tree - case _ => finalize(tree, untpd.InterpolatedString(id, segments)) + case _ => finalize(tree, untpd.InterpolatedString(id, segments)(tree.source)) } - def Function(tree: Tree)(args: List[Tree], body: Tree): Tree = tree match { + def Function(tree: Tree)(args: List[Tree], body: Tree)(implicit ctx: Context): Tree = tree match { case tree: Function if (args eq tree.args) && (body eq tree.body) => tree - case _ => finalize(tree, untpd.Function(args, body)) + case _ => finalize(tree, untpd.Function(args, body)(tree.source)) } - def InfixOp(tree: Tree)(left: Tree, op: Ident, right: Tree): Tree = tree match { + def InfixOp(tree: Tree)(left: Tree, op: Ident, right: Tree)(implicit ctx: Context): Tree = tree match { case tree: InfixOp if (left eq tree.left) && (op eq tree.op) && (right eq tree.right) => tree - case _ => finalize(tree, untpd.InfixOp(left, op, right)) + case _ => finalize(tree, untpd.InfixOp(left, op, right)(tree.source)) } - def PostfixOp(tree: Tree)(od: Tree, op: Ident): Tree = tree match { + def PostfixOp(tree: Tree)(od: Tree, op: Ident)(implicit ctx: Context): Tree = tree match { case tree: PostfixOp if (od eq tree.od) && (op eq tree.op) => tree - case _ => finalize(tree, untpd.PostfixOp(od, op)) + case _ => finalize(tree, untpd.PostfixOp(od, op)(tree.source)) } - def PrefixOp(tree: Tree)(op: Ident, od: Tree): Tree = tree match { + def PrefixOp(tree: Tree)(op: Ident, od: Tree)(implicit ctx: Context): Tree = tree match { case tree: PrefixOp if (op eq tree.op) && (od eq tree.od) => tree - case _ => finalize(tree, untpd.PrefixOp(op, od)) + case _ => finalize(tree, untpd.PrefixOp(op, od)(tree.source)) } - def Parens(tree: Tree)(t: Tree): ProxyTree = tree match { + def Parens(tree: Tree)(t: Tree)(implicit ctx: Context): ProxyTree = tree match { case tree: Parens if t eq tree.t => tree - case _ => finalize(tree, untpd.Parens(t)) + case _ => finalize(tree, untpd.Parens(t)(tree.source)) } - def Tuple(tree: Tree)(trees: List[Tree]): Tree = tree match { + def Tuple(tree: Tree)(trees: List[Tree])(implicit ctx: Context): Tree = tree match { case tree: Tuple if trees eq tree.trees => tree - case _ => finalize(tree, untpd.Tuple(trees)) + case _ => finalize(tree, untpd.Tuple(trees)(tree.source)) } - def Throw(tree: Tree)(expr: Tree): TermTree = tree match { + def Throw(tree: Tree)(expr: Tree)(implicit ctx: Context): TermTree = tree match { case tree: Throw if expr eq tree.expr => tree - case _ => finalize(tree, untpd.Throw(expr)) + case _ => finalize(tree, untpd.Throw(expr)(tree.source)) } - def Quote(tree: Tree)(expr: Tree): TermTree = tree match { + def Quote(tree: Tree)(expr: Tree)(implicit ctx: Context): TermTree = tree match { case tree: Quote if expr eq tree.expr => tree - case _ => finalize(tree, untpd.Quote(expr)) + case _ => finalize(tree, untpd.Quote(expr)(tree.source)) } - def DoWhile(tree: Tree)(body: Tree, cond: Tree): TermTree = tree match { + def DoWhile(tree: Tree)(body: Tree, cond: Tree)(implicit ctx: Context): TermTree = tree match { case tree: DoWhile if (body eq tree.body) && (cond eq tree.cond) => tree - case _ => finalize(tree, untpd.DoWhile(body, cond)) + case _ => finalize(tree, untpd.DoWhile(body, cond)(tree.source)) } - def ForYield(tree: Tree)(enums: List[Tree], expr: Tree): TermTree = tree match { + def ForYield(tree: Tree)(enums: List[Tree], expr: Tree)(implicit ctx: Context): TermTree = tree match { case tree: ForYield if (enums eq tree.enums) && (expr eq tree.expr) => tree - case _ => finalize(tree, untpd.ForYield(enums, expr)) + case _ => finalize(tree, untpd.ForYield(enums, expr)(tree.source)) } - def ForDo(tree: Tree)(enums: List[Tree], body: Tree): TermTree = tree match { + def ForDo(tree: Tree)(enums: List[Tree], body: Tree)(implicit ctx: Context): TermTree = tree match { case tree: ForDo if (enums eq tree.enums) && (body eq tree.body) => tree - case _ => finalize(tree, untpd.ForDo(enums, body)) + case _ => finalize(tree, untpd.ForDo(enums, body)(tree.source)) } - def GenFrom(tree: Tree)(pat: Tree, expr: Tree): Tree = tree match { + def GenFrom(tree: Tree)(pat: Tree, expr: Tree)(implicit ctx: Context): Tree = tree match { case tree: GenFrom if (pat eq tree.pat) && (expr eq tree.expr) => tree - case _ => finalize(tree, untpd.GenFrom(pat, expr)) + case _ => finalize(tree, untpd.GenFrom(pat, expr)(tree.source)) } - def GenAlias(tree: Tree)(pat: Tree, expr: Tree): Tree = tree match { + def GenAlias(tree: Tree)(pat: Tree, expr: Tree)(implicit ctx: Context): Tree = tree match { case tree: GenAlias if (pat eq tree.pat) && (expr eq tree.expr) => tree - case _ => finalize(tree, untpd.GenAlias(pat, expr)) + case _ => finalize(tree, untpd.GenAlias(pat, expr)(tree.source)) } - def ContextBounds(tree: Tree)(bounds: TypeBoundsTree, cxBounds: List[Tree]): TypTree = tree match { + def ContextBounds(tree: Tree)(bounds: TypeBoundsTree, cxBounds: List[Tree])(implicit ctx: Context): TypTree = tree match { case tree: ContextBounds if (bounds eq tree.bounds) && (cxBounds eq tree.cxBounds) => tree - case _ => finalize(tree, untpd.ContextBounds(bounds, cxBounds)) + case _ => finalize(tree, untpd.ContextBounds(bounds, cxBounds)(tree.source)) } - def PatDef(tree: Tree)(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree): Tree = tree match { + def PatDef(tree: Tree)(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree)(implicit ctx: Context): Tree = tree match { case tree: PatDef if (mods eq tree.mods) && (pats eq tree.pats) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree - case _ => finalize(tree, untpd.PatDef(mods, pats, tpt, rhs)) + case _ => finalize(tree, untpd.PatDef(mods, pats, tpt, rhs)(tree.source)) } def TypedSplice(tree: Tree)(splice: tpd.Tree)(implicit ctx: Context): ProxyTree = tree match { case tree: TypedSplice if splice `eq` tree.splice => tree - case _ => finalize(tree, untpd.TypedSplice(splice)) + case _ => finalize(tree, untpd.TypedSplice(splice)(ctx)) } } diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 15cd9ef325ac..2026488631ba 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -87,6 +87,7 @@ class ScalaSettings extends Settings.SettingGroup { val YdebugFlags: Setting[Boolean] = BooleanSetting("-Ydebug-flags", "Print all flags of definitions") val YdebugMissingRefs: Setting[Boolean] = BooleanSetting("-Ydebug-missing-refs", "Print a stacktrace when a required symbol is missing") val YdebugNames: Setting[Boolean] = BooleanSetting("-Ydebug-names", "Show internal representation of names") + val YdebugPos: Setting[Boolean] = BooleanSetting("-Ydebug-pos", "Show full source positions including spans") val YtermConflict: Setting[String] = ChoiceSetting("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error") val Ylog: Setting[List[String]] = PhasesSetting("-Ylog", "Log operations during") val YemitTastyInClass: Setting[Boolean] = BooleanSetting("-Yemit-tasty-in-class", "Generate tasty in the .class file and add an empty *.hasTasty file.") diff --git a/compiler/src/dotty/tools/dotc/core/Comments.scala b/compiler/src/dotty/tools/dotc/core/Comments.scala index 6bb489550012..06079a6e4c48 100644 --- a/compiler/src/dotty/tools/dotc/core/Comments.scala +++ b/compiler/src/dotty/tools/dotc/core/Comments.scala @@ -5,7 +5,7 @@ package core import ast.{ untpd, tpd } import Decorators._, Symbols._, Contexts._ import util.SourceFile -import util.Positions._ +import util.Spans._ import util.CommentParsing._ import util.Property.Key import parsing.Parsers.Parser @@ -40,12 +40,12 @@ object Comments { * A `Comment` contains the unformatted docstring, it's position and potentially more * information that is populated when the comment is "cooked". * - * @param pos The position of this `Comment`. + * @param span The position span of this `Comment`. * @param raw The raw comment, as seen in the source code, without any expansion. * @param expanded If this comment has been expanded, it's expansion, otherwise `None`. * @param usecases The usecases for this comment. */ - final case class Comment(pos: Position, raw: String, expanded: Option[String], usecases: List[UseCase]) { + final case class Comment(span: Span, raw: String, expanded: Option[String], usecases: List[UseCase]) { /** Has this comment been cooked or expanded? */ def isExpanded: Boolean = expanded.isDefined @@ -65,8 +65,8 @@ object Comments { */ def expand(f: String => String)(implicit ctx: Context): Comment = { val expandedComment = f(raw) - val useCases = Comment.parseUsecases(expandedComment, pos) - Comment(pos, raw, Some(expandedComment), useCases) + val useCases = Comment.parseUsecases(expandedComment, span) + Comment(span, raw, Some(expandedComment), useCases) } } @@ -74,16 +74,16 @@ object Comments { def isDocComment(comment: String): Boolean = comment.startsWith("/**") - def apply(pos: Position, raw: String): Comment = - Comment(pos, raw, None, Nil) + def apply(span: Span, raw: String): Comment = + Comment(span, raw, None, Nil) - private def parseUsecases(expandedComment: String, pos: Position)(implicit ctx: Context): List[UseCase] = + private def parseUsecases(expandedComment: String, span: Span)(implicit ctx: Context): List[UseCase] = if (!isDocComment(expandedComment)) { Nil } else { tagIndex(expandedComment) .filter { startsWithTag(expandedComment, _, "@usecase") } - .map { case (start, end) => decomposeUseCase(expandedComment, pos, start, end) } + .map { case (start, end) => decomposeUseCase(expandedComment, span, start, end) } } /** Turns a usecase section into a UseCase, with code changed to: @@ -94,13 +94,13 @@ object Comments { * def foo: A = ??? * }}} */ - private[this] def decomposeUseCase(body: String, pos: Position, start: Int, end: Int)(implicit ctx: Context): UseCase = { + private[this] def decomposeUseCase(body: String, span: Span, start: Int, end: Int)(implicit ctx: Context): UseCase = { def subPos(start: Int, end: Int) = - if (pos == NoPosition) NoPosition + if (span == NoSpan) NoSpan else { - val start1 = pos.start + start - val end1 = pos.end + end - pos withStart start1 withPoint start1 withEnd end1 + val start1 = span.start + start + val end1 = span.end + end + span withStart start1 withPoint start1 withEnd end1 } val codeStart = skipWhitespace(body, start + "@usecase".length) @@ -112,20 +112,20 @@ object Comments { } } - final case class UseCase(code: String, codePos: Position, untpdCode: untpd.Tree, tpdCode: Option[tpd.DefDef]) { + final case class UseCase(code: String, codePos: Span, untpdCode: untpd.Tree, tpdCode: Option[tpd.DefDef]) { def typed(tpdCode: tpd.DefDef): UseCase = copy(tpdCode = Some(tpdCode)) } object UseCase { - def apply(code: String, codePos: Position)(implicit ctx: Context): UseCase = { + def apply(code: String, codePos: Span)(implicit ctx: Context): UseCase = { val tree = { - val tree = new Parser(new SourceFile("", code)).localDef(codePos.start) + val tree = new Parser(SourceFile.virtual("", code)).localDef(codePos.start) tree match { case tree: untpd.DefDef => val newName = ctx.freshNames.newName(tree.name, NameKinds.DocArtifactName) tree.copy(name = newName) case _ => - ctx.error(ProperDefinitionNotFound(), codePos) + ctx.error(ProperDefinitionNotFound(), ctx.source.atSpan(codePos)) tree } } @@ -199,7 +199,7 @@ object Comments { case None => // SI-8210 - The warning would be false negative when this symbol is a setter if (ownComment.indexOf("@inheritdoc") != -1 && ! sym.isSetter) - dottydoc.println(s"${sym.pos}: the comment for ${sym} contains @inheritdoc, but no parent comment is available to inherit from.") + dottydoc.println(s"${sym.span}: the comment for ${sym} contains @inheritdoc, but no parent comment is available to inherit from.") ownComment.replaceAllLiterally("@inheritdoc", "") case Some(sc) => if (ownComment == "") sc @@ -314,7 +314,7 @@ object Comments { val sectionTextBounds = extractSectionText(parent, section) cleanupSectionText(parent.substring(sectionTextBounds._1, sectionTextBounds._2)) case None => - dottydoc.println(s"""${sym.pos}: the """" + getSectionHeader + "\" annotation of the " + sym + + dottydoc.println(s"""${sym.span}: the """" + getSectionHeader + "\" annotation of the " + sym + " comment contains @inheritdoc, but the corresponding section in the parent is not defined.") "" } @@ -441,8 +441,8 @@ object Comments { * If a symbol does not have a doc comment but some overridden version of it does, * the position of the doc comment of the overridden version is returned instead. */ - def docCommentPos(sym: Symbol)(implicit ctx: Context): Position = - ctx.docCtx.flatMap(_.docstring(sym).map(_.pos)).getOrElse(NoPosition) + def docCommentPos(sym: Symbol)(implicit ctx: Context): Span = + ctx.docCtx.flatMap(_.docstring(sym).map(_.span)).getOrElse(NoSpan) /** A version which doesn't consider self types, as a temporary measure: * an infinite loop has broken out between superComment and cookedDocComment diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index b212e3cbfcfb..31c8269d0da9 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -20,7 +20,7 @@ import config.Settings._ import config.Config import reporting._ import reporting.diagnostic.Message -import io.AbstractFile +import io.{AbstractFile, NoAbstractFile, PlainFile, Path} import scala.io.Codec import collection.mutable import printing._ @@ -34,6 +34,7 @@ import util.Property.Key import util.Store import xsbti.AnalysisCallback import plugins._ +import java.util.concurrent.atomic.AtomicInteger object Contexts { @@ -158,6 +159,11 @@ object Contexts { _typeComparer } + /** The current source file */ + private[this] var _source: SourceFile = _ + protected def source_=(source: SourceFile): Unit = _source = source + def source: SourceFile = _source + /** A map in which more contextual properties can be stored * Typically used for attributes that are read and written only in special situations. */ @@ -227,8 +233,24 @@ object Contexts { } /** Sourcefile corresponding to given abstract file, memoized */ - def getSource(file: AbstractFile, codec: => Codec = Codec(settings.encoding.value)) = + def getSource(file: AbstractFile, codec: => Codec = Codec(settings.encoding.value)) = { + util.Stats.record("getSource") base.sources.getOrElseUpdate(file, new SourceFile(file, codec)) + } + + /** Sourcefile with given path name, memoized */ + def getSource(path: SourceFile.PathName): SourceFile = base.sourceNamed.get(path) match { + case Some(source) => + source + case None => + val f = new PlainFile(Path(path.toString)) + val src = getSource(f) + base.sourceNamed(path) = src + src + } + + /** Sourcefile with given path, memoized */ + def getSource(path: String): SourceFile = getSource(path.toTermName) /** Those fields are used to cache phases created in withPhase. * phasedCtx is first phase with altered phase ever requested. @@ -385,12 +407,6 @@ object Contexts { ctx.fresh.setImportInfo(new ImportInfo(implicit ctx => sym, imp.selectors, impNameOpt)) } - /** The current source file; will be derived from current - * compilation unit. - */ - def source: SourceFile = - if (compilationUnit == null) NoSource else compilationUnit.source - /** Does current phase use an erased types interpretation? */ def erasedTypes: Boolean = phase.erasedTypes @@ -409,6 +425,7 @@ object Contexts { this.implicitsCache = null this.phasedCtx = this this.phasedCtxs = null + this.sourceCtx = null // See comment related to `creationTrace` in this file // setCreationTrace() this @@ -420,6 +437,24 @@ object Contexts { final def withOwner(owner: Symbol): Context = if (owner ne this.owner) fresh.setOwner(owner) else this + private var sourceCtx: SimpleIdentityMap[SourceFile, Context] = null + + final def withSource(source: SourceFile): Context = + if (source `eq` this.source) this + else if ((source `eq` outer.source) && + outer.sourceCtx != null && + (outer.sourceCtx(this.source) `eq` this)) outer + else { + if (sourceCtx == null) sourceCtx = SimpleIdentityMap.Empty + val prev = sourceCtx(source) + if (prev != null) prev + else { + val newCtx = fresh.setSource(source) + sourceCtx = sourceCtx.updated(source, newCtx) + newCtx + } + } + final def withProperty[T](key: Key[T], value: Option[T]): Context = if (property(key) == value) this else value match { @@ -455,7 +490,7 @@ object Contexts { def pendingUnderlying: mutable.HashSet[Type] = base.pendingUnderlying def uniqueNamedTypes: Uniques.NamedTypeUniques = base.uniqueNamedTypes def uniques: util.HashSet[Type] = base.uniques - def nextId: Int = base.nextId + def nextSymId: Int = base.nextSymId def initialize()(implicit ctx: Context): Unit = base.initialize()(ctx) } @@ -488,16 +523,21 @@ object Contexts { def setGadt(gadt: GADTMap): this.type = { this.gadt = gadt; this } def setFreshGADTBounds: this.type = setGadt(gadt.fresh) def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this } + def setSource(source: SourceFile): this.type = { this.source = source; this } def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this } private def setMoreProperties(moreProperties: Map[Key[Any], Any]): this.type = { this.moreProperties = moreProperties; this } private def setStore(store: Store): this.type = { this.store = store; this } def setImplicits(implicits: ContextualImplicits): this.type = { this.implicitsCache = implicits; this } + def setCompilationUnit(compilationUnit: CompilationUnit): this.type = { + setSource(compilationUnit.source) + updateStore(compilationUnitLoc, compilationUnit) + } + def setCompilerCallback(callback: CompilerCallback): this.type = updateStore(compilerCallbackLoc, callback) def setSbtCallback(callback: AnalysisCallback): this.type = updateStore(sbtCallbackLoc, callback) def setPrinterFn(printer: Context => Printer): this.type = updateStore(printerFnLoc, printer) def setSettings(settingsState: SettingsState): this.type = updateStore(settingsStateLoc, settingsState) - def setCompilationUnit(compilationUnit: CompilationUnit): this.type = updateStore(compilationUnitLoc, compilationUnit) def setRun(run: Run): this.type = updateStore(runLoc, run) def setProfiler(profiler: Profiler): this.type = updateStore(profilerLoc, profiler) def setFreshNames(freshNames: FreshNameCreator): this.type = updateStore(freshNamesLoc, freshNames) @@ -559,6 +599,7 @@ object Contexts { tree = untpd.EmptyTree typeAssigner = TypeAssigner moreProperties = Map.empty + source = NoSource store = initialStore.updated(settingsStateLoc, settingsGroup.defaultState) typeComparer = new TypeComparer(this) searchHistory = new SearchRoot @@ -566,6 +607,7 @@ object Contexts { } @sharable object NoContext extends Context { + override def source = NoSource val base: ContextBase = null override val implicits: ContextualImplicits = new ContextualImplicits(Nil, null)(this) } @@ -625,13 +667,13 @@ object Contexts { class ContextState { // Symbols state - /** A counter for unique ids */ - private[core] var _nextId: Int = 0 - - def nextId: Int = { _nextId += 1; _nextId } + /** Counter for unique symbol ids */ + private[this] var _nextSymId: Int = 0 + def nextSymId: Int = { _nextSymId += 1; _nextSymId } /** Sources that were loaded */ val sources: mutable.HashMap[AbstractFile, SourceFile] = new mutable.HashMap[AbstractFile, SourceFile] + val sourceNamed: mutable.HashMap[SourceFile.PathName, SourceFile] = new mutable.HashMap[SourceFile.PathName, SourceFile] // Types state /** A table for hash consing unique types */ @@ -706,6 +748,7 @@ object Contexts { for ((_, set) <- uniqueSets) set.clear() errorTypeMsg.clear() sources.clear() + sourceNamed.clear() } // Test that access is single threaded diff --git a/compiler/src/dotty/tools/dotc/core/Decorators.scala b/compiler/src/dotty/tools/dotc/core/Decorators.scala index 601665468bbe..8d8bdffa7151 100644 --- a/compiler/src/dotty/tools/dotc/core/Decorators.scala +++ b/compiler/src/dotty/tools/dotc/core/Decorators.scala @@ -4,7 +4,7 @@ package core import annotation.tailrec import Symbols._ import Contexts._, Names._, Phases._, printing.Texts._, printing.Printer -import util.Positions.Position, util.SourcePosition +import util.Spans.Span, util.SourcePosition import collection.mutable.ListBuffer import dotty.tools.dotc.transform.MegaPhase import ast.tpd._ @@ -165,16 +165,6 @@ object Decorators { } } - implicit def sourcePos(pos: Position)(implicit ctx: Context): SourcePosition = { - def recur(inlinedCalls: List[Tree], pos: Position): SourcePosition = inlinedCalls match { - case inlinedCall :: rest => - sourceFile(inlinedCall).atPos(pos).withOuter(recur(rest, inlinedCall.pos)) - case empty => - ctx.source.atPos(pos) - } - recur(enclosingInlineds, pos) - } - implicit class genericDeco[T](val x: T) extends AnyVal { def reporting(op: T => String, printer: config.Printers.Printer = config.Printers.default): T = { printer.println(op(x)) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 03a4631e8c25..e44b02107266 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -794,6 +794,8 @@ class Definitions { def TASTYLongSignatureAnnot(implicit ctx: Context): ClassSymbol = TASTYLongSignatureAnnotType.symbol.asClass lazy val TailrecAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.tailrec") def TailrecAnnot(implicit ctx: Context): ClassSymbol = TailrecAnnotType.symbol.asClass + lazy val TransientParamAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.constructorOnly") + def TransientParamAnnot(implicit ctx: Context): ClassSymbol = TransientParamAnnotType.symbol.asClass lazy val SwitchAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.switch") def SwitchAnnot(implicit ctx: Context): ClassSymbol = SwitchAnnotType.symbol.asClass lazy val ThrowsAnnotType: TypeRef = ctx.requiredClassRef("scala.throws") diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 8b1975f6d1fd..aa909c68429e 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -376,7 +376,7 @@ object Names { override def replace(from: Char, to: Char): SimpleName = { val cs = new Array[Char](length) - Array.copy(chrs, start, cs, 0, length) + System.arraycopy(chrs, start, cs, 0, length) for (i <- 0 until length) { if (cs(i) == from) cs(i) = to } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 9e08f4c4f821..b1e237f6d62c 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -2108,7 +2108,7 @@ object SymDenotations { def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { val sym = denot.symbol def errMsg = BadSymbolicReference(denot) - ctx.error(errMsg, sym.pos) + ctx.error(errMsg, sym.sourcePos) if (ctx.debug) throw new scala.Error() initializeToDefaults(denot, errMsg) } @@ -2302,7 +2302,7 @@ object SymDenotations { private def resize(size: Int) = { val classIds1 = new Array[Int](size) - Array.copy(classIds, 0, classIds1, 0, classIds.length min size) + System.arraycopy(classIds, 0, classIds1, 0, classIds.length min size) classIds = classIds1 } diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 1f849ccd3e65..4876d8cf3fdb 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -70,19 +70,19 @@ object SymbolLoaders { // offer a setting to resolve the conflict one way or the other. // This was motivated by the desire to use YourKit probes, which // require yjp.jar at runtime. See SI-2089. - if (ctx.settings.YtermConflict.isDefault) - throw new TypeError( - i"""$owner contains object and package with same name: $pname - |one of them needs to be removed from classpath""") - else if (ctx.settings.YtermConflict.value == "package") { + if (ctx.settings.YtermConflict.value == "package" || ctx.mode.is(Mode.Interactive)) { ctx.warning( s"Resolving package/object name conflict in favor of package ${preExisting.fullName}. The object will be inaccessible.") owner.asClass.delete(preExisting) - } else { + } else if (ctx.settings.YtermConflict.value == "object") { ctx.warning( s"Resolving package/object name conflict in favor of object ${preExisting.fullName}. The package will be inaccessible.") return NoSymbol } + else + throw new TypeError( + i"""$owner contains object and package with same name: $pname + |one of them needs to be removed from classpath""") } ctx.newModuleSymbol(owner, pname, PackageCreationFlags, PackageCreationFlags, completer).entered @@ -134,7 +134,7 @@ object SymbolLoaders { ctx.warning(i"""$what ${tree.name} is in the wrong directory. |It was declared to be in package ${path.reverse.mkString(".")} |But it is found in directory ${filePath.reverse.mkString(File.separator)}""", - tree.pos) + tree.sourcePos) ok } @@ -159,7 +159,7 @@ object SymbolLoaders { Nil) } - val unit = new CompilationUnit(ctx.run.getSource(src.path)) + val unit = CompilationUnit(ctx.getSource(src.path)) enterScanned(unit)(ctx.run.runContext.fresh.setCompilationUnit(unit)) } } diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 616970c9d373..f5fa0ba3edd9 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -13,7 +13,7 @@ import SymDenotations._ import printing.Texts._ import printing.Printer import Types._ -import util.Positions._ +import util.Spans._ import DenotTransformers._ import StdNames._ import NameOps._ @@ -26,7 +26,7 @@ import reporting.diagnostic.Message import collection.mutable import io.AbstractFile import language.implicitConversions -import util.{NoSource, Property} +import util.{SourceFile, NoSource, Property, SourcePosition} import scala.collection.JavaConverters._ import scala.annotation.internal.sharable import config.Printers.typr @@ -43,11 +43,11 @@ trait Symbols { this: Context => * it's debug-friendlier not to create an anonymous class here. */ def newNakedSymbol[N <: Name](coord: Coord = NoCoord)(implicit ctx: Context): Symbol { type ThisName = N } = - new Symbol(coord, ctx.nextId).asInstanceOf[Symbol { type ThisName = N }] + new Symbol(coord, ctx.nextSymId).asInstanceOf[Symbol { type ThisName = N }] /** Create a class symbol without a denotation. */ def newNakedClassSymbol(coord: Coord = NoCoord, assocFile: AbstractFile = null)(implicit ctx: Context): ClassSymbol = - new ClassSymbol(coord, assocFile, ctx.nextId) + new ClassSymbol(coord, assocFile, ctx.nextSymId) // ---- Symbol creation methods ---------------------------------- @@ -212,8 +212,8 @@ trait Symbols { this: Context => /** Define a new symbol associated with a Bind or pattern wildcard and * make it gadt narrowable. */ - def newPatternBoundSymbol(name: Name, info: Type, pos: Position): Symbol = { - val sym = newSymbol(owner, name, Case, info, coord = pos) + def newPatternBoundSymbol(name: Name, info: Type, span: Span): Symbol = { + val sym = newSymbol(owner, name, Case, info, coord = span) if (name.isTypeName) { val bounds = info.bounds gadt.addBound(sym, bounds.lo, isUpper = false) @@ -415,7 +415,8 @@ object Symbols { * @param coord The coordinates of the symbol (a position or an index) * @param id A unique identifier of the symbol (unique per ContextBase) */ - class Symbol private[Symbols] (private[this] var myCoord: Coord, val id: Int) extends Designator with ParamInfo with printing.Showable { + class Symbol private[Symbols] (private[this] var myCoord: Coord, val id: Int) + extends Designator with ParamInfo with printing.Showable { type ThisName <: Name @@ -497,7 +498,7 @@ object Symbols { /** Does this symbol come from a currently compiled source file? */ final def isDefinedInCurrentRun(implicit ctx: Context): Boolean = - pos.exists && defRunId == ctx.runId && { + span.exists && defRunId == ctx.runId && { val file = associatedFile file != null && ctx.run.files.contains(file) } @@ -622,21 +623,15 @@ object Symbols { final def symbol(implicit ev: DontUseSymbolOnSymbol): Nothing = unsupported("symbol") type DontUseSymbolOnSymbol - /** The source file from which this class was generated, null if not applicable. */ - final def sourceFile(implicit ctx: Context): AbstractFile = { - val file = associatedFile - if (file != null && file.extension != "class") file - else { - val topLevelCls = denot.topLevelClass(ctx.withPhaseNoLater(ctx.flattenPhase)) - topLevelCls.getAnnotation(defn.SourceFileAnnot) match { - case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match { - case Some(Constant(path: String)) => AbstractFile.getFile(path) - case none => null - } - case none => null - } + final def source(implicit ctx: Context): SourceFile = + if (!defTree.isEmpty && !ctx.erasedTypes) defTree.source + else this match { + case cls: ClassSymbol => cls.sourceOfClass + case _ => + if (denot.is(Module)) denot.moduleClass.source + else if (denot.exists) denot.owner.source + else NoSource } - } /** A symbol related to `sym` that is defined in source code. * @@ -658,14 +653,15 @@ object Symbols { denot.owner.sourceSymbol else this - /** The position of this symbol, or NoPosition if the symbol was not loaded + /** The position of this symbol, or NoSpan if the symbol was not loaded * from source or from TASTY. This is always a zero-extent position. - * - * NOTE: If the symbol was not loaded from the current compilation unit, - * the implicit conversion `sourcePos` will return the wrong result, careful! - * TODO: Consider changing this method return type to `SourcePosition`. */ - final def pos: Position = if (coord.isPosition) coord.toPosition else NoPosition + final def span: Span = if (coord.isSpan) coord.toSpan else NoSpan + + final def sourcePos(implicit ctx: Context): SourcePosition = { + val src = source + (if (src.exists) src else ctx.source).atSpan(span) + } // ParamInfo types and methods def isTypeParam(implicit ctx: Context): Boolean = denot.is(TypeParam) @@ -764,6 +760,29 @@ object Symbols { if (assocFile != null || (this.owner is PackageClass) || this.isEffectiveRoot) assocFile else super.associatedFile + private[this] var mySource: SourceFile = NoSource + + final def sourceOfClass(implicit ctx: Context): SourceFile = { + if (!mySource.exists && !denot.is(Package)) + // this allows sources to be added in annotations after `sourceOfClass` is first called + mySource = { + val file = associatedFile + if (file != null && file.extension != "class") ctx.getSource(file) + else { + def sourceFromTopLevel(implicit ctx: Context) = + denot.topLevelClass.unforcedAnnotation(defn.SourceFileAnnot) match { + case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match { + case Some(Constant(path: String)) => ctx.getSource(path) + case none => NoSource + } + case none => NoSource + } + sourceFromTopLevel(ctx.withPhaseNoLater(ctx.flattenPhase)) + } + }//.reporting(res => i"source of $this # $id in ${denot.owner} = $res") + mySource + } + final def classDenot(implicit ctx: Context): ClassDenotation = denot.asInstanceOf[ClassDenotation] diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index aa6ce6207706..5d04517fe618 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -4,7 +4,8 @@ package core import Contexts._, Types._, Symbols._, Names._, Flags._ import SymDenotations._ -import util.Positions._ +import util.Spans._ +import util.SourcePosition import NameKinds.DepParamName import Decorators._ import StdNames._ @@ -320,7 +321,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. def dynamicsEnabled: Boolean = featureEnabled(defn.LanguageModuleClass, nme.dynamics) - def testScala2Mode(msg: => Message, pos: Position, replace: => Unit = ()): Boolean = { + def testScala2Mode(msg: => Message, pos: SourcePosition, replace: => Unit = ()): Boolean = { if (scala2Mode) { migrationWarning(msg, pos) replace diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 508794fc8a7b..8ec4e9a7a221 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -4,7 +4,7 @@ package core package classfile import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, Decorators._ -import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotations._, util.Positions._ +import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotations._, util.Spans._ import NameKinds.DefaultGetterName import dotty.tools.dotc.core.tasty.{TastyHeaderUnpickler, TastyReader} import ast.tpd._ diff --git a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala index 585d4129734a..d226d3582735 100644 --- a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala @@ -80,7 +80,7 @@ object PickledQuotes { treePkl.compactify() pickler.addrOfTree = treePkl.buf.addrOfTree pickler.addrOfSym = treePkl.addrOfSym - if (tree.pos.exists) + if (tree.span.exists) new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil) if (quotePickling ne noPrinter) @@ -128,7 +128,7 @@ object PickledQuotes { } private def functionAppliedTo(fn: Tree, args: List[Tree])(implicit ctx: Context): Tree = { - val argVals = args.map(arg => SyntheticValDef(NameKinds.UniqueName.fresh("x".toTermName), arg)) + val argVals = args.map(arg => SyntheticValDef(NameKinds.UniqueName.fresh("x".toTermName), arg).withSpan(arg.span)) def argRefs() = argVals.map(argVal => ref(argVal.symbol)) def rec(fn: Tree): Tree = fn match { case Inlined(call, bindings, expansion) => @@ -140,10 +140,10 @@ object PickledQuotes { new TreeTypeMap( oldOwners = ddef.symbol :: Nil, newOwners = ctx.owner :: Nil, - treeMap = tree => paramToVals.get(tree.symbol).map(_.withPos(tree.pos)).getOrElse(tree) + treeMap = tree => paramToVals.get(tree.symbol).map(_.withSpan(tree.span)).getOrElse(tree) ).transform(ddef.rhs) case Block(stats, expr) => - seq(stats, rec(expr)) + seq(stats, rec(expr)).withSpan(fn.span) case _ => fn.select(nme.apply).appliedToArgs(argRefs()) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/CommentPickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/CommentPickler.scala index 5fa2272d39e7..426f0194ccad 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/CommentPickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/CommentPickler.scala @@ -23,7 +23,7 @@ class CommentPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Option[Addr] buf.writeAddr(addr) buf.writeNat(length) buf.writeBytes(bytes, length) - buf.writeLongInt(cmt.pos.coords) + buf.writeLongInt(cmt.span.coords) case other => () } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/CommentUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/CommentUnpickler.scala index 0dfe01f6ea12..f3d016921a4a 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/CommentUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/CommentUnpickler.scala @@ -2,7 +2,7 @@ package dotty.tools.dotc.core.tasty import dotty.tools.dotc.core.Comments.Comment import dotty.tools.dotc.core.tasty.TastyBuffer.Addr -import dotty.tools.dotc.util.Positions.Position +import dotty.tools.dotc.util.Spans.Span import scala.collection.mutable.HashMap @@ -18,7 +18,7 @@ class CommentUnpickler(reader: TastyReader) { val length = readNat() if (length > 0) { val bytes = readBytes(length) - val position = new Position(readLongInt()) + val position = new Span(readLongInt()) val rawComment = new String(bytes, Charset.forName("UTF-8")) comments(addr) = Comment(position, rawComment) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala index 57125fed3e65..cccf6411652a 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala @@ -23,7 +23,7 @@ object DottyUnpickler { class PositionsSectionUnpickler extends SectionUnpickler[PositionUnpickler]("Positions") { def unpickle(reader: TastyReader, nameAtRef: NameTable): PositionUnpickler = - new PositionUnpickler(reader) + new PositionUnpickler(reader, nameAtRef) } class CommentsSectionUnpickler extends SectionUnpickler[CommentUnpickler]("Comments") { @@ -51,9 +51,6 @@ class DottyUnpickler(bytes: Array[Byte], mode: UnpickleMode = UnpickleMode.TopLe def enter(roots: Set[SymDenotation])(implicit ctx: Context): Unit = treeUnpickler.enter(roots) - def unpickleTypeTree()(implicit ctx: Context): Tree = - treeUnpickler.unpickleTypeTree() - protected def treeSectionUnpickler(posUnpicklerOpt: Option[PositionUnpickler], commentUnpicklerOpt: Option[CommentUnpickler]): TreeSectionUnpickler = { new TreeSectionUnpickler(posUnpicklerOpt, commentUnpicklerOpt) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala index 2af9e393500b..b563f5408ac8 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala @@ -6,11 +6,13 @@ package tasty import ast._ import ast.Trees._ import ast.Trees.WithLazyField +import util.{SourceFile, NoSource} import core._ -import Contexts._, Symbols._, Annotations._ +import Contexts._, Symbols._, Annotations._, Decorators._ import collection.mutable import TastyBuffer._ -import util.Positions._ +import util.Spans._ +import TastyFormat.SOURCE class PositionPickler(pickler: TastyPickler, addrOfTree: untpd.Tree => Option[Addr]) { val buf: TastyBuffer = new TastyBuffer(5000) @@ -26,64 +28,79 @@ class PositionPickler(pickler: TastyPickler, addrOfTree: untpd.Tree => Option[Ad def picklePositions(roots: List[Tree])(implicit ctx: Context): Unit = { var lastIndex = 0 - var lastPos = Position(0, 0) - def pickleDeltas(index: Int, pos: Position) = { + var lastSpan = Span(0, 0) + def pickleDeltas(index: Int, span: Span) = { val addrDelta = index - lastIndex - val startDelta = pos.start - lastPos.start - val endDelta = pos.end - lastPos.end - buf.writeInt(header(addrDelta, startDelta != 0, endDelta != 0, !pos.isSynthetic)) + val startDelta = span.start - lastSpan.start + val endDelta = span.end - lastSpan.end + buf.writeInt(header(addrDelta, startDelta != 0, endDelta != 0, !span.isSynthetic)) if (startDelta != 0) buf.writeInt(startDelta) if (endDelta != 0) buf.writeInt(endDelta) - if (!pos.isSynthetic) buf.writeInt(pos.pointDelta) + if (!span.isSynthetic) buf.writeInt(span.pointDelta) lastIndex = index - lastPos = pos + lastSpan = span pickledIndices += index } - /** True if x's position shouldn't be reconstructed automatically from its initialPos + def pickleSource(source: SourceFile): Unit = { + buf.writeInt(SOURCE) + buf.writeInt(pickler.nameBuffer.nameIndex(source.pathName).index) + } + + /** True if x's position shouldn't be reconstructed automatically from its initial span */ def alwaysNeedsPos(x: Positioned) = x match { case - // initialPos is inaccurate for trees with lazy field + // initialSpan is inaccurate for trees with lazy field _: WithLazyField[_] // A symbol is created before the corresponding tree is unpickled, // and its position cannot be changed afterwards. - // so we cannot use the tree initialPos to set the symbol position. + // so we cannot use the tree initialSpan to set the symbol position. // Instead, we always pickle the position of definitions. | _: Trees.DefTree[_] // package defs might be split into several Tasty files - | _: Trees.PackageDef[_] => true + | _: Trees.PackageDef[_] + // holes can change source files when filled, which means + // they might lose their position + | _: TreePickler.Hole => true case _ => false } - def traverse(x: Any): Unit = x match { + def traverse(x: Any, current: SourceFile): Unit = x match { case x: untpd.Tree => - val pos = if (x.isInstanceOf[untpd.MemberDef]) x.pos else x.pos.toSynthetic - if (pos.exists && (pos != x.initialPos.toSynthetic || alwaysNeedsPos(x))) { + if (x.span.exists) { + val sourceChange = x.source != current + val needsPos = x.span.toSynthetic != x.envelope(x.source) || alwaysNeedsPos(x) addrOfTree(x) match { - case Some(addr) if !pickledIndices.contains(addr.index) => - //println(i"pickling $x with $pos at $addr") - pickleDeltas(addr.index, pos) + case Some(addr) + if needsPos && !pickledIndices.contains(addr.index) || sourceChange => + // we currently do not share trees when unpickling, so if one path to a tree contains + // a source change while another does not, we have to record the position of the tree twice + // in order not to miss the source change. Test case is t3232a.scala. + //println(i"pickling $x with $span at $addr") + pickleDeltas(addr.index, x.span) + if (sourceChange) pickleSource(x.source) case _ => //println(i"no address for $x") } } - //else if (x.pos.exists) println(i"skipping $x") x match { case x: untpd.MemberDef @unchecked => - for (ann <- x.symbol.annotations) traverse(ann.tree) + for (ann <- x.symbol.annotations) traverse(ann.tree, x.source) case _ => } - traverse(x.productIterator) + traverse(x.productIterator, x.source) case xs: TraversableOnce[_] => - xs.foreach(traverse) + xs.foreach(traverse(_, current)) case x: Annotation => - traverse(x.tree) + traverse(x.tree, current) case _ => } - traverse(roots) + for (root <- roots) { + traverse(root, NoSource) + } } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala index 1e1031cb9e6f..ca283576886d 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala @@ -3,36 +3,61 @@ package dotc package core package tasty -import util.Positions._ +import util.Spans._ import collection.{mutable, Map} -import TastyBuffer.Addr +import TastyBuffer.{Addr, NameRef} +import TastyFormat.SOURCE +import Names.TermName /** Unpickler for tree positions */ -class PositionUnpickler(reader: TastyReader) { +class PositionUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName) { import reader._ - private[tasty] lazy val positions: Map[Addr, Position] = { - val positions = new mutable.HashMap[Addr, Position] - var curIndex = 0 - var curStart = 0 - var curEnd = 0 - while (!isAtEnd) { - val header = readInt() - val addrDelta = header >> 3 - val hasStart = (header & 4) != 0 - val hasEnd = (header & 2) != 0 - val hasPoint = (header & 1) != 0 - curIndex += addrDelta - assert(curIndex >= 0) - if (hasStart) curStart += readInt() - if (hasEnd) curEnd += readInt() - positions(Addr(curIndex)) = - if (hasPoint) Position(curStart, curEnd, curStart + readInt()) - else Position(curStart, curEnd) + private var mySpans: mutable.HashMap[Addr, Span] = _ + private var mySourcePaths: mutable.HashMap[Addr, String] = _ + private var isDefined = false + + def ensureDefined(): Unit = + if (!isDefined) { + mySpans = new mutable.HashMap[Addr, Span] + mySourcePaths = new mutable.HashMap[Addr, String] + var curIndex = 0 + var curStart = 0 + var curEnd = 0 + while (!isAtEnd) { + val header = readInt() + if (header == SOURCE) { + val path = nameAtRef(readNameRef()).toString + mySourcePaths(Addr(curIndex)) = path + } + else { + val addrDelta = header >> 3 + val hasStart = (header & 4) != 0 + val hasEnd = (header & 2) != 0 + val hasPoint = (header & 1) != 0 + curIndex += addrDelta + assert(curIndex >= 0) + if (hasStart) curStart += readInt() + if (hasEnd) curEnd += readInt() + mySpans(Addr(curIndex)) = + if (hasPoint) Span(curStart, curEnd, curStart + readInt()) + else Span(curStart, curEnd) + } + } + isDefined = true } - positions + + private[tasty] def spans: Map[Addr, Span] = { + ensureDefined() + mySpans + } + + private[tasty] def sourcePaths: Map[Addr, String] = { + ensureDefined() + mySourcePaths } - def posAt(addr: Addr): Position = positions.getOrElse(addr, NoPosition) + def spanAt(addr: Addr): Span = spans.getOrElse(addr, NoSpan) + def sourcePathAt(addr: Addr): String = sourcePaths.getOrElse(addr, "") } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala index e494b4381186..a75d1750dcbe 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala @@ -59,7 +59,7 @@ class TastyBuffer(initialSize: Int) { /** Write the first `n` bytes of `data`. */ def writeBytes(data: Array[Byte], n: Int): Unit = { while (bytes.length < length + n) bytes = dble(bytes) - Array.copy(data, 0, bytes, length, n) + System.arraycopy(data, 0, bytes, length, n) length += n } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyClassName.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyClassName.scala index ab7ead709560..6ca530997717 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyClassName.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyClassName.scala @@ -7,7 +7,7 @@ import Names.{Name, TermName} import StdNames.nme import TastyUnpickler._ import TastyBuffer.NameRef -import util.Positions.offsetToInt +import util.Spans.offsetToInt import printing.Highlighting._ /** Reads the package and class name of the class contained in this TASTy */ diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 9172fc2049e9..4f4da8d26881 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -218,14 +218,21 @@ Note: Tree tags are grouped into 5 categories that determine what follows, and t Standard Section: "Positions" Assoc* - Assoc = Header offset_Delta? offset_Delta? - Header = addr_Delta + // in one Nat: difference of address to last recorded node << 2 + - hasStartDiff + // one bit indicating whether there follows a start address delta << 1 - hasEndDiff // one bit indicating whether there follows an end address delta + Assoc = Header offset_Delta? offset_Delta? point_Delta? + | SOURCE nameref_Int + Header = addr_Delta + // in one Nat: difference of address to last recorded node << 3 + + hasStartDiff + // one bit indicating whether there follows a start address delta << 2 + hasEndDiff + // one bit indicating whether there follows an end address delta << 1 + hasPoint // one bit indicating whether the new position has a point (i.e ^ position) // Nodes which have the same positions as their parents are omitted. // offset_Deltas give difference of start/end offset wrt to the // same offset in the previously recorded node (or 0 for the first recorded node) Delta = Int // Difference between consecutive offsets, + SOURCE = 4 // Impossible as header, since addr_Delta = 0 implies that we refer to the + // same tree as the previous one, but then hasStartDiff = 1 implies that + // the tree's range starts later than the range of itself. + +All elements of a position section are serialized as Ints Standard Section: "Comments" Comment* @@ -237,7 +244,7 @@ Standard Section: "Comments" Comment* object TastyFormat { final val header: Array[Int] = Array(0x5C, 0xA1, 0xAB, 0x1F) - val MajorVersion: Int = 11 + val MajorVersion: Int = 12 val MinorVersion: Int = 0 /** Tags used to serialize names */ @@ -272,7 +279,11 @@ object TastyFormat { } object NameTags extends NameTags - // AST tags + // Position header + + final val SOURCE = 4 + + // AST tags // Cat. 1: tag final val firstSimpleTreeTag = UNITconst diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyHTMLPrinter.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyHTMLPrinter.scala index 4366ce29f76b..e6d2ea258760 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyHTMLPrinter.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyHTMLPrinter.scala @@ -6,7 +6,7 @@ import Contexts._, Decorators._ import Names.Name import TastyUnpickler._ import TastyBuffer.NameRef -import util.Positions.offsetToInt +import util.Spans.offsetToInt import printing.Highlighting._ class TastyHTMLPrinter(bytes: Array[Byte])(implicit ctx: Context) extends TastyPrinter(bytes) { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala index 22ec8bfd8c74..c9a59577a9f3 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala @@ -5,8 +5,8 @@ package tasty import Contexts._, Decorators._ import Names.Name import TastyUnpickler._ -import TastyBuffer.NameRef -import util.Positions.offsetToInt +import TastyBuffer.{Addr, NameRef} +import util.Spans.offsetToInt import printing.Highlighting._ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) { @@ -129,9 +129,9 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) { def unpickle(reader: TastyReader, tastyName: NameTable): String = { sb.append(s" ${reader.endAddr.index - reader.currentAddr.index}") - val positions = new PositionUnpickler(reader).positions + val spans = new PositionUnpickler(reader, tastyName).spans sb.append(s" position bytes:\n") - val sorted = positions.toSeq.sortBy(_._1.index) + val sorted = spans.toSeq.sortBy(_._1.index) for ((addr, pos) <- sorted) { sb.append(treeColor("%10d".format(addr.index))) sb.append(s": ${offsetToInt(pos.start)} .. ${pos.end}\n") diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala index b90546d61d47..2c4dbc4b9247 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala @@ -54,7 +54,7 @@ class TastyReader(val bytes: Array[Byte], start: Int, end: Int, val base: Int = /** Read the next `n` bytes of `data`. */ def readBytes(n: Int): Array[Byte] = { val result = new Array[Byte](n) - Array.copy(bytes, bp, result, 0, n) + System.arraycopy(bytes, bp, result, 0, n) bp += n result } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala index 8afedec37b2b..2de9a776b53b 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala @@ -137,7 +137,7 @@ class TreeBuffer extends TastyBuffer(50000) { var i = 0 var wasted = 0 def shift(end: Int) = - Array.copy(bytes, start, bytes, start - lastDelta, end - start) + System.arraycopy(bytes, start, bytes, start - lastDelta, end - start) while (i < numOffsets) { val next = offsets(i) shift(next) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 950863fa565f..2f531aa60275 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -14,12 +14,14 @@ import TastyBuffer._ import transform.SymUtils._ import printing.Printer import printing.Texts._ +import util.SourceFile +import annotation.constructorOnly object TreePickler { val sectionName = "ASTs" - case class Hole(idx: Int, args: List[tpd.Tree]) extends tpd.Tree { + case class Hole(idx: Int, args: List[tpd.Tree])(implicit @constructorOnly src: SourceFile) extends tpd.Tree { override def fallbackToText(printer: Printer): Text = s"[[$idx|" ~~ printer.toTextGlobal(args, ", ") ~~ "]]" } @@ -63,7 +65,7 @@ class TreePickler(pickler: TastyPickler) { } } - private def pickleName(name: Name): Unit = writeNat(nameIndex(name).index) + def pickleName(name: Name): Unit = writeNat(nameIndex(name).index) private def pickleNameAndSig(name: Name, sig: Signature): Unit = pickleName( @@ -78,7 +80,7 @@ class TreePickler(pickler: TastyPickler) { // I believe it's a bug in typer: the type of an implicit argument refers // to a closure parameter outside the closure itself. TODO: track this down, so that we // can eliminate this case. - ctx.log(i"pickling reference to as yet undefined $sym in ${sym.owner}", sym.pos) + ctx.log(i"pickling reference to as yet undefined $sym in ${sym.owner}", sym.sourcePos) pickleForwardSymRef(sym) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index bc8a8cc53595..f90ff942ff61 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -18,7 +18,8 @@ import Annotations._ import NameKinds._ import typer.ConstFold import typer.Checking.checkNonCyclic -import util.Positions._ +import util.Spans._ +import util.SourceFile import ast.{TreeTypeMap, Trees, tpd, untpd} import Trees._ import Decorators._ @@ -34,6 +35,7 @@ import core.quoted.PickledQuotes import scala.quoted import scala.quoted.Types.TreeType import scala.quoted.Exprs.TastyTreeExpr +import scala.annotation.constructorOnly import scala.annotation.internal.sharable /** Unpickler for typed trees @@ -93,13 +95,6 @@ class TreeUnpickler(reader: TastyReader, rdr.indexStats(reader.endAddr) } - def unpickleTypeTree()(implicit ctx: Context): Tree = { - this.roots = Set(ctx.owner) - val rdr = new TreeReader(reader).fork - ownerTree = new OwnerTree(NoAddr, 0, rdr.fork, reader.endAddr) - rdr.readTpt() - } - /** The unpickled trees */ def unpickle(mode: UnpickleMode)(implicit ctx: Context): List[Tree] = { assert(roots != null, "unpickle without previous enterTopLevel") @@ -111,12 +106,14 @@ class TreeUnpickler(reader: TastyReader, } } - class Completer(owner: Symbol, reader: TastyReader) extends LazyType { + class Completer(reader: TastyReader)(implicit @constructorOnly ctx: Context) extends LazyType { import reader._ + val owner = ctx.owner + val source = ctx.source def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { treeAtAddr(currentAddr) = new TreeReader(reader).readIndexedDef()( - ctx.withPhaseNoLater(ctx.picklerPhase).withOwner(owner)) + ctx.withPhaseNoLater(ctx.picklerPhase).withOwner(owner).withSource(source)) } } @@ -278,7 +275,7 @@ class TreeUnpickler(reader: TastyReader, def readType()(implicit ctx: Context): Type = { val start = currentAddr val tag = readByte() - pickling.println(s"reading type ${astTagToString(tag)} at $start") + pickling.println(s"reading type ${astTagToString(tag)} at $start, ${ctx.source}") def registeringType[T](tp: Type, op: => T): T = { typeAtAddr(start) = tp @@ -547,13 +544,13 @@ class TreeUnpickler(reader: TastyReader, pickling.println(i"overwriting ${rootd.symbol} # ${rootd.hashCode}") rootd.symbol.coord = coord rootd.info = adjustIfModule( - new Completer(ctx.owner, subReader(start, end)) with SymbolLoaders.SecondCompleter) + new Completer(subReader(start, end)) with SymbolLoaders.SecondCompleter) rootd.flags = flags &~ Touched // allow one more completion rootd.privateWithin = privateWithin seenRoots += rootd.symbol rootd.symbol case _ => - val completer = adjustIfModule(new Completer(ctx.owner, subReader(start, end))) + val completer = adjustIfModule(new Completer(subReader(start, end))) if (isClass) ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer, privateWithin, coord) else @@ -571,7 +568,8 @@ class TreeUnpickler(reader: TastyReader, } else if (sym.isInlineMethod) sym.addAnnotation(LazyBodyAnnotation { ctx0 => - implicit val ctx: Context = localContext(sym)(ctx0).addMode(Mode.ReadPositions) + val ctx1 = localContext(sym)(ctx0).addMode(Mode.ReadPositions) + implicit val ctx: Context = sourceChangeContext(Addr(0))(ctx1) // avoids space leaks by not capturing the current context forkAt(rhsStart).readTerm() }) @@ -696,9 +694,11 @@ class TreeUnpickler(reader: TastyReader, /** Process package with given operation `op`. The operation takes as arguments * - a `RefTree` representing the `pid` of the package, * - an end address, - * - a context which has the processd package as owner + * - a context which has the processed package as owner */ def processPackage[T](op: (RefTree, Addr) => Context => T)(implicit ctx: Context): T = { + val sctx = sourceChangeContext() + if (sctx `ne` ctx) return processPackage(op)(sctx) readByte() val end = readEnd() val pid = ref(readTermRef()).asInstanceOf[RefTree] @@ -741,6 +741,8 @@ class TreeUnpickler(reader: TastyReader, } private def readNewDef()(implicit ctx: Context): Tree = { + val sctx = sourceChangeContext() + if (sctx `ne` ctx) return readNewDef()(sctx) val start = currentAddr val sym = symAtAddr(start) val tag = readByte() @@ -845,9 +847,9 @@ class TreeUnpickler(reader: TastyReader, // Note: Once the inline PR with its changes to positions is in, this should be // no longer necessary. goto(end) - setPos(start, tree) + setSpan(start, tree) if (!sym.isType) { // Only terms might have leaky aliases, see the documentation of `checkNoPrivateLeaks` - sym.info = ta.avoidPrivateLeaks(sym, tree.pos) + sym.info = ta.avoidPrivateLeaks(sym, tree.sourcePos) } sym.defTree = tree @@ -866,6 +868,7 @@ class TreeUnpickler(reader: TastyReader, private def readTemplate(implicit ctx: Context): Template = { val start = currentAddr + assert(sourcePathAt(start).isEmpty) val cls = ctx.owner.asClass val assumedSelfType = if (cls.is(Module) && cls.owner.isClass) TermRef(cls.owner.thisType, cls.name.sourceModuleName) @@ -908,7 +911,7 @@ class TreeUnpickler(reader: TastyReader, val stats = rdr.readIndexedStats(localDummy, end) tparams ++ vparams ++ stats }) - setPos(start, + setSpan(start, untpd.Template(constr, mappedParents, self, lazyStats) .withType(localDummy.termRef)) } @@ -943,7 +946,7 @@ class TreeUnpickler(reader: TastyReader, case PACKAGE => val start = currentAddr processPackage { (pid, end) => implicit ctx => - setPos(start, PackageDef(pid, readIndexedStats(exprOwner, end)(ctx))) + setSpan(start, PackageDef(pid, readIndexedStats(exprOwner, end)(ctx))) } case _ => readTerm()(ctx.withOwner(exprOwner)) @@ -951,22 +954,24 @@ class TreeUnpickler(reader: TastyReader, def readImport()(implicit ctx: Context): Tree = { val start = currentAddr + assert(sourcePathAt(start).isEmpty) readByte() readEnd() val expr = readTerm() - setPos(start, Import(expr, readSelectors())) + setSpan(start, Import(expr, readSelectors())) } def readSelectors()(implicit ctx: Context): List[untpd.Tree] = nextByte match { case IMPORTED => val start = currentAddr + assert(sourcePathAt(start).isEmpty) readByte() - val from = setPos(start, untpd.Ident(readName())) + val from = setSpan(start, untpd.Ident(readName())) nextByte match { case RENAMED => val start2 = currentAddr readByte() - val to = setPos(start2, untpd.Ident(readName())) + val to = setSpan(start2, untpd.Ident(readName())) untpd.Thicket(from, to) :: readSelectors() case _ => from :: readSelectors() @@ -994,9 +999,11 @@ class TreeUnpickler(reader: TastyReader, // ------ Reading trees ----------------------------------------------------- def readTerm()(implicit ctx: Context): Tree = { // TODO: rename to readTree + val sctx = sourceChangeContext() + if (sctx `ne` ctx) return readTerm()(sctx) val start = currentAddr val tag = readByte() - pickling.println(s"reading term ${astTagToString(tag)} at $start") + pickling.println(s"reading term ${astTagToString(tag)} at $start, ${ctx.source}") def readPathTerm(): Tree = { goto(start) @@ -1017,7 +1024,7 @@ class TreeUnpickler(reader: TastyReader, def readQualId(): (untpd.Ident, TypeRef) = { val qual = readTerm().asInstanceOf[untpd.Ident] - (untpd.Ident(qual.name).withPos(qual.pos), qual.tpe.asInstanceOf[TypeRef]) + (untpd.Ident(qual.name).withSpan(qual.span), qual.tpe.asInstanceOf[TypeRef]) } def accessibleDenot(pre: Type, name: Name, sig: Signature) = { @@ -1195,11 +1202,14 @@ class TreeUnpickler(reader: TastyReader, val tree = if (tag < firstLengthTreeTag) readSimpleTerm() else readLengthTerm() if (!tree.isInstanceOf[TypTree]) // FIXME: Necessary to avoid self-type cyclic reference in tasty_tools tree.overwriteType(tree.tpe.simplified) - setPos(start, tree) + setSpan(start, tree) } def readTpt()(implicit ctx: Context): Tree = { - nextByte match { + val sctx = sourceChangeContext() + if (sctx `ne` ctx) return readTpt()(sctx) + val start = currentAddr + val tree = nextByte match { case SHAREDterm => readByte() forkAt(readAddr()).readTpt() @@ -1220,9 +1230,10 @@ class TreeUnpickler(reader: TastyReader, else { val start = currentAddr val tp = readType() - if (tp.exists) setPos(start, TypeTree(tp)) else EmptyTree + if (tp.exists) setSpan(start, TypeTree(tp)) else EmptyTree } } + setSpan(start, tree) } def readCases(end: Addr)(implicit ctx: Context): List[CaseDef] = @@ -1235,13 +1246,15 @@ class TreeUnpickler(reader: TastyReader, } def readCase()(implicit ctx: Context): CaseDef = { + val sctx = sourceChangeContext() + if (sctx `ne` ctx) return readCase()(sctx) val start = currentAddr assert(readByte() == CASEDEF) val end = readEnd() val pat = readTerm() val rhs = readTerm() val guard = ifBefore(end)(readTerm(), EmptyTree) - setPos(start, CaseDef(pat, guard, rhs)) + setSpan(start, CaseDef(pat, guard, rhs)) } def readLater[T <: AnyRef](end: Addr, op: TreeReader => Context => T)(implicit ctx: Context): Trees.Lazy[T] = @@ -1250,7 +1263,7 @@ class TreeUnpickler(reader: TastyReader, def readLaterWithOwner[T <: AnyRef](end: Addr, op: TreeReader => Context => T)(implicit ctx: Context): Symbol => Trees.Lazy[T] = { val localReader = fork goto(end) - owner => new LazyReader(localReader, owner, ctx.mode, op) + owner => new LazyReader(localReader, owner, ctx.mode, ctx.source, op) } def readHole(end: Addr, isType: Boolean)(implicit ctx: Context): Tree = { @@ -1261,49 +1274,88 @@ class TreeUnpickler(reader: TastyReader, if (arg.isTerm) new TastyTreeExpr(arg) else new TreeType(arg) val reifiedArgs = args.map(wrap) - if (isType) { + val filled = if (isType) { val quotedType = splice.asInstanceOf[Seq[Any] => quoted.Type[_]](reifiedArgs) PickledQuotes.quotedTypeToTree(quotedType) } else { val quotedExpr = splice.asInstanceOf[Seq[Any] => quoted.Expr[_]](reifiedArgs) PickledQuotes.quotedExprToTree(quotedExpr) } + // We need to make sure a hole is created with the source file of the surrounding context, even if + // it filled with contents a different source file. Otherwise nodes containing holes might end + // up without a position. PositionPickler makes sure that holes always get spans assigned, + // so we can just return the filler tree with the new source and no span here. + if (filled.source == ctx.source) filled + else { + val filled1 = filled.cloneIn(ctx.source) + filled1.span = NoSpan + filled1 + } } // ------ Setting positions ------------------------------------------------ - /** Pickled position for `addr`. */ - def posAt(addr: Addr)(implicit ctx: Context): Position = + /** Pickled span for `addr`. */ + def spanAt(addr: Addr)(implicit ctx: Context): Span = if (ctx.mode.is(Mode.ReadPositions)) { posUnpicklerOpt match { case Some(posUnpickler) => - posUnpickler.posAt(addr) + posUnpickler.spanAt(addr) case _ => - NoPosition + NoSpan } - } else NoPosition + } else NoSpan /** Coordinate for the symbol at `addr`. */ def coordAt(addr: Addr)(implicit ctx: Context): Coord = { - val pos = posAt(addr) - if (pos.exists) - positionCoord(pos) + val span = spanAt(addr) + if (span.exists) + spanCoord(span) else indexCoord(addr.index) } + /** Pickled source path at `addr`. */ + def sourcePathAt(addr: Addr)(implicit ctx: Context): String = + if (ctx.mode.is(Mode.ReadPositions)) { + posUnpicklerOpt match { + case Some(posUnpickler) => + posUnpickler.sourcePathAt(addr) + case _ => + "" + } + } else "" + + /** If currentAddr carries a source path, the current context with + * the source of that path, otherwise the current context itself. + */ + def sourceChangeContext(addr: Addr = currentAddr)(implicit ctx: Context): Context = { + val path = sourcePathAt(addr) + if (path.nonEmpty) { + pickling.println(i"source change at $addr: $path") + ctx.withSource(ctx.getSource(path)) + } + else ctx + } + /** Set position of `tree` at given `addr`. */ - def setPos[T <: untpd.Tree](addr: Addr, tree: T)(implicit ctx: Context): tree.type = { - val pos = posAt(addr) - if (pos.exists) tree.setPosUnchecked(pos) + def setSpan[T <: untpd.Tree](addr: Addr, tree: T)(implicit ctx: Context): tree.type = { + val span = spanAt(addr) + if (span.exists) tree.span = span tree } } - class LazyReader[T <: AnyRef](reader: TreeReader, owner: Symbol, mode: Mode, op: TreeReader => Context => T) extends Trees.Lazy[T] { + class LazyReader[T <: AnyRef]( + reader: TreeReader, owner: Symbol, mode: Mode, source: SourceFile, + op: TreeReader => Context => T) extends Trees.Lazy[T] { def complete(implicit ctx: Context): T = { pickling.println(i"starting to read at ${reader.reader.currentAddr} with owner $owner") - op(reader)(ctx.withPhaseNoLater(ctx.picklerPhase).withOwner(owner).withModeBits(mode)) + op(reader)(ctx + .withPhaseNoLater(ctx.picklerPhase) + .withOwner(owner) + .withModeBits(mode) + .withSource(source)) } } @@ -1385,7 +1437,7 @@ object TreeUnpickler { } /** A marker value used to detect cyclic reference while unpickling definitions. */ - @sharable val PoisonTree: tpd.Tree = Thicket(Nil) + @sharable val PoisonTree: tpd.Tree = new EmptyTree /** An enumeration indicating which subtrees should be added to an OwnerTree. */ type MemberDefMode = Int diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala index f96d3348ec11..b136447c4e1c 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala @@ -20,7 +20,7 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) { /** Double bytes array */ private def dble(): Unit = { val bytes1 = new Array[Byte](bytes.length * 2) - Array.copy(bytes, 0, bytes1, 0, writeIndex) + System.arraycopy(bytes, 0, bytes1, 0, writeIndex) bytes = bytes1 } @@ -69,7 +69,7 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) { def patchNat(pos: Int, x: Int): Unit = { def patchNatPrefix(x: Int): Unit = { writeByte(0) - Array.copy(bytes, pos, bytes, pos + 1, writeIndex - (pos + 1)) + System.arraycopy(bytes, pos, bytes, pos + 1, writeIndex - (pos + 1)) bytes(pos) = ((x & 0x7f) | 0x80).toByte val y = x >>> 7 if (y != 0) patchNatPrefix(y) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index d1297623da83..fd02618c3111 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -10,7 +10,7 @@ import java.lang.Double.longBitsToDouble import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._ import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._ import NameKinds.{Scala2MethodNameKinds, SuperAccessorName, ExpandedName} -import util.Positions._ +import util.Spans._ import dotty.tools.dotc.ast.{tpd, untpd}, ast.tpd._ import ast.untpd.Modifiers import printing.Texts._ @@ -984,7 +984,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas symbol = readSymbolRef() } - implicit val pos: Position = NoPosition + implicit val span: Span = NoSpan tag match { case EMPTYtree => diff --git a/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala b/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala index 13fac7bbc19d..a44d3ad6b38a 100644 --- a/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala +++ b/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala @@ -9,7 +9,6 @@ import Symbols.{Symbol, ClassSymbol} import SymDenotations.ClassDenotation import NameOps._ import ast.Trees.Tree -import CompilationUnit.mkCompilationUnit import Phases.Phase @@ -44,7 +43,7 @@ class ReadTasty extends Phase { case unpickler: tasty.DottyUnpickler => if (cls.rootTree.isEmpty) None else { - val unit = mkCompilationUnit(cls, cls.rootTree, forceTrees = true) + val unit = CompilationUnit(cls, cls.rootTree, forceTrees = true) unit.pickled += (cls -> unpickler.unpickler.bytes) Some(unit) } diff --git a/compiler/src/dotty/tools/dotc/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala index 5060aae3d2fb..c48ef40fa6b8 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala @@ -40,7 +40,7 @@ object Completion { * @return offset and list of symbols for possible completions */ def completions(pos: SourcePosition)(implicit ctx: Context): (Int, List[Completion]) = { - val path = Interactive.pathTo(ctx.compilationUnit.tpdTree, pos.pos) + val path = Interactive.pathTo(ctx.compilationUnit.tpdTree, pos.span) computeCompletions(pos, path)(Interactive.contextOfPath(path)) } @@ -62,7 +62,7 @@ object Completion { else Mode.None case Thicket(name :: _ :: Nil) :: (_: Import) :: _ => - if (name.pos.contains(pos.pos)) Mode.Import + if (name.span.contains(pos.span)) Mode.Import else Mode.None // Can't help completing the renaming case Import(_, _) :: _ => @@ -83,13 +83,13 @@ object Completion { completionPrefix(name :: Nil, pos) case Import(expr, selectors) :: _ => - selectors.find(_.pos.contains(pos.pos)).map { selector => + selectors.find(_.span.contains(pos.span)).map { selector => completionPrefix(selector.asInstanceOf[Tree] :: Nil, pos) }.getOrElse("") case (ref: RefTree) :: _ => if (ref.name == nme.ERROR) "" - else ref.name.toString.take(pos.pos.point - ref.pos.point) + else ref.name.toString.take(pos.span.point - ref.span.point) case _ => "" @@ -99,7 +99,7 @@ object Completion { /** Inspect `path` to determine the offset where the completion result should be inserted. */ private def completionOffset(path: List[Tree]): Int = { path match { - case (ref: RefTree) :: _ => ref.pos.point + case (ref: RefTree) :: _ => ref.span.point case _ => 0 } } @@ -313,7 +313,7 @@ object Completion { */ private def implicitConversionTargets(qual: Tree)(implicit ctx: Context): Set[Type] = { val typer = ctx.typer - val conversions = new typer.ImplicitSearch(defn.AnyType, qual, pos.pos).allImplicits + val conversions = new typer.ImplicitSearch(defn.AnyType, qual, pos.span).allImplicits val targets = conversions.map(_.widen.finalResultType) interactiv.println(i"implicit conversion targets considered: ${targets.toList}%, %") targets diff --git a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala index 797bf77f1e8e..6f9561f4d393 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala @@ -6,10 +6,10 @@ import scala.annotation.tailrec import scala.collection._ import ast.{NavigateAST, Trees, tpd, untpd} -import core._, core.Decorators.{sourcePos => _, _} +import core._, core.Decorators._ import Contexts._, Flags._, Names._, NameOps._, Symbols._, Trees._, Types._ import transform.SymUtils.decorateSymbol -import util.Positions._, util.SourceFile, util.SourcePosition +import util.Spans._, util.SourceFile, util.SourcePosition import core.Denotations.SingleDenotation import NameKinds.SimpleNameKind import config.Printers.interactiv @@ -121,10 +121,10 @@ object Interactive { List(select.symbol) case (_: Thicket) :: (imp: Import) :: _ => - importedSymbols(imp, _.pos.contains(pos.pos)) + importedSymbols(imp, _.span.contains(pos.span)) case (imp: Import) :: _ => - importedSymbols(imp, _.pos.contains(pos.pos)) + importedSymbols(imp, _.span.contains(pos.span)) case _ => List(enclosingTree(path).symbol) @@ -186,8 +186,8 @@ object Interactive { if (tree.symbol.exists && !tree.symbol.is(Synthetic) && !tree.symbol.isPrimaryConstructor - && tree.pos.exists - && !tree.pos.isZeroExtent + && tree.span.exists + && !tree.span.isZeroExtent && (include.isReferences || isDefinition(tree)) && treePredicate(tree)) buf += SourceTree(tree, source) @@ -252,13 +252,13 @@ object Interactive { */ def pathTo(trees: List[SourceTree], pos: SourcePosition)(implicit ctx: Context): List[Tree] = trees.find(_.pos.contains(pos)) match { - case Some(tree) => pathTo(tree.tree, pos.pos) + case Some(tree) => pathTo(tree.tree, pos.span) case None => Nil } - def pathTo(tree: Tree, pos: Position)(implicit ctx: Context): List[Tree] = - if (tree.pos.contains(pos)) - NavigateAST.pathTo(pos, tree, skipZeroExtent = true) + def pathTo(tree: Tree, span: Span)(implicit ctx: Context): List[Tree] = + if (tree.span.contains(span)) + NavigateAST.pathTo(span, tree, skipZeroExtent = true) .collect { case t: untpd.Tree => t } .dropWhile(!_.hasType).asInstanceOf[List[tpd.Tree]] else Nil diff --git a/compiler/src/dotty/tools/dotc/interactive/SourceTree.scala b/compiler/src/dotty/tools/dotc/interactive/SourceTree.scala index 3c8a51617723..f7cfb0ec155e 100644 --- a/compiler/src/dotty/tools/dotc/interactive/SourceTree.scala +++ b/compiler/src/dotty/tools/dotc/interactive/SourceTree.scala @@ -5,9 +5,9 @@ package interactive import scala.io.Codec import ast.tpd -import core._, core.Decorators.{sourcePos => _} +import core._ import Contexts._, NameOps._, Symbols._, StdNames._ -import util._, util.Positions._ +import util._, util.Spans._ /** * A `tree` coming from `source` @@ -17,14 +17,14 @@ import util._, util.Positions._ case class SourceTree(tree: tpd.Tree /** really: tpd.Import | tpd.NameTree */, source: SourceFile) { /** The position of `tree` */ - final def pos(implicit ctx: Context): SourcePosition = source.atPos(tree.pos) + final def pos(implicit ctx: Context): SourcePosition = source.atSpan(tree.span) /** The position of the name in `tree` */ def namePos(implicit ctx: Context): SourcePosition = tree match { case tree: tpd.NameTree => // FIXME: Merge with NameTree#namePos ? - val treePos = tree.pos - if (treePos.isZeroExtent || tree.name.toTermName == nme.ERROR) + val treeSpan = tree.span + if (treeSpan.isZeroExtent || tree.name.toTermName == nme.ERROR) NoSourcePosition else { // Constructors are named `` in the trees, but `this` in the source. @@ -36,14 +36,14 @@ case class SourceTree(tree: tpd.Tree /** really: tpd.Import | tpd.NameTree */, s // FIXME: This is incorrect in some cases, like with backquoted identifiers, // see https://github.com/lampepfl/dotty/pull/1634#issuecomment-257079436 val (start, end) = - if (!treePos.isSynthetic) - (treePos.point, treePos.point + nameLength) + if (!treeSpan.isSynthetic) + (treeSpan.point, treeSpan.point + nameLength) else // If we don't have a point, we need to find it - (treePos.end - nameLength, treePos.end) - Position(start, end, start) + (treeSpan.end - nameLength, treeSpan.end) + Span(start, end, start) } - source.atPos(position) + source.atSpan(position) } case _ => NoSourcePosition @@ -53,7 +53,7 @@ case class SourceTree(tree: tpd.Tree /** really: tpd.Import | tpd.NameTree */, s object SourceTree { def fromSymbol(sym: ClassSymbol, id: String = "")(implicit ctx: Context): List[SourceTree] = { if (sym == defn.SourceFileAnnot || // FIXME: No SourceFile annotation on SourceFile itself - sym.sourceFile == null) // FIXME: We cannot deal with external projects yet + !sym.source.exists) // FIXME: We cannot deal with external projects yet Nil else { import ast.Trees._ @@ -61,8 +61,7 @@ object SourceTree { case PackageDef(_, stats) => stats.flatMap(sourceTreeOfClass).headOption case tree: tpd.TypeDef if tree.symbol == sym => - val sourceFile = ctx.getSource(sym.sourceFile, Codec.UTF8) - Some(SourceTree(tree, sourceFile)) + Some(SourceTree(tree, sym.source)) case _ => None } diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index e16d27ce06af..d1ad08e251ff 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -21,7 +21,7 @@ import Decorators._ import StdNames._ import dotty.tools.dotc.reporting.diagnostic.messages.IdentifierExpected import dotty.tools.dotc.util.SourceFile -import util.Positions._ +import util.Spans._ import scala.collection.mutable.ListBuffer object JavaParsers { @@ -77,9 +77,9 @@ object JavaParsers { syntaxError(in.offset, msg, skipIt) } - def syntaxError(pos: Int, msg: String, skipIt: Boolean): Unit = { - if (pos > lastErrorOffset) { - syntaxError(msg, pos) + def syntaxError(offset: Int, msg: String, skipIt: Boolean): Unit = { + if (offset > lastErrorOffset) { + syntaxError(msg, offset) // no more errors on this token. lastErrorOffset = in.offset } @@ -87,7 +87,7 @@ object JavaParsers { skip() } - def errorTypeTree: TypeTree = TypeTree().withType(UnspecifiedErrorType) withPos Position(in.offset) + def errorTypeTree: TypeTree = TypeTree().withType(UnspecifiedErrorType).withSpan(Span(in.offset)) // --------- tree building ----------------------------- @@ -225,12 +225,12 @@ object JavaParsers { /** Convert (qual)ident to type identifier */ def convertToTypeId(tree: Tree): Tree = convertToTypeName(tree) match { - case Some(t) => t withPos tree.pos + case Some(t) => t.withSpan(tree.span) case _ => tree match { case AppliedTypeTree(_, _) | Select(_, _) => tree case _ => - syntaxError(IdentifierExpected(tree.show), tree.pos) + syntaxError(IdentifierExpected(tree.show), tree.span) errorTypeTree } } @@ -245,24 +245,24 @@ object JavaParsers { // -------------------- specific parsing routines ------------------ def qualId(): RefTree = { - var t: RefTree = atPos(in.offset) { Ident(ident()) } + var t: RefTree = atSpan(in.offset) { Ident(ident()) } while (in.token == DOT) { in.nextToken() - t = atPos(t.pos.start, in.offset) { Select(t, ident()) } + t = atSpan(t.span.start, in.offset) { Select(t, ident()) } } t } def optArrayBrackets(tpt: Tree): Tree = if (in.token == LBRACKET) { - val tpt1 = atPos(tpt.pos.start, in.offset) { arrayOf(tpt) } + val tpt1 = atSpan(tpt.span.start, in.offset) { arrayOf(tpt) } in.nextToken() accept(RBRACKET) optArrayBrackets(tpt1) } else tpt def basicType(): Tree = - atPos(in.offset) { + atSpan(in.offset) { in.token match { case BYTE => in.nextToken(); TypeTree(ByteType) case SHORT => in.nextToken(); TypeTree(ShortType) @@ -280,7 +280,7 @@ object JavaParsers { optArrayBrackets { if (in.token == FINAL) in.nextToken() if (in.token == IDENTIFIER) { - var t = typeArgs(atPos(in.offset)(Ident(ident()))) + var t = typeArgs(atSpan(in.offset)(Ident(ident()))) // typeSelect generates Select nodes if the lhs is an Ident or Select, // For other nodes it always assumes that the selected item is a type. def typeSelect(t: Tree, name: Name) = t match { @@ -289,7 +289,7 @@ object JavaParsers { } while (in.token == DOT) { in.nextToken() - t = typeArgs(atPos(t.pos.start, in.offset)(typeSelect(t, ident()))) + t = typeArgs(atSpan(t.span.start, in.offset)(typeSelect(t, ident()))) } convertToTypeId(t) } else { @@ -305,7 +305,7 @@ object JavaParsers { in.nextToken() val hi = if (in.token == EXTENDS) { in.nextToken() ; typ() } else EmptyTree val lo = if (in.token == SUPER) { in.nextToken() ; typ() } else EmptyTree - atPos(offset) { + atSpan(offset) { /* TypeDef( Modifiers(Flags.JavaDefined | Flags.Deferred), @@ -323,7 +323,7 @@ object JavaParsers { val t1 = convertToTypeId(t) val args = repsep(() => typeArg(), COMMA) acceptClosingAngle() - atPos(t1.pos.start) { + atSpan(t1.span.start) { AppliedTypeTree(t1, args) } } else t @@ -352,7 +352,7 @@ object JavaParsers { var isPackageAccess = true var annots: List[Tree] = Nil def addAnnot(sym: ClassSymbol) = - annots :+= atPos(in.offset) { + annots :+= atSpan(in.offset) { in.nextToken() New(TypeTree(sym.typeRef)) } @@ -413,14 +413,14 @@ object JavaParsers { } else List() def typeParam(flags: FlagSet): TypeDef = - atPos(in.offset) { + atSpan(in.offset) { val name = identForType() val hi = if (in.token == EXTENDS) { in.nextToken() ; bound() } else EmptyTree TypeDef(name, TypeBoundsTree(EmptyTree, hi)).withMods(Modifiers(flags)) } def bound(): Tree = - atPos(in.offset) { + atSpan(in.offset) { val buf = ListBuffer[Tree](typ()) while (in.token == AMP) { in.nextToken() @@ -445,11 +445,11 @@ object JavaParsers { var t = typ() if (in.token == DOTDOTDOT) { in.nextToken() - t = atPos(t.pos.start) { + t = atSpan(t.span.start) { PostfixOp(t, Ident(tpnme.raw.STAR)) } } - atPos(start, in.offset) { + atSpan(start, in.offset) { varDecl(Modifiers(Flags.JavaDefined | Flags.Param), t, ident().toTermName) } } @@ -461,7 +461,7 @@ object JavaParsers { } } - def methodBody(): Tree = atPos(in.offset) { + def methodBody(): Tree = atSpan(in.offset) { skipAhead() accept(RBRACE) // skip block unimplementedExpr @@ -475,7 +475,7 @@ object JavaParsers { val isVoid = in.token == VOID var rtpt = if (isVoid) - atPos(in.offset) { + atSpan(in.offset) { in.nextToken() TypeTree(UnitType) } @@ -490,7 +490,7 @@ object JavaParsers { val vparams = formalParams() optThrows() List { - atPos(start) { + atSpan(start) { DefDef(nme.CONSTRUCTOR, parentTParams, List(vparams), TypeTree(), methodBody()).withMods(mods) } @@ -512,7 +512,7 @@ object JavaParsers { } else { if (parentToken == AT && in.token == DEFAULT) { val annot = - atPos(nameOffset) { + atSpan(nameOffset) { New(Select(Select(scalaDot(nme.annotation), nme.internal), tpnme.AnnotationDefaultATTR), Nil) } mods1 = mods1 withAddedAnnotation annot @@ -527,7 +527,7 @@ object JavaParsers { } //if (inInterface) mods1 |= Flags.Deferred List { - atPos(start, nameOffset) { + atSpan(start, nameOffset) { DefDef(name.toTermName, tparams, List(vparams), rtpt, body).withMods(mods1 | Flags.Method) } } @@ -551,7 +551,7 @@ object JavaParsers { */ 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) }) + atSpan(start, firstNameOffset) { varDecl(mods, tpt, name.toTermName) }) val maybe = new ListBuffer[Tree] // potential variable definitions. while (in.token == COMMA) { in.nextToken() @@ -560,10 +560,10 @@ object JavaParsers { 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 += atPos(start, nextNameOffset) { varDecl(mods, tpt, name.toTermName) } + buf += atSpan(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 += atPos(start, nextNameOffset) { varDecl(mods, tpt, name.toTermName) } + maybe += atSpan(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) @@ -596,14 +596,14 @@ object JavaParsers { } def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree = - atPos(cdef.pos) { - assert(cdef.pos.exists) + atSpan(cdef.span) { + assert(cdef.span.exists) ModuleDef(cdef.name.toTermName, makeTemplate(List(), statics, List(), false)).withMods((cdef.mods & Flags.RetainedModuleClassFlags).toTermFlags) } def importCompanionObject(cdef: TypeDef): Tree = - Import(Ident(cdef.name.toTermName).withPos(NoPosition), Ident(nme.WILDCARD) :: Nil) + Import(Ident(cdef.name.toTermName).withSpan(NoSpan), Ident(nme.WILDCARD) :: Nil) // Importing the companion object members cannot be done uncritically: see // ticket #2377 wherein a class contains two static inner classes, each of which @@ -660,12 +660,12 @@ object JavaParsers { } else { val qual = ((Ident(names.head): Tree) /: names.tail.init) (Select(_, _)) val lastname = names.last - val ident = Ident(lastname) withPos Position(lastnameOffset) + val ident = Ident(lastname).withSpan(Span(lastnameOffset)) // val selector = lastname match { -// case nme.WILDCARD => Pair(ident, Ident(null) withPos Position(-1)) +// case nme.WILDCARD => Pair(ident, Ident(null) withPos Span(-1)) // case _ => Pair(ident, ident) // } - val imp = atPos(start) { Import(qual, List(ident)) } + val imp = atSpan(start) { Import(qual, List(ident)) } imp :: Nil } } @@ -692,7 +692,7 @@ object JavaParsers { } val interfaces = interfacesOpt() val (statics, body) = typeBody(CLASS, name, tparams) - val cls = atPos(start, nameOffset) { + val cls = atSpan(start, nameOffset) { TypeDef(name, makeTemplate(superclass :: interfaces, body, tparams, true)).withMods(mods) } addCompanionObject(statics, cls) @@ -711,7 +711,7 @@ object JavaParsers { List(javaLangObject()) } val (statics, body) = typeBody(INTERFACE, name, tparams) - val iface = atPos(start, nameOffset) { + val iface = atSpan(start, nameOffset) { TypeDef( name, makeTemplate(parents, body, tparams, false)).withMods(mods | Flags.Trait | Flags.JavaInterface | Flags.Abstract) @@ -732,7 +732,7 @@ object JavaParsers { val members = new ListBuffer[Tree] while (in.token != RBRACE && in.token != EOF) { val start = in.offset - var mods = atPos(start) { modifiers(inInterface) } + var mods = modifiers(inInterface) if (in.token == LBRACE) { skipAhead() // skip init block, we just assume we have seen only static accept(RBRACE) @@ -786,7 +786,7 @@ object JavaParsers { val constr = DefDef(nme.CONSTRUCTOR, List(), List(constructorParams), TypeTree(), EmptyTree).withMods(Modifiers(Flags.JavaDefined)) val templ = makeTemplate(annotationParents, constr :: body, List(), true) - val annot = atPos(start, nameOffset) { + val annot = atSpan(start, nameOffset) { TypeDef(name, templ).withMods(mods | Flags.Abstract) } addCompanionObject(statics, annot) @@ -837,7 +837,7 @@ object JavaParsers { val superclazz = Apply(TypeApply( Select(New(javaLangDot(tpnme.Enum)), nme.CONSTRUCTOR), List(enumType)), List(Literal(Constant(null)),Literal(Constant(0)))) - val enumclazz = atPos(start, nameOffset) { + val enumclazz = atSpan(start, nameOffset) { TypeDef(name, makeTemplate(superclazz :: interfaces, body, List(), true)).withMods(mods | Flags.JavaEnum) } @@ -846,7 +846,7 @@ object JavaParsers { def enumConst(enumType: Tree): ValDef = { annotations() - atPos(in.offset) { + atSpan(in.offset) { val name = ident() if (in.token == LPAREN) { // skip arguments @@ -895,11 +895,11 @@ object JavaParsers { while (in.token == SEMI) in.nextToken() if (in.token != EOF) { val start = in.offset - val mods = atPos(start) { modifiers(inInterface = false) } + val mods = modifiers(inInterface = false) buf ++= typeDecl(start, mods) } } - val unit = atPos(start) { PackageDef(pkg, buf.toList) } + val unit = atSpan(start) { PackageDef(pkg, buf.toList) } accept(EOF) unit } diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index c62e47c0ad44..35011a34b75a 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -17,7 +17,7 @@ import NameKinds.WildcardParamName import ast.{Positioned, Trees} import ast.Trees._ import StdNames._ -import util.Positions._ +import util.Spans._ import Constants._ import ScriptParsers._ import Decorators._ @@ -69,41 +69,41 @@ object Parsers { /* ------------- POSITIONS ------------------------------------------- */ /** Positions tree. - * If `t` does not have a position yet, set its position to the given one. + * If `t` does not have a span yet, set its span to the given one. */ - def atPos[T <: Positioned](pos: Position)(t: T): T = - if (t.pos.isSourceDerived) t else t.withPos(pos) + def atSpan[T <: Positioned](span: Span)(t: T): T = + if (t.span.isSourceDerived) t else t.withSpan(span) - def atPos[T <: Positioned](start: Offset, point: Offset, end: Offset)(t: T): T = - atPos(Position(start, end, point))(t) + def atSpan[T <: Positioned](start: Offset, point: Offset, end: Offset)(t: T): T = + atSpan(Span(start, end, point))(t) - /** If the last read offset is strictly greater than `start`, position tree - * to position spanning from `start` to last read offset, with given point. + /** If the last read offset is strictly greater than `start`, assign tree + * the span from `start` to last read offset, with given point. * If the last offset is less than or equal to start, the tree `t` did not - * consume any source for its construction. In this case, don't position it yet, - * but wait for its position to be determined by `setChildPositions` when the + * consume any source for its construction. In this case, don't assign a span yet, + * but wait for its span to be determined by `setChildSpans` when the * parent node is positioned. */ - def atPos[T <: Positioned](start: Offset, point: Offset)(t: T): T = - if (in.lastOffset > start) atPos(start, point, in.lastOffset)(t) else t + def atSpan[T <: Positioned](start: Offset, point: Offset)(t: T): T = + if (in.lastOffset > start) atSpan(start, point, in.lastOffset)(t) else t - def atPos[T <: Positioned](start: Offset)(t: T): T = - atPos(start, start)(t) + def atSpan[T <: Positioned](start: Offset)(t: T): T = + atSpan(start, start)(t) def startOffset(t: Positioned): Int = - if (t.pos.exists) t.pos.start else in.offset + if (t.span.exists) t.span.start else in.offset def pointOffset(t: Positioned): Int = - if (t.pos.exists) t.pos.point else in.offset + if (t.span.exists) t.span.point else in.offset def endOffset(t: Positioned): Int = - if (t.pos.exists) t.pos.end else in.lastOffset + if (t.span.exists) t.span.end else in.lastOffset 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) + source.atSpan(Span(off)) /** in.offset, except if this is at a new line, in which case `lastOffset` is preferred. */ def expectedOffset: Int = { @@ -124,15 +124,15 @@ object Parsers { def syntaxError(msg: => Message, offset: Int = in.offset): Unit = if (offset > lastErrorOffset) { val length = if (offset == in.offset && in.name != null) in.name.show.length else 0 - syntaxError(msg, Position(offset, offset + length)) + syntaxError(msg, Span(offset, offset + length)) lastErrorOffset = in.offset } - /** Unconditionally issue an error at given position, without - * updating lastErrorOffset. - */ - def syntaxError(msg: => Message, pos: Position): Unit = - ctx.error(msg, source atPos pos) + /** Unconditionally issue an error at given span, without + * updating lastErrorOffset. + */ + def syntaxError(msg: => Message, span: Span): Unit = + ctx.error(msg, source.atSpan(span)) } trait OutlineParserCommon extends ParserCommon { @@ -270,14 +270,14 @@ object Parsers { ctx.warning(msg, sourcePos) def warning(msg: => Message, offset: Int = in.offset): Unit = - ctx.warning(msg, source atPos Position(offset)) + ctx.warning(msg, source.atSpan(Span(offset))) def deprecationWarning(msg: => Message, offset: Int = in.offset): Unit = - ctx.deprecationWarning(msg, source atPos Position(offset)) + ctx.deprecationWarning(msg, source.atSpan(Span(offset))) /** Issue an error at current offset that input is incomplete */ def incompleteInputError(msg: => Message): Unit = - ctx.incompleteInputError(msg, source atPos Position(in.offset)) + ctx.incompleteInputError(msg, source.atSpan(Span(in.offset))) /** If at end of file, issue an incompleteInputError. * Otherwise issue a syntax error and skip to next safe point. @@ -324,7 +324,7 @@ object Parsers { accept(SEMI) } - def errorTermTree: Literal = atPos(in.offset) { Literal(Constant(null)) } + def errorTermTree: Literal = atSpan(in.offset) { Literal(Constant(null)) } private[this] var inFunReturnType = false private def fromWithinReturnType[T](body: => T): T = { @@ -356,7 +356,7 @@ object Parsers { def migrationWarningOrError(msg: String, offset: Int = in.offset): Unit = if (in.isScala2Mode) - ctx.migrationWarning(msg, source atPos Position(offset)) + ctx.migrationWarning(msg, source.atSpan(Span(offset))) else syntaxError(msg, offset) @@ -374,11 +374,11 @@ object Parsers { */ def convertToParam(tree: Tree, mods: Modifiers = Modifiers(), expected: String = "formal parameter"): ValDef = tree match { case Ident(name) => - makeParameter(name.asTermName, TypeTree(), mods) withPos tree.pos + makeParameter(name.asTermName, TypeTree(), mods).withSpan(tree.span) case Typed(Ident(name), tpt) => - makeParameter(name.asTermName, tpt, mods) withPos tree.pos + makeParameter(name.asTermName, tpt, mods).withSpan(tree.span) case _ => - syntaxError(s"not a legal $expected", tree.pos) + syntaxError(s"not a legal $expected", tree.span) makeParameter(nme.ERROR, tree, mods) } @@ -390,7 +390,7 @@ object Parsers { case id @ Select(qual, name) => cpy.Select(id)(qual, name.toTypeName) case _ => - syntaxError(IdentifierExpected(tree.show), tree.pos) + syntaxError(IdentifierExpected(tree.show), tree.span) tree } @@ -408,7 +408,7 @@ object Parsers { try op finally { placeholderParams match { - case vd :: _ => syntaxError(UnboundPlaceholderParameter(), vd.pos) + case vd :: _ => syntaxError(UnboundPlaceholderParameter(), vd.span) case _ => } placeholderParams = savedPlaceholderParams @@ -487,7 +487,7 @@ object Parsers { if (prec < opPrec || leftAssoc && prec == opPrec) { opStack = opStack.tail recur { - atPos(opInfo.operator.pos union opInfo.operand.pos union top.pos) { + atSpan(opInfo.operator.span union opInfo.operand.span union top.span) { val op = opInfo.operator val l = opInfo.operand val r = top @@ -527,7 +527,7 @@ object Parsers { val topInfo = opStack.head opStack = opStack.tail val od = reduceStack(base, topInfo.operand, 0, true, in.name, isType) - return atPos(startOffset(od), topInfo.offset) { + return atSpan(startOffset(od), topInfo.offset) { PostfixOp(od, topInfo.operator) } } @@ -550,12 +550,12 @@ object Parsers { } /** Accept identifier and return Ident with its name as a term name. */ - def termIdent(): Ident = atPos(in.offset) { + def termIdent(): Ident = atSpan(in.offset) { makeIdent(in.token, ident()) } /** Accept identifier and return Ident with its name as a type name. */ - def typeIdent(): Ident = atPos(in.offset) { + def typeIdent(): Ident = atSpan(in.offset) { makeIdent(in.token, ident().toTypeName) } @@ -564,14 +564,14 @@ object Parsers { else Ident(name) def wildcardIdent(): Ident = - atPos(accept(USCORE)) { Ident(nme.WILDCARD) } + atSpan(accept(USCORE)) { Ident(nme.WILDCARD) } def termIdentOrWildcard(): Ident = if (in.token == USCORE) wildcardIdent() else termIdent() /** Accept identifier acting as a selector on given tree `t`. */ def selector(t: Tree): Tree = - atPos(startOffset(t), in.offset) { Select(t, ident()) } + atSpan(startOffset(t), in.offset) { Select(t, ident()) } /** Selectors ::= id { `.' id } * @@ -608,14 +608,14 @@ object Parsers { val start = in.offset def handleThis(qual: Ident) = { in.nextToken() - val t = atPos(start) { This(qual) } - if (!thisOK && in.token != DOT) syntaxError(DanglingThisInPath(), t.pos) + val t = atSpan(start) { This(qual) } + if (!thisOK && in.token != DOT) syntaxError(DanglingThisInPath(), t.span) dotSelectors(t, finish) } def handleSuper(qual: Ident) = { in.nextToken() val mix = mixinQualifierOpt() - val t = atPos(start) { Super(This(qual), mix) } + val t = atSpan(start) { Super(This(qual), mix) } accept(DOT) dotSelectors(selector(t), finish) } @@ -637,7 +637,7 @@ object Parsers { /** MixinQualifier ::= `[' id `]' */ def mixinQualifierOpt(): Ident = - if (in.token == LBRACKET) inBrackets(atPos(in.offset) { typeIdent() }) + if (in.token == LBRACKET) inBrackets(atSpan(in.offset) { typeIdent() }) else EmptyTypeIdent /** StableId ::= id @@ -660,20 +660,20 @@ object Parsers { */ def literal(negOffset: Int = in.offset, inPattern: Boolean = false): Tree = { def finish(value: Any): Tree = { - val t = atPos(negOffset) { Literal(Constant(value)) } + val t = atSpan(negOffset) { Literal(Constant(value)) } in.nextToken() t } val isNegated = negOffset < in.offset - atPos(negOffset) { + atSpan(negOffset) { if (in.token == SYMBOLLIT) { migrationWarningOrError(em"""symbol literal '${in.name} is no longer supported, |use a string literal "${in.name}" or an application Symbol("${in.name}") instead.""") if (in.isScala2Mode) { - patch(source, Position(in.offset, in.offset + 1), "Symbol(\"") - patch(source, Position(in.charOffset - 1), "\")") + patch(source, Span(in.offset, in.offset + 1), "Symbol(\"") + patch(source, Span(in.charOffset - 1), "\")") } - atPos(in.skipToken()) { SymbolLit(in.strVal) } + atSpan(in.skipToken()) { SymbolLit(in.strVal) } } else if (in.token == INTERPOLATIONID) interpolatedString(inPattern) else finish(in.token match { @@ -693,14 +693,14 @@ object Parsers { } } - private def interpolatedString(inPattern: Boolean = false): Tree = atPos(in.offset) { + private def interpolatedString(inPattern: Boolean = false): Tree = atSpan(in.offset) { val segmentBuf = new ListBuffer[Tree] val interpolator = in.name in.nextToken() while (in.token == STRINGPART) { segmentBuf += Thicket( literal(inPattern = inPattern), - atPos(in.offset) { + atSpan(in.offset) { if (in.token == IDENTIFIER) termIdent() else if (in.token == USCORE && inPattern) { @@ -715,7 +715,7 @@ object Parsers { if (inPattern) Block(Nil, inBraces(pattern())) else expr() else { - ctx.error(InterpolatedStringError(), source atPos Position(in.offset)) + ctx.error(InterpolatedStringError(), source.atSpan(Span(in.offset))) EmptyTree } }) @@ -762,7 +762,7 @@ object Parsers { val start = in.offset val imods = modifiers(funArgMods) def functionRest(params: List[Tree]): Tree = - atPos(start, accept(ARROW)) { + atSpan(start, accept(ARROW)) { val t = typ() if (imods.is(Implicit) || imods.is(Erased)) new FunctionWithMods(params, t, imods) else Function(params, t) @@ -804,13 +804,13 @@ object Parsers { for (t <- ts) yield { t match { case t@ByNameTypeTree(t1) => - syntaxError(ByNameParameterNotSupported(t), t.pos) + syntaxError(ByNameParameterNotSupported(t), t.span) t1 case _ => t } } - val tuple = atPos(start) { makeTupleOrParens(ts) } + val tuple = atSpan(start) { makeTupleOrParens(ts) } infixTypeRest( refinedTypeRest( withTypeRest( @@ -823,7 +823,7 @@ object Parsers { val start = in.offset val tparams = typeParamClause(ParamOwner.TypeParam) if (in.token == ARROW) - atPos(start, in.skipToken())(LambdaTypeTree(tparams, toplevelTyp())) + atSpan(start, in.skipToken())(LambdaTypeTree(tparams, toplevelTyp())) else { accept(ARROW); typ() } } else infixType() @@ -839,11 +839,11 @@ object Parsers { } } - private def implicitKwPos(start: Int): Position = - Position(start, start + nme.IMPLICITkw.asSimpleName.length) + private def implicitKwPos(start: Int): Span = + Span(start, start + nme.IMPLICITkw.asSimpleName.length) /** TypedFunParam ::= id ':' Type */ - def typedFunParam(start: Offset, name: TermName, mods: Modifiers = EmptyModifiers): Tree = atPos(start) { + def typedFunParam(start: Offset, name: TermName, mods: Modifiers = EmptyModifiers): Tree = atSpan(start) { accept(COLON) makeParameter(name, typ(), mods | Param) } @@ -865,7 +865,7 @@ object Parsers { def refinedTypeRest(t: Tree): Tree = { newLineOptWhenFollowedBy(LBRACE) - if (in.token == LBRACE) refinedTypeRest(atPos(startOffset(t)) { RefinedTypeTree(checkWildcard(t), refinement()) }) + if (in.token == LBRACE) refinedTypeRest(atSpan(startOffset(t)) { RefinedTypeTree(checkWildcard(t), refinement()) }) else t } @@ -887,7 +887,7 @@ object Parsers { def annotType(): Tree = annotTypeRest(simpleType()) def annotTypeRest(t: Tree): Tree = - if (in.token == AT) annotTypeRest(atPos(startOffset(t)) { Annotated(t, annot()) }) + if (in.token == AT) annotTypeRest(atSpan(startOffset(t)) { Annotated(t, annot()) }) else t /** SimpleType ::= SimpleType TypeArgs @@ -902,18 +902,18 @@ object Parsers { */ def simpleType(): Tree = simpleTypeRest { if (in.token == LPAREN) - atPos(in.offset) { + atSpan(in.offset) { makeTupleOrParens(inParens(argTypes(namedOK = false, wildOK = true))) } else if (in.token == LBRACE) - atPos(in.offset) { RefinedTypeTree(EmptyTree, refinement()) } + atSpan(in.offset) { RefinedTypeTree(EmptyTree, refinement()) } else if (isSimpleLiteral) { SingletonTypeTree(literal()) } else if (in.token == USCORE) { val start = in.skipToken() - typeBounds().withPos(Position(start, in.lastOffset, start)) + typeBounds().withSpan(Span(start, in.lastOffset, start)) } else if (isIdent(nme.raw.TILDE) && in.lookaheadIn(BitSet(IDENTIFIER, BACKQUOTED_IDENT))) - atPos(in.offset) { PrefixOp(typeIdent(), path(thisOK = true)) } + atSpan(in.offset) { PrefixOp(typeIdent(), path(thisOK = true)) } else path(thisOK = false, handleSingletonType) match { case r @ SingletonTypeTree(_) => r case r => convertToTypeId(r) @@ -923,12 +923,12 @@ object Parsers { val handleSingletonType: Tree => Tree = t => if (in.token == TYPE) { in.nextToken() - atPos(startOffset(t)) { SingletonTypeTree(t) } + atSpan(startOffset(t)) { SingletonTypeTree(t) } } else t private def simpleTypeRest(t: Tree): Tree = in.token match { case HASH => simpleTypeRest(typeProjection(t)) - case LBRACKET => simpleTypeRest(atPos(startOffset(t)) { + case LBRACKET => simpleTypeRest(atSpan(startOffset(t)) { AppliedTypeTree(checkWildcard(t), typeArgs(namedOK = false, wildOK = true)) }) case _ => t } @@ -936,7 +936,7 @@ object Parsers { private def typeProjection(t: Tree): Tree = { accept(HASH) val id = typeIdent() - atPos(startOffset(t), startOffset(id)) { Select(t, id.name) } + atSpan(startOffset(t), startOffset(id)) { Select(t, id.name) } } /** NamedTypeArg ::= id `=' Type @@ -975,13 +975,13 @@ object Parsers { /** FunArgType ::= Type | `=>' Type */ val funArgType: () => Tree = () => - if (in.token == ARROW) atPos(in.skipToken()) { ByNameTypeTree(typ()) } + if (in.token == ARROW) atSpan(in.skipToken()) { ByNameTypeTree(typ()) } else typ() /** ParamType ::= [`=>'] ParamValueType */ def paramType(): Tree = - if (in.token == ARROW) atPos(in.skipToken()) { ByNameTypeTree(paramValueType()) } + if (in.token == ARROW) atSpan(in.skipToken()) { ByNameTypeTree(paramValueType()) } else paramValueType() /** ParamValueType ::= Type [`*'] @@ -990,7 +990,7 @@ object Parsers { val t = toplevelTyp() if (isIdent(nme.raw.STAR)) { in.nextToken() - atPos(startOffset(t)) { PostfixOp(t, Ident(tpnme.raw.STAR)) } + atSpan(startOffset(t)) { PostfixOp(t, Ident(tpnme.raw.STAR)) } } else t } @@ -1006,7 +1006,7 @@ object Parsers { /** TypeBounds ::= [`>:' Type] [`<:' Type] */ def typeBounds(): TypeBoundsTree = - atPos(in.offset) { TypeBoundsTree(bound(SUPERTYPE), bound(SUBTYPE)) } + atSpan(in.offset) { TypeBoundsTree(bound(SUPERTYPE), bound(SUBTYPE)) } private def bound(tok: Int): Tree = if (in.token == tok) { in.nextToken(); toplevelTyp() } @@ -1018,17 +1018,17 @@ object Parsers { val t = typeBounds() val cbs = contextBounds(pname) if (cbs.isEmpty) t - else atPos((t.pos union cbs.head.pos).start) { ContextBounds(t, cbs) } + else atSpan((t.span union cbs.head.span).start) { ContextBounds(t, cbs) } } def contextBounds(pname: TypeName): List[Tree] = in.token match { case COLON => - atPos(in.skipToken()) { + atSpan(in.skipToken()) { AppliedTypeTree(toplevelTyp(), Ident(pname)) } :: contextBounds(pname) case VIEWBOUND => deprecationWarning("view bounds `<%' are deprecated, use a context bound `:' instead") - atPos(in.skipToken()) { + atSpan(in.skipToken()) { Function(Ident(pname) :: Nil, toplevelTyp()) } :: contextBounds(pname) case _ => @@ -1037,7 +1037,7 @@ object Parsers { def typedOpt(): Tree = if (in.token == COLON) { in.nextToken(); toplevelTyp() } - else TypeTree().withPos(Position(in.lastOffset)) + else TypeTree().withSpan(Span(in.lastOffset)) def typeDependingOn(location: Location.Value): Tree = if (location == Location.InParens) typ() @@ -1059,7 +1059,7 @@ object Parsers { def rejectWildcard(t: Tree, fallbackTree: Tree): Tree = findNonValueTypeTree(t, false) match { case Some(wildcardTree) => - syntaxError(UnboundWildcardType(), wildcardTree.pos) + syntaxError(UnboundWildcardType(), wildcardTree.span) fallbackTree case None => t } @@ -1076,9 +1076,9 @@ object Parsers { case Some(typTree) => typTree match { case typTree: TypeBoundsTree => - syntaxError(UnboundWildcardType(), typTree.pos) + syntaxError(UnboundWildcardType(), typTree.span) case typTree: ByNameTypeTree => - syntaxError(ByNameParameterNotSupported(typTree), typTree.pos) + syntaxError(ByNameParameterNotSupported(typTree), typTree.span) } scalaAny case None => t @@ -1095,7 +1095,7 @@ object Parsers { def condExpr(altToken: Token): Tree = { if (in.token == LPAREN) { - val t = atPos(in.offset) { Parens(inParens(exprInParens())) } + val t = atSpan(in.offset) { Parens(inParens(exprInParens())) } if (in.token == altToken) in.nextToken() t } else { @@ -1171,14 +1171,14 @@ object Parsers { case IF => ifExpr(in.offset, If) case WHILE => - atPos(in.skipToken()) { + atSpan(in.skipToken()) { val cond = condExpr(DO) newLinesOpt() val body = expr() WhileDo(cond, body) } case DO => - atPos(in.skipToken()) { + atSpan(in.skipToken()) { val body = expr() if (isStatSep) in.nextToken() accept(WHILE) @@ -1187,13 +1187,13 @@ object Parsers { } case TRY => val tryOffset = in.offset - atPos(in.skipToken()) { + atSpan(in.skipToken()) { val body = expr() val (handler, handlerStart) = if (in.token == CATCH) { - val pos = in.offset + val span = in.offset in.nextToken() - (expr(), pos) + (expr(), span) } else (EmptyTree, -1) handler match { @@ -1201,7 +1201,7 @@ object Parsers { assert(handlerStart != -1) syntaxError( EmptyCatchBlock(body), - Position(handlerStart, endOffset(handler)) + Span(handlerStart, endOffset(handler)) ) case _ => } @@ -1211,16 +1211,16 @@ object Parsers { else { if (handler.isEmpty) warning( EmptyCatchAndFinallyBlock(body), - source atPos Position(tryOffset, endOffset(body)) + source.atSpan(Span(tryOffset, endOffset(body))) ) EmptyTree } ParsedTry(body, handler, finalizer) } case THROW => - atPos(in.skipToken()) { Throw(expr()) } + atSpan(in.skipToken()) { Throw(expr()) } case RETURN => - atPos(in.skipToken()) { Return(if (isExprIntro) expr() else EmptyTree, EmptyTree) } + atSpan(in.skipToken()) { Return(if (isExprIntro) expr() else EmptyTree, EmptyTree) } case FOR => forExpr() case _ => @@ -1245,7 +1245,7 @@ object Parsers { case EQUALS => t match { case Ident(_) | Select(_, _) | Apply(_, _) => - atPos(startOffset(t), in.skipToken()) { Assign(t, expr()) } + atSpan(startOffset(t), in.skipToken()) { Assign(t, expr()) } case _ => t } @@ -1257,7 +1257,7 @@ object Parsers { t } - def ascription(t: Tree, location: Location.Value): Tree = atPos(startOffset(t)) { + def ascription(t: Tree, location: Location.Value): Tree = atSpan(startOffset(t)) { in.skipToken() in.token match { case USCORE => @@ -1265,7 +1265,7 @@ object Parsers { if (isIdent(nme.raw.STAR)) { in.nextToken() if (in.token != RPAREN) syntaxError(SeqWildcardPatternPos(), uscoreStart) - Typed(t, atPos(uscoreStart) { Ident(tpnme.WILDCARD_STAR) }) + Typed(t, atSpan(uscoreStart) { Ident(tpnme.WILDCARD_STAR) }) } else { syntaxErrorOrIncomplete(IncorrectRepeatedParameterSyntax()) t @@ -1277,7 +1277,7 @@ object Parsers { if (isWildcard(t) && location != Location.InPattern) { val vd :: rest = placeholderParams placeholderParams = - cpy.ValDef(vd)(tpt = tpt).withPos(vd.pos union tpt.pos) :: rest + cpy.ValDef(vd)(tpt = tpt).withSpan(vd.span.union(tpt.span)) :: rest } Typed(t, tpt) } @@ -1287,7 +1287,7 @@ object Parsers { * `if' Expr `then' Expr [[semi] else Expr] */ def ifExpr(start: Offset, mkIf: (Tree, Tree, Tree) => If): If = - atPos(start, in.skipToken()) { + atSpan(start, in.skipToken()) { val cond = condExpr(THEN) newLinesOpt() val thenp = expr() @@ -1299,7 +1299,7 @@ object Parsers { /** `match' { CaseClauses } */ def matchExpr(t: Tree, start: Offset, mkMatch: (Tree, List[CaseDef]) => Match) = - atPos(start, in.skipToken()) { + atSpan(start, in.skipToken()) { inBraces(mkMatch(t, caseClauses(caseClause))) } @@ -1307,7 +1307,7 @@ object Parsers { */ def implicitMatch(start: Int, imods: Modifiers) = { def markFirstIllegal(mods: List[Mod]) = mods match { - case mod :: _ => syntaxError(em"illegal modifier for implicit match", mod.pos) + case mod :: _ => syntaxError(em"illegal modifier for implicit match", mod.span) case _ => } imods.mods match { @@ -1322,7 +1322,7 @@ object Parsers { case pat => isVarPattern(pat) } if (!isImplicitPattern(pat)) - syntaxError(em"not a legal pattern for an implicit match", pat.pos) + syntaxError(em"not a legal pattern for an implicit match", pat.span) } result } @@ -1330,7 +1330,7 @@ object Parsers { /** `match' { TypeCaseClauses } */ def matchType(bound: Tree, t: Tree): MatchTypeTree = - atPos((if (bound.isEmpty) t else bound).pos.start, accept(MATCH)) { + atSpan((if (bound.isEmpty) t else bound).span.start, accept(MATCH)) { inBraces(MatchTypeTree(bound, t, caseClauses(typeCaseClause))) } @@ -1354,19 +1354,19 @@ object Parsers { in.nextToken() val t = infixType() if (false && in.isScala2Mode) { - patch(source, Position(start), "(") - patch(source, Position(in.lastOffset), ")") + patch(source, Span(start), "(") + patch(source, Span(in.lastOffset), ")") } t } else TypeTree() - (atPos(start) { makeParameter(name, t, mods) }) :: Nil + (atSpan(start) { makeParameter(name, t, mods) }) :: Nil } /** Binding ::= (id | `_') [`:' Type] */ def binding(mods: Modifiers): Tree = - atPos(in.offset) { makeParameter(bindingName(), typedOpt(), mods) } + atSpan(in.offset) { makeParameter(bindingName(), typedOpt(), mods) } def bindingName(): TermName = if (in.token == USCORE) { @@ -1382,7 +1382,7 @@ object Parsers { closureRest(start, location, funParams(implicitMods, location)) def closureRest(start: Int, location: Location.Value, params: List[Tree]): Tree = - atPos(start, in.offset) { + atSpan(start, in.offset) { accept(ARROW) Function(params, if (location == Location.InBlock) block() else expr()) } @@ -1403,7 +1403,7 @@ object Parsers { if (op.name == nme.raw.MINUS && isNumericLit) simpleExprRest(literal(start), canApply = true) else - atPos(start) { PrefixOp(op, simpleExpr()) } + atSpan(start) { PrefixOp(op, simpleExpr()) } } else simpleExpr() @@ -1432,23 +1432,23 @@ object Parsers { val start = in.skipToken() val pname = WildcardParamName.fresh() val param = ValDef(pname, TypeTree(), EmptyTree).withFlags(SyntheticTermParam) - .withPos(Position(start)) + .withSpan(Span(start)) placeholderParams = param :: placeholderParams - atPos(start) { Ident(pname) } + atSpan(start) { Ident(pname) } case LPAREN => - atPos(in.offset) { makeTupleOrParens(inParens(exprsInParensOpt())) } + atSpan(in.offset) { makeTupleOrParens(inParens(exprsInParensOpt())) } case LBRACE => canApply = false blockExpr() case QPAREN => in.token = LPAREN - atPos(in.offset)(Quote(simpleExpr())) + atSpan(in.offset)(Quote(simpleExpr())) case QBRACE => in.token = LBRACE - atPos(in.offset)(Quote(simpleExpr())) + atSpan(in.offset)(Quote(simpleExpr())) case QBRACKET => in.token = LBRACKET - atPos(in.offset)(Quote(inBrackets(typ()))) + atSpan(in.offset)(Quote(inBrackets(typ()))) case NEW => canApply = false val start = in.skipToken() @@ -1456,9 +1456,9 @@ object Parsers { impl.parents match { case parent :: Nil if missingBody => if (parent.isType) ensureApplied(wrapNew(parent)) - else parent.withPos(Position(start, in.lastOffset)) + else parent.withSpan(Span(start, in.lastOffset)) case _ => - New(impl.withPos(Position(start, in.lastOffset))) + New(impl.withSpan(Span(start, in.lastOffset))) } case _ => if (isLiteral) literal() @@ -1477,13 +1477,13 @@ object Parsers { in.nextToken() simpleExprRest(selector(t), canApply = true) case LBRACKET => - val tapp = atPos(startOffset(t), in.offset) { TypeApply(t, typeArgs(namedOK = true, wildOK = false)) } + val tapp = atSpan(startOffset(t), in.offset) { TypeApply(t, typeArgs(namedOK = true, wildOK = false)) } simpleExprRest(tapp, canApply = true) case LPAREN | LBRACE if canApply => - val app = atPos(startOffset(t), in.offset) { Apply(t, argumentExprs()) } + val app = atSpan(startOffset(t), in.offset) { Apply(t, argumentExprs()) } simpleExprRest(app, canApply = true) case USCORE => - atPos(startOffset(t), in.skipToken()) { PostfixOp(t, Ident(nme.WILDCARD)) } + atSpan(startOffset(t), in.skipToken()) { PostfixOp(t, Ident(nme.WILDCARD)) } case _ => t } @@ -1543,7 +1543,7 @@ object Parsers { } if (in.token == LPAREN && (!inClassConstrAnnots || isLegalAnnotArg)) parArgumentExprss( - atPos(startOffset(fn)) { Apply(fn, parArgumentExprs()) } + atSpan(startOffset(fn)) { Apply(fn, parArgumentExprs()) } ) else fn } @@ -1551,7 +1551,7 @@ object Parsers { /** BlockExpr ::= `{' BlockExprContents `}' * BlockExprContents ::= CaseClauses | Block */ - def blockExpr(): Tree = atPos(in.offset) { + def blockExpr(): Tree = atSpan(in.offset) { inDefScopeBraces { if (in.token == CASE) Match(EmptyTree, caseClauses(caseClause)) else block() @@ -1559,7 +1559,7 @@ object Parsers { } /** Block ::= BlockStatSeq - * @note Return tree does not carry source position. + * @note Return tree does not have a defined span. */ def block(): Tree = { val stats = blockStatSeq() @@ -1591,7 +1591,7 @@ object Parsers { if (in.token == IF) guard() else { val pat = pattern1() - if (in.token == EQUALS) atPos(startOffset(pat), in.skipToken()) { GenAlias(pat, expr()) } + if (in.token == EQUALS) atSpan(startOffset(pat), in.skipToken()) { GenAlias(pat, expr()) } else generatorRest(pat) } @@ -1600,13 +1600,13 @@ object Parsers { def generator(): Tree = generatorRest(pattern1()) def generatorRest(pat: Tree): GenFrom = - atPos(startOffset(pat), accept(LARROW)) { GenFrom(pat, expr()) } + atSpan(startOffset(pat), accept(LARROW)) { GenFrom(pat, expr()) } /** ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}') * {nl} [`yield'] Expr * | `for' Enumerators (`do' Expr | `yield' Expr) */ - def forExpr(): Tree = atPos(in.skipToken()) { + def forExpr(): Tree = atSpan(in.skipToken()) { var wrappedEnums = true val enums = if (in.token == LBRACE) inBraces(enumerators()) @@ -1619,7 +1619,7 @@ object Parsers { wrappedEnums = false accept(RPAREN) openParens.change(LPAREN, -1) - atPos(lparenOffset) { makeTupleOrParens(pats) } // note: alternatives `|' need to be weeded out by typer. + atSpan(lparenOffset) { makeTupleOrParens(pats) } // note: alternatives `|' need to be weeded out by typer. } else pats.head val res = generatorRest(pat) :: enumeratorsRest() @@ -1655,16 +1655,16 @@ object Parsers { /** CaseClause ::= ‘case’ Pattern [Guard] `=>' Block * ImplicitCaseClause ::= ‘case’ PatVar [Ascription] [Guard] `=>' Block */ - val caseClause: () => CaseDef = () => atPos(in.offset) { + val caseClause: () => CaseDef = () => atSpan(in.offset) { accept(CASE) - CaseDef(pattern(), guard(), atPos(accept(ARROW)) { block() }) + CaseDef(pattern(), guard(), atSpan(accept(ARROW)) { block() }) } /** TypeCaseClause ::= ‘case’ InfixType ‘=>’ Type [nl] */ - val typeCaseClause: () => CaseDef = () => atPos(in.offset) { + val typeCaseClause: () => CaseDef = () => atSpan(in.offset) { accept(CASE) - CaseDef(infixType(), EmptyTree, atPos(accept(ARROW)) { + CaseDef(infixType(), EmptyTree, atSpan(accept(ARROW)) { val t = typ() if (isStatSep) in.nextToken() t @@ -1678,7 +1678,7 @@ object Parsers { val pattern: () => Tree = () => { val pat = pattern1() if (isIdent(nme.raw.BAR)) - atPos(startOffset(pat)) { Alternative(pat :: patternAlts()) } + atSpan(startOffset(pat)) { Alternative(pat :: patternAlts()) } else pat } @@ -1705,14 +1705,14 @@ object Parsers { infixPattern() match { case pt @ Ident(tpnme.WILDCARD_STAR) => migrationWarningOrError("The syntax `x @ _*' is no longer supported; use `x : _*' instead", startOffset(p)) - atPos(startOffset(p), offset) { Typed(p, pt) } + atSpan(startOffset(p), offset) { Typed(p, pt) } case pt => - atPos(startOffset(p), 0) { Bind(name, pt) } + atSpan(startOffset(p), 0) { Bind(name, pt) } } case p @ Ident(tpnme.WILDCARD_STAR) => // compatibility for Scala2 `_*` syntax migrationWarningOrError("The syntax `_*' is no longer supported; use `x : _*' instead", startOffset(p)) - atPos(startOffset(p)) { Typed(Ident(nme.WILDCARD), p) } + atSpan(startOffset(p)) { Typed(Ident(nme.WILDCARD), p) } case p => p } @@ -1745,11 +1745,11 @@ object Parsers { // `x: _*' is parsed in `ascription' if (isIdent(nme.raw.STAR)) { in.nextToken() - if (in.token != RPAREN) syntaxError(SeqWildcardPatternPos(), wildIndent.pos) - atPos(wildIndent.pos) { Ident(tpnme.WILDCARD_STAR) } + if (in.token != RPAREN) syntaxError(SeqWildcardPatternPos(), wildIndent.span) + atSpan(wildIndent.span) { Ident(tpnme.WILDCARD_STAR) } } else wildIndent case LPAREN => - atPos(in.offset) { makeTupleOrParens(inParens(patternsOpt())) } + atSpan(in.offset) { makeTupleOrParens(inParens(patternsOpt())) } case XMLSTART => xmlLiteralPattern() case _ => @@ -1763,9 +1763,9 @@ object Parsers { def simplePatternRest(t: Tree): Tree = { var p = t if (in.token == LBRACKET) - p = atPos(startOffset(t), in.offset) { TypeApply(p, typeArgs(namedOK = false, wildOK = false)) } + p = atSpan(startOffset(t), in.offset) { TypeApply(p, typeArgs(namedOK = false, wildOK = false)) } if (in.token == LPAREN) - p = atPos(startOffset(t), in.offset) { Apply(p, argumentPatterns()) } + p = atSpan(startOffset(t), in.offset) { Apply(p, argumentPatterns()) } p } @@ -1816,7 +1816,7 @@ object Parsers { private def addModifier(mods: Modifiers): Modifiers = { val tok = in.token val name = in.name - val mod = atPos(in.skipToken()) { modOfToken(tok, name) } + val mod = atSpan(in.skipToken()) { modOfToken(tok, name) } if (mods is mod.flags) syntaxError(RepeatedModifier(mod.flags.toString)) addMod(mods, mod) @@ -1892,15 +1892,15 @@ object Parsers { /** Wrap annotation or constructor in New(...). */ def wrapNew(tpt: Tree): Select = Select(New(tpt), nme.CONSTRUCTOR) - /** Adjust start of annotation or constructor to position of preceding @ or new */ + /** Adjust start of annotation or constructor to offset of preceding @ or new */ def adjustStart(start: Offset)(tree: Tree): Tree = { val tree1 = tree match { case Apply(fn, args) => cpy.Apply(tree)(adjustStart(start)(fn), args) case Select(qual, name) => cpy.Select(tree)(adjustStart(start)(qual), name) case _ => tree } - if (tree1.pos.exists && start < tree1.pos.start) - tree1.withPos(tree1.pos.withStart(start)) + if (tree1.span.exists && start < tree1.span.start) + tree1.withSpan(tree1.span.withStart(start)) else tree1 } @@ -1942,7 +1942,7 @@ object Parsers { def typeParam(): TypeDef = { val isConcreteOwner = ownerKind == ParamOwner.Class || ownerKind == ParamOwner.Def val start = in.offset - val mods = atPos(start) { + val mods = annotsAsMods() | { if (ownerKind == ParamOwner.Class) Param | PrivateLocal else Param @@ -1953,8 +1953,7 @@ object Parsers { else EmptyFlags else EmptyFlags } - } - atPos(start, nameStart) { + atSpan(start, nameStart) { val name = if (isConcreteOwner || in.token != USCORE) ident().toTypeName else { @@ -1991,37 +1990,35 @@ object Parsers { prefix: Boolean = false, // clause precedes name of an extension method firstClause: Boolean = false) // clause is the first in regular list of clauses : List[ValDef] = { - var implicitOffset = -1 // use once + var impliedMods: Modifiers = EmptyModifiers - def param(impliedMods: Modifiers): ValDef = { + def param(): ValDef = { val start = in.offset var mods = impliedMods.withAnnotations(annotations()) if (ofClass) { mods = addFlag(modifiers(start = mods), ParamAccessor) mods = - atPos(start, in.offset) { - if (in.token == VAL) { - in.nextToken() - mods - } - else if (in.token == VAR) { - val mod = atPos(in.skipToken()) { Mod.Var() } - addMod(mods, mod) - } - else { - if (!(mods.flags &~ (ParamAccessor | Inline | impliedMods.flags)).isEmpty) - syntaxError("`val' or `var' expected") - if (firstClause && ofCaseClass) mods - else mods | PrivateLocal - } + if (in.token == VAL) { + in.nextToken() + mods + } + else if (in.token == VAR) { + val mod = atSpan(in.skipToken()) { Mod.Var() } + addMod(mods, mod) + } + else { + if (!(mods.flags &~ (ParamAccessor | Inline | impliedMods.flags)).isEmpty) + syntaxError("`val' or `var' expected") + if (firstClause && ofCaseClass) mods + else mods | PrivateLocal } } else { if (isIdent(nme.inline) && in.isSoftModifierInParamModifierPosition) mods = addModifier(mods) - mods = atPos(start) { mods | Param } + mods |= Param } - atPos(start, nameStart) { + atSpan(start, nameStart) { val name = ident() accept(COLON) if (in.token == ARROW && ofClass && !(mods is Local)) @@ -2030,9 +2027,8 @@ object Parsers { val default = if (in.token == EQUALS) { in.nextToken(); expr() } else EmptyTree - if (implicitOffset >= 0) { - mods = mods.withPos(mods.pos.union(Position(implicitOffset, implicitOffset))) - implicitOffset = -1 + if (impliedMods.mods.nonEmpty) { + impliedMods = impliedMods.withMods(Nil) // keep only flags, so that parameter positions don't overlap } ValDef(name, tpt, default).withMods(mods) } @@ -2044,7 +2040,7 @@ object Parsers { case vparam :: rest => vparam.tpt match { case PostfixOp(_, op) if op.name == tpnme.raw.STAR => - syntaxError(VarArgsParamMustComeLast(), vparam.tpt.pos) + syntaxError(VarArgsParamMustComeLast(), vparam.tpt.span) case _ => } checkVarArgsRules(rest) @@ -2055,18 +2051,16 @@ object Parsers { if (in.token == RPAREN && !prefix) Nil else { def funArgMods(mods: Modifiers): Modifiers = - if (in.token == IMPLICIT) { - implicitOffset = in.offset - funArgMods(addMod(mods, atPos(accept(IMPLICIT)) { Mod.Implicit() })) - } + if (in.token == IMPLICIT) + funArgMods(addMod(mods, atSpan(accept(IMPLICIT)) { Mod.Implicit() })) else if (in.token == ERASED) - funArgMods(addMod(mods, atPos(accept(ERASED)) { Mod.Erased() })) + funArgMods(addMod(mods, atSpan(accept(ERASED)) { Mod.Erased() })) else mods - val paramMods = funArgMods(EmptyModifiers) + impliedMods = funArgMods(EmptyModifiers) val clause = - if (prefix) param(paramMods) :: Nil - else commaSeparated(() => param(paramMods)) + if (prefix) param() :: Nil + else commaSeparated(() => param()) checkVarArgsRules(clause) clause } @@ -2107,11 +2101,11 @@ object Parsers { val offset = accept(IMPORT) commaSeparated(importExpr) match { case t :: rest => - // The first import should start at the position of the keyword. + // The first import should start at the start offset of the keyword. val firstPos = - if (t.pos.exists) t.pos.withStart(offset) - else Position(offset, in.lastOffset) - t.withPos(firstPos) :: rest + if (t.span.exists) t.span.withStart(offset) + else Span(offset, in.lastOffset) + t.withSpan(firstPos) :: rest case nil => nil } } @@ -2122,7 +2116,7 @@ object Parsers { case imp: Import => imp case sel @ Select(qual, name) => - val selector = atPos(pointOffset(sel)) { Ident(name) } + val selector = atSpan(pointOffset(sel)) { Ident(name) } cpy.Import(sel)(qual, selector :: Nil) case t => accept(DOT) @@ -2156,14 +2150,14 @@ object Parsers { def importSelector(): Tree = { val from = termIdentOrWildcard() if (from.name != nme.WILDCARD && in.token == ARROW) - atPos(startOffset(from), in.skipToken()) { + atSpan(startOffset(from), in.skipToken()) { val start = in.offset val to = termIdentOrWildcard() val toWithPos = if (to.name == nme.ERROR) - // error identifiers don't consume any characters, so atPos(start)(id) wouldn't set a position. - // Some testcases would then fail in Positioned.checkPos. Set a position anyway! - atPos(start, start, in.lastOffset)(to) + // error identifiers don't consume any characters, so atSpan(start)(id) wouldn't set a span. + // Some testcases would then fail in Positioned.checkPos. Set a span anyway! + atSpan(start, start, in.lastOffset)(to) else to Thicket(from, toWithPos) @@ -2172,9 +2166,8 @@ object Parsers { } def posMods(start: Int, mods: Modifiers): Modifiers = { - val mods1 = atPos(start)(mods) in.nextToken() - mods1 + mods } /** Def ::= val PatDef @@ -2193,7 +2186,7 @@ object Parsers { in.nextToken() patDefOrDcl(start, mods) case VAR => - val mod = atPos(in.skipToken()) { Mod.Var() } + val mod = atSpan(in.skipToken()) { Mod.Var() } val mod1 = addMod(mods, mod) patDefOrDcl(start, mod1) case DEF => @@ -2211,7 +2204,7 @@ object Parsers { * ValDcl ::= id {`,' id} `:' Type * VarDcl ::= id {`,' id} `:' Type */ - def patDefOrDcl(start: Offset, mods: Modifiers): Tree = atPos(start, nameStart) { + def patDefOrDcl(start: Offset, mods: Modifiers): Tree = atSpan(start, nameStart) { val lhs = commaSeparated(pattern2) val tpt = typedOpt() val rhs = @@ -2237,13 +2230,13 @@ object Parsers { * DefDcl ::= DefSig `:' Type * DefSig ::= ‘(’ DefParam ‘)’ [nl] id [DefTypeParamClause] ParamClauses */ - def defDefOrDcl(start: Offset, mods: Modifiers): Tree = atPos(start, nameStart) { + def defDefOrDcl(start: Offset, mods: Modifiers): Tree = atSpan(start, nameStart) { def scala2ProcedureSyntax(resultTypeStr: String) = { val toInsert = if (in.token == LBRACE) s"$resultTypeStr =" else ": Unit " // trailing space ensures that `def f()def g()` works. in.testScala2Mode(s"Procedure syntax no longer supported; `$toInsert' should be inserted here") && { - patch(source, Position(in.lastOffset), toInsert) + patch(source, Span(in.lastOffset), toInsert) true } } @@ -2259,7 +2252,7 @@ object Parsers { if (in.isScala2Mode) newLineOptWhenFollowedBy(LBRACE) val rhs = { if (!(in.token == LBRACE && scala2ProcedureSyntax(""))) accept(EQUALS) - atPos(in.offset) { constrExpr() } + atSpan(in.offset) { constrExpr() } } makeConstructor(Nil, vparamss, rhs).withMods(mods).setComment(in.getDocComment(start)) } else { @@ -2316,7 +2309,7 @@ object Parsers { /** SelfInvocation ::= this ArgumentExprs {ArgumentExprs} */ def selfInvocation(): Tree = - atPos(accept(THIS)) { + atSpan(accept(THIS)) { newLineOptWhenFollowedBy(LBRACE) argumentExprss(Apply(Ident(nme.CONSTRUCTOR), argumentExprs())) } @@ -2324,7 +2317,7 @@ object Parsers { /** ConstrBlock ::= `{' SelfInvocation {semi BlockStat} `}' */ def constrBlock(): Tree = - atPos(in.skipToken()) { + atSpan(in.skipToken()) { val stats = selfInvocation() :: { if (isStatSep) { in.nextToken(); blockStatSeq() } else Nil @@ -2338,7 +2331,7 @@ object Parsers { */ def typeDefOrDcl(start: Offset, mods: Modifiers): Tree = { newLinesOpt() - atPos(start, nameStart) { + atSpan(start, nameStart) { val name = ident().toTypeName val tparams = typeParamClauseOpt(ParamOwner.Type) def makeTypeDef(rhs: Tree): Tree = @@ -2381,7 +2374,7 @@ object Parsers { case CASEOBJECT => objectDef(start, posMods(start, mods | Case | Module)) case ENUM => - enumDef(start, mods, atPos(in.skipToken()) { Mod.Enum() }) + enumDef(start, mods, atSpan(in.skipToken()) { Mod.Enum() }) case _ => syntaxErrorOrIncomplete(ExpectedStartOfTopLevelDefinition()) EmptyTree @@ -2390,7 +2383,7 @@ object Parsers { /** ClassDef ::= id ClassConstr TemplateOpt */ - def classDef(start: Offset, mods: Modifiers): TypeDef = atPos(start, nameStart) { + def classDef(start: Offset, mods: Modifiers): TypeDef = atSpan(start, nameStart) { classDefRest(start, mods, ident().toTypeName) } @@ -2402,7 +2395,7 @@ object Parsers { /** ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses */ - def classConstr(isCaseClass: Boolean = false): DefDef = atPos(in.lastOffset) { + def classConstr(isCaseClass: Boolean = false): DefDef = atSpan(in.lastOffset) { val tparams = typeParamClauseOpt(ParamOwner.Class) val cmods = fromWithinClassConstr(constrModsOpt()) val vparamss = paramClauses(ofClass = true, ofCaseClass = isCaseClass) @@ -2416,28 +2409,28 @@ object Parsers { /** ObjectDef ::= id TemplateOpt */ - def objectDef(start: Offset, mods: Modifiers): ModuleDef = atPos(start, nameStart) { + def objectDef(start: Offset, mods: Modifiers): ModuleDef = atSpan(start, nameStart) { objectDefRest(start, mods, ident()) } def objectDefRest(start: Offset, mods: Modifiers, name: TermName): ModuleDef = { val template = templateOpt(emptyConstructor) - def flagPos(flag: FlagSet) = mods.mods.find(_.flags == flag).get.pos + def flagSpan(flag: FlagSet) = mods.mods.find(_.flags == flag).get.span if (mods is Abstract) - syntaxError(hl"""${Abstract} modifier cannot be used for objects""", flagPos(Abstract)) + syntaxError(hl"""${Abstract} modifier cannot be used for objects""", flagSpan(Abstract)) if (mods is Sealed) - syntaxError(hl"""${Sealed} modifier is redundant for objects""", flagPos(Sealed)) + syntaxError(hl"""${Sealed} modifier is redundant for objects""", flagSpan(Sealed)) // Maybe this should be an error; see https://github.com/scala/bug/issues/11094. if (mods is Final) - warning(hl"""${Final} modifier is redundant for objects""", source atPos flagPos(Final)) + warning(hl"""${Final} modifier is redundant for objects""", source atSpan flagSpan(Final)) finalizeDef(ModuleDef(name, template), mods, start) } /** EnumDef ::= id ClassConstr [`extends' [ConstrApps]] EnumBody */ - def enumDef(start: Offset, mods: Modifiers, enumMod: Mod): TypeDef = atPos(start, nameStart) { + def enumDef(start: Offset, mods: Modifiers, enumMod: Mod): TypeDef = atSpan(start, nameStart) { val modName = ident() val clsName = modName.toTypeName val constr = classConstr() @@ -2448,14 +2441,14 @@ object Parsers { /** EnumCase = `case' (id ClassConstr [`extends' ConstrApps] | ids) */ def enumCase(start: Offset, mods: Modifiers): DefTree = { - val mods1 = addMod(mods, atPos(in.offset)(Mod.Enum())) | Case + val mods1 = addMod(mods, atSpan(in.offset)(Mod.Enum())) | Case accept(CASE) in.adjustSepRegions(ARROW) // Scanner thinks it is in a pattern match after seeing the `case`. // We need to get it out of that mode by telling it we are past the `=>` - atPos(start, nameStart) { + atSpan(start, nameStart) { val id = termIdent() if (in.token == COMMA) { in.nextToken() @@ -2549,7 +2542,7 @@ object Parsers { /** Create a tree representing a packaging */ def makePackaging(start: Int, pkg: Tree, stats: List[Tree]): PackageDef = pkg match { - case x: RefTree => atPos(start, pointOffset(pkg))(PackageDef(x, stats)) + case x: RefTree => atSpan(start, pointOffset(pkg))(PackageDef(x, stats)) } /** Packaging ::= package QualId [nl] `{' TopStatSeq `}' @@ -2574,8 +2567,10 @@ object Parsers { setLastStatOffset() if (in.token == PACKAGE) { val start = in.skipToken() - if (in.token == OBJECT) - stats += objectDef(start, atPos(start, in.skipToken()) { Modifiers(Package) }) + if (in.token == OBJECT) { + in.nextToken() + stats += objectDef(start, Modifiers(Package)) + } else stats += packaging(start) } else if (in.token == IMPORT) @@ -2612,11 +2607,11 @@ object Parsers { if (in.token == ARROW) { first match { case Typed(tree @ This(EmptyTypeIdent), tpt) => - self = makeSelfDef(nme.WILDCARD, tpt).withPos(first.pos) + self = makeSelfDef(nme.WILDCARD, tpt).withSpan(first.span) case _ => val ValDef(name, tpt, _) = convertToParam(first, EmptyModifiers, "self type clause") if (name != nme.ERROR) - self = makeSelfDef(name, tpt).withPos(first.pos) + self = makeSelfDef(name, tpt).withSpan(first.span) } in.nextToken() } else { @@ -2659,7 +2654,7 @@ object Parsers { } if (isLegal) tree :: Nil else { - syntaxError("illegal refinement", tree.pos) + syntaxError("illegal refinement", tree.span) Nil } } @@ -2735,7 +2730,8 @@ object Parsers { if (in.token == PACKAGE) { in.nextToken() if (in.token == OBJECT) { - ts += objectDef(start, atPos(start, in.skipToken()) { Modifiers(Package) }) + in.nextToken() + ts += objectDef(start, Modifiers(Package)) if (in.token != EOF) { acceptStatSep() ts ++= topStatSeq() diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 193c4d74d977..ec1c3c28106f 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -2,7 +2,7 @@ package dotty.tools package dotc package parsing -import core.Names._, core.Contexts._, core.Decorators._, util.Positions._ +import core.Names._, core.Contexts._, core.Decorators._, util.Spans._ import core.StdNames._, core.Comments._ import util.SourceFile import java.lang.Character.isDigit @@ -66,14 +66,14 @@ object Scanners { /** Generate an error at the given offset */ def error(msg: String, off: Offset = offset): Unit = { - ctx.error(msg, source atPos Position(off)) + ctx.error(msg, source atSpan Span(off)) token = ERROR errOffset = off } /** signal an error where the input ended in the middle of a token */ def incompleteInputError(msg: String): Unit = { - ctx.incompleteInputError(msg, source atPos Position(offset)) + ctx.incompleteInputError(msg, source atSpan Span(offset)) token = EOF errOffset = offset } @@ -178,10 +178,10 @@ object Scanners { private[this] var docstringMap: SortedMap[Int, Comment] = SortedMap.empty /* A Buffer for comment positions */ - private[this] val commentPosBuf = new mutable.ListBuffer[Position] + private[this] val commentPosBuf = new mutable.ListBuffer[Span] /** Return a list of all the comment positions */ - def commentPositions: List[Position] = commentPosBuf.toList + def commentSpans: List[Span] = commentPosBuf.toList private[this] def addComment(comment: Comment): Unit = { val lookahead = lookaheadReader() @@ -211,8 +211,8 @@ object Scanners { private def treatAsIdent() = { testScala2Mode(i"$name is now a keyword, write `$name` instead of $name to keep it as an identifier") - patch(source, Position(offset), "`") - patch(source, Position(offset + name.length), "`") + patch(source, Span(offset), "`") + patch(source, Span(offset + name.length), "`") IDENTIFIER } @@ -245,8 +245,8 @@ object Scanners { val isScala2Mode: Boolean = ctx.scala2Setting /** Cannot use ctx.featureEnabled because accessing the context would force too much */ - def testScala2Mode(msg: String, pos: Position = Position(offset)): Boolean = { - if (isScala2Mode) ctx.migrationWarning(msg, source atPos pos) + def testScala2Mode(msg: String, span: Span = Span(offset)): Boolean = { + if (isScala2Mode) ctx.migrationWarning(msg, source.atSpan(span)) isScala2Mode } @@ -617,7 +617,7 @@ object Scanners { val start = lastCharOffset def finishComment(): Boolean = { if (keepComments) { - val pos = Position(start, charOffset - 1, start) + val pos = Span(start, charOffset - 1, start) val comment = Comment(pos, flushBuf(commentBuf)) commentPosBuf += pos diff --git a/compiler/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused b/compiler/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused index 672c85179ff2..d92cbd9572f1 100644 --- a/compiler/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused +++ b/compiler/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused @@ -5,7 +5,7 @@ package parsing import core._ import Flags._, Trees._, TypedTrees._, UntypedTrees._, Names._, StdNames._, NameOps._, Contexts._ import scala.collection.mutable.ListBuffer -import util.Positions._, Symbols._, Decorators._, Flags._, Constants._ +import util.Spans._, Symbols._, Decorators._, Flags._, Constants._ import TreeInfo._ /** Methods for building trees, used in the parser. All the trees @@ -42,7 +42,7 @@ class TreeBuilder(implicit ctx: Context) { case Ident(name) if isVarPattern(tree) && name != nme.WILDCARD => Bind( name, Ident(nme.WILDCARD).withPos(tree.pos.focus) - ).withPos(tree.pos) + ).withSpan(tree.span) case Typed(id @ Ident(name), tpt) if isVarPattern(id) && name != nme.WILDCARD => Bind( name, diff --git a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala index 0f0a0d36bf53..a56df8e14906 100644 --- a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala @@ -8,9 +8,10 @@ import mutable.{ Buffer, ArrayBuffer, ListBuffer } import scala.util.control.ControlThrowable import scala.tasty.util.Chars.SU import Parsers._ -import util.Positions._ +import util.Spans._ import core._ import Constants._ +import util.SourceFile import Utility._ @@ -46,11 +47,11 @@ object MarkupParsers { override def getMessage: String = "input ended while parsing XML" } - class MarkupParser(parser: Parser, final val preserveWS: Boolean) extends MarkupParserCommon { + class MarkupParser(parser: Parser, final val preserveWS: Boolean)(implicit src: SourceFile) extends MarkupParserCommon { import Tokens.{ LBRACE, RBRACE } - type PositionType = Position + type PositionType = Span type InputType = CharArrayReader type ElementType = Tree type AttributesType = mutable.Map[String, Tree] @@ -72,7 +73,7 @@ object MarkupParsers { import parser.{ symbXMLBuilder => handle } def curOffset : Int = input.charOffset - 1 - var tmppos : Position = NoPosition + var tmppos : Span = NoSpan def ch: Char = input.ch /** this method assign the next character to ch and advances in input */ def nextch(): Unit = { input.nextChar() } @@ -81,7 +82,7 @@ object MarkupParsers { val result = ch; input.nextChar(); result } - def mkProcInstr(position: Position, name: String, text: String): ElementType = + def mkProcInstr(position: Span, name: String, text: String): ElementType = parser.symbXMLBuilder.procInstr(position, name, text) var xEmbeddedBlock: Boolean = false @@ -127,7 +128,7 @@ object MarkupParsers { case '"' | '\'' => val tmp = xAttributeValue(ch_returning_nextch) - try handle.parseAttribute(Position(start, curOffset, mid), tmp) + try handle.parseAttribute(Span(start, curOffset, mid), tmp) catch { case e: RuntimeException => errorAndResult("error parsing attribute value", parser.errorTermTree) @@ -160,12 +161,12 @@ object MarkupParsers { val start = curOffset xToken("[CDATA[") val mid = curOffset - xTakeUntil(handle.charData, () => Position(start, curOffset, mid), "]]>") + xTakeUntil(handle.charData, () => Span(start, curOffset, mid), "]]>") } def xUnparsed: Tree = { val start = curOffset - xTakeUntil(handle.unparsed, () => Position(start, curOffset, start), "") + xTakeUntil(handle.unparsed, () => Span(start, curOffset, start), "") } /** Comment ::= '' @@ -175,11 +176,11 @@ object MarkupParsers { def xComment: Tree = { val start = curOffset - 2 // Rewinding to include " Position(start, curOffset, start), "-->") + xTakeUntil(handle.comment, () => Span(start, curOffset, start), "-->") } - def appendText(pos: Position, ts: Buffer[Tree], txt: String): Unit = { - def append(t: String) = ts append handle.text(pos, t) + def appendText(span: Span, ts: Buffer[Tree], txt: String): Unit = { + def append(t: String) = ts append handle.text(span, t) if (preserveWS) append(txt) else { @@ -219,7 +220,7 @@ object MarkupParsers { * @precond ch == '{' * @postcond: xEmbeddedBlock == false! */ - def content_BRACE(p: Position, ts: ArrayBuffer[Tree]): Unit = + def content_BRACE(p: Span, ts: ArrayBuffer[Tree]): Unit = if (xCheckEmbeddedBlock) ts append xEmbeddedExpr else appendText(p, ts, xText) @@ -249,7 +250,7 @@ object MarkupParsers { if (xEmbeddedBlock) ts append xEmbeddedExpr else { - tmppos = Position(curOffset) + tmppos = Span(curOffset) ch match { // end tag, cdata, comment, pi or child node case '<' => nextch() ; if (content_LT(ts)) return ts @@ -274,7 +275,7 @@ object MarkupParsers { val (qname, attrMap) = xTag(()) if (ch == '/') { // empty element xToken("/>") - handle.element(Position(start, curOffset, start), qname, attrMap, true, new ListBuffer[Tree]) + handle.element(Span(start, curOffset, start), qname, attrMap, true, new ListBuffer[Tree]) } else { // handle content xToken('>') @@ -285,10 +286,10 @@ object MarkupParsers { val ts = content xEndTag(qname) debugLastStartElement = debugLastStartElement.tail - val pos = Position(start, curOffset, start) + val span = Span(start, curOffset, start) qname match { - case "xml:group" => handle.group(pos, ts) - case _ => handle.element(pos, qname, attrMap, false, ts) + case "xml:group" => handle.group(span, ts) + case _ => handle.element(span, qname, attrMap, false, ts) } } } @@ -355,7 +356,7 @@ object MarkupParsers { val ts = new ArrayBuffer[Tree] val start = curOffset - tmppos = Position(curOffset) // Iuli: added this line, as it seems content_LT uses tmppos when creating trees + tmppos = Span(curOffset) // Iuli: added this line, as it seems content_LT uses tmppos when creating trees content_LT(ts) // parse more XML ? @@ -366,7 +367,7 @@ object MarkupParsers { ts append element xSpaceOpt() } - handle.makeXMLseq(Position(start, curOffset, start), ts) + handle.makeXMLseq(Span(start, curOffset, start), ts) } else { assert(ts.length == 1) @@ -410,7 +411,7 @@ object MarkupParsers { */ def xScalaPatterns: List[Tree] = escapeToScala(parser.patterns(), "pattern") - def reportSyntaxError(pos: Int, str: String): Unit = parser.syntaxError(str, pos) + def reportSyntaxError(offset: Int, str: String): Unit = parser.syntaxError(str, offset) def reportSyntaxError(str: String): Unit = { reportSyntaxError(curOffset, "in XML literal: " + str) nextch() @@ -453,7 +454,7 @@ object MarkupParsers { throw TruncatedXMLControl case _ => // text - appendText(Position(start1, curOffset, start1), ts, xText) + appendText(Span(start1, curOffset, start1), ts, xText) // here xEmbeddedBlock might be true: // if (xEmbeddedBlock) throw new ApplicationError("after:" + text); // assert } @@ -465,7 +466,7 @@ object MarkupParsers { debugLastStartElement = debugLastStartElement.tail } - handle.makeXMLpat(Position(start, curOffset, start), qname, ts) + handle.makeXMLpat(Span(start, curOffset, start), qname, ts) } } /* class MarkupParser */ } diff --git a/compiler/src/dotty/tools/dotc/parsing/xml/SymbolicXMLBuilder.scala b/compiler/src/dotty/tools/dotc/parsing/xml/SymbolicXMLBuilder.scala index 32a2bbbc714e..393fd0a5f626 100644 --- a/compiler/src/dotty/tools/dotc/parsing/xml/SymbolicXMLBuilder.scala +++ b/compiler/src/dotty/tools/dotc/parsing/xml/SymbolicXMLBuilder.scala @@ -9,7 +9,7 @@ import Decorators._ import Flags.Mutable import Names._, StdNames._, ast.Trees._, ast.{tpd, untpd} import Symbols._, Contexts._ -import util.Positions._ +import util.Spans._ import Parsers.Parser /** This class builds instance of `Tree` that represent XML. @@ -28,7 +28,7 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont import Constants.Constant import untpd._ - import parser.atPos + import parser.atSpan private[parsing] var isPattern: Boolean = _ @@ -89,7 +89,7 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont /** Wildly wrong documentation deleted in favor of "self-documenting code." */ protected def mkXML( - pos: Position, + span: Span, isPattern: Boolean, pre: Tree, label: Tree, @@ -100,41 +100,41 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont { def starArgs = if (children.isEmpty) Nil - else List(Typed(makeXMLseq(pos, children), wildStar)) + else List(Typed(makeXMLseq(span, children), wildStar)) def pat = Apply(_scala_xml__Elem, List(pre, label, wild, wild) ::: convertToTextPat(children)) def nonpat = New(_scala_xml_Elem, List(List(pre, label, attrs, scope, if (empty) Literal(Constant(true)) else Literal(Constant(false))) ::: starArgs)) - atPos(pos) { if (isPattern) pat else nonpat } + atSpan(span) { if (isPattern) pat else nonpat } } - final def entityRef(pos: Position, n: String): Tree = - atPos(pos)( New(_scala_xml_EntityRef, LL(const(n))) ) + final def entityRef(span: Span, n: String): Tree = + atSpan(span)( New(_scala_xml_EntityRef, LL(const(n))) ) // create scala.xml.Text here <: scala.xml.Node - final def text(pos: Position, txt: String): Tree = atPos(pos) { + final def text(span: Span, txt: String): Tree = atSpan(span) { if (isPattern) makeTextPat(const(txt)) else makeText1(const(txt)) } def makeTextPat(txt: Tree): Apply = Apply(_scala_xml__Text, List(txt)) def makeText1(txt: Tree): Tree = New(_scala_xml_Text, LL(txt)) - def comment(pos: Position, text: String): Tree = atPos(pos)( Comment(const(text)) ) - def charData(pos: Position, txt: String): Tree = atPos(pos)( makeText1(const(txt)) ) + def comment(span: Span, text: String): Tree = atSpan(span)( Comment(const(text)) ) + def charData(span: Span, txt: String): Tree = atSpan(span)( makeText1(const(txt)) ) - def procInstr(pos: Position, target: String, txt: String): Tree = - atPos(pos)( ProcInstr(const(target), const(txt)) ) + def procInstr(span: Span, target: String, txt: String): Tree = + atSpan(span)( ProcInstr(const(target), const(txt)) ) protected def Comment(txt: Tree): Tree = New(_scala_xml_Comment, LL(txt)) protected def ProcInstr(target: Tree, txt: Tree): Tree = New(_scala_xml_ProcInstr, LL(target, txt)) /** @todo: attributes */ - def makeXMLpat(pos: Position, n: String, args: Seq[Tree]): Tree = { + def makeXMLpat(span: Span, n: String, args: Seq[Tree]): Tree = { val (prepat, labpat) = splitPrefix(n) match { case (Some(pre), rest) => (const(pre), const(rest)) case _ => (wild, const(n)) } - mkXML(pos, true, prepat, labpat, null, null, false, args) + mkXML(span, true, prepat, labpat, null, null, false, args) } protected def convertToTextPat(t: Tree): Tree = t match { @@ -144,12 +144,12 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont protected def convertToTextPat(buf: Seq[Tree]): List[Tree] = (buf map convertToTextPat).toList - def parseAttribute(pos: Position, s: String): Tree = { - val ts = Utility.parseAttributeValue(s, text(pos, _), entityRef(pos, _)) + def parseAttribute(span: Span, s: String): Tree = { + val ts = Utility.parseAttributeValue(s, text(span, _), entityRef(span, _)) ts match { - case Nil => TypedSplice(tpd.ref(defn.NilModule) withPos pos) + case Nil => TypedSplice(tpd.ref(defn.NilModule).withSpan(span)) case t :: Nil => t - case _ => makeXMLseq(pos, ts) + case _ => makeXMLseq(span, ts) } } @@ -159,11 +159,11 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont } /** could optimize if args.length == 0, args.length == 1 AND args(0) is <: Node. */ - def makeXMLseq(pos: Position, args: Seq[Tree]): Block = { + def makeXMLseq(span: Span, args: Seq[Tree]): Block = { val buffer = ValDef(_buf, TypeTree(), New(_scala_xml_NodeBuffer, ListOfNil)) val applies = args filterNot isEmptyText map (t => Apply(Select(Ident(_buf), _plus), List(t))) - atPos(pos)( Block(buffer :: applies.toList, Ident(_buf)) ) + atSpan(span)( Block(buffer :: applies.toList, Ident(_buf)) ) } /** Returns (Some(prefix) | None, rest) based on position of ':' */ @@ -173,13 +173,13 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont } /** Various node constructions. */ - def group(pos: Position, args: Seq[Tree]): Tree = - atPos(pos)( New(_scala_xml_Group, LL(makeXMLseq(pos, args))) ) + def group(span: Span, args: Seq[Tree]): Tree = + atSpan(span)( New(_scala_xml_Group, LL(makeXMLseq(span, args))) ) - def unparsed(pos: Position, str: String): Tree = - atPos(pos)( New(_scala_xml_Unparsed, LL(const(str))) ) + def unparsed(span: Span, str: String): Tree = + atSpan(span)( New(_scala_xml_Unparsed, LL(const(str))) ) - def element(pos: Position, qname: String, attrMap: mutable.Map[String, Tree], empty: Boolean, args: Seq[Tree]): Tree = { + def element(span: Span, qname: String, attrMap: mutable.Map[String, Tree], empty: Boolean, args: Seq[Tree]): Tree = { def handleNamespaceBinding(pre: String, z: String): Tree = { def mkAssign(t: Tree): Tree = Assign( Ident(_tmpscope), @@ -210,7 +210,7 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont case (None, x) => (null, x) } - def mkAttributeTree(pre: String, key: String, value: Tree) = atPos(pos.toSynthetic) { + def mkAttributeTree(pre: String, key: String, value: Tree) = atSpan(span.toSynthetic) { // XXX this is where we'd like to put Select(value, nme.toString_) for #1787 // after we resolve the Some(foo) situation. val baseArgs = List(const(key), value, Ident(_md)) @@ -244,7 +244,7 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont } val body = mkXML( - pos.toSynthetic, + span.toSynthetic, false, const(pre), const(newlabel), @@ -254,6 +254,6 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont args ) - atPos(pos.toSynthetic)(new XMLBlock(nsResult, new XMLBlock(attrResult, body))) + atSpan(span.toSynthetic)(new XMLBlock(nsResult, new XMLBlock(attrResult, body))) } } diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 4255a8a175f7..60d9d4545488 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -42,6 +42,7 @@ class PlainPrinter(_ctx: Context) extends Printer { /** If true, tweak output so it is the same before and after pickling */ protected def homogenizedView: Boolean = ctx.settings.YtestPickler.value + protected def debugPos: Boolean = ctx.settings.YdebugPos.value def homogenize(tp: Type): Type = if (homogenizedView) @@ -502,13 +503,14 @@ class PlainPrinter(_ctx: Context) extends Printer { else Text() - nodeName ~ "(" ~ elems ~ tpSuffix ~ ")" ~ (Str(tree.pos.toString) provided ctx.settings.YprintPos.value) + nodeName ~ "(" ~ elems ~ tpSuffix ~ ")" ~ (Str(tree.sourcePos.toString) provided ctx.settings.YprintPos.value) }.close // todo: override in refined printer - def toText(pos: SourcePosition): Text = + def toText(pos: SourcePosition): Text = { if (!pos.exists) "" - else if (pos.source.exists) s"${pos.source.file}:${pos.line + 1}" - else s"(no source file, offset = ${pos.pos.point})" + else if (pos.source.exists) s"${pos.source.file.name}:${pos.line + 1}" + else s"(no source file, offset = ${pos.span.point})" + } def toText(result: SearchResult): Text = result match { case result: SearchSuccess => diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 849c0c5d7826..5344e738e79c 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -311,7 +311,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { val txt = tree.typeOpt match { case tp: NamedType if name != nme.WILDCARD => val pre = if (tp.symbol is JavaStatic) tp.prefix.widen else tp.prefix - toTextPrefix(pre) ~ withPos(selectionString(tp), tree.pos) + toTextPrefix(pre) ~ withPos(selectionString(tp), tree.sourcePos) case _ => toText(name) } @@ -340,8 +340,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { typeApplyText(tree) case Literal(c) => tree.typeOpt match { - case ConstantType(tc) => withPos(toText(tc), tree.pos) - case _ => withPos(toText(c), tree.pos) + case ConstantType(tc) => withPos(toText(tc), tree.sourcePos) + case _ => withPos(toText(c), tree.sourcePos) } case New(tpt) => keywordStr("new ") ~ { @@ -506,7 +506,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case SymbolLit(str) => "'" + str case InterpolatedString(id, segments) => - def strText(str: Literal) = withPos(escapedString(str.const.stringValue), tree.pos) + def strText(str: Literal) = withPos(escapedString(str.const.stringValue), tree.sourcePos) def segmentText(segment: Tree) = segment match { case Thicket(List(str: Literal, expr)) => strText(str) ~ "{" ~ toTextGlobal(expr) ~ "}" case str: Literal => strText(str) @@ -603,15 +603,18 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } if (!suppressPositions) { if (printPos) { - val pos = - if (homogenizedView && !tree.isInstanceOf[MemberDef]) tree.pos.toSynthetic - else tree.pos + val posStr = + if (homogenizedView || debugPos) + if (tree.isInstanceOf[MemberDef]) Str(s"${tree.source}${tree.span}") + else Str(s"${tree.source}${tree.span.toSynthetic}") + else + "<" ~ toText(tree.sourcePos) ~ ">" val clsStr = ""//if (tree.isType) tree.getClass.toString else "" - txt = (txt ~ "@" ~ pos.toString ~ clsStr).close + txt = (txt ~ "@" ~ posStr ~ clsStr).close } if (ctx.settings.YprintPosSyms.value && tree.isDef) txt = (txt ~ - s"@@(${tree.symbol.name}=" ~ tree.symbol.pos.toString ~ ")").close + s"@@(${tree.symbol.name}=" ~ tree.symbol.sourcePos.toString ~ ")").close } if (ctx.settings.YshowTreeIds.value) txt = (txt ~ "#" ~ tree.uniqueId.toString).close @@ -647,8 +650,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (tree.hasType && tree.symbol.exists) { val str: Text = nameString(tree.symbol) tree match { - case tree: RefTree => withPos(str, tree.pos) - case tree: MemberDef => withPos(str, tree.namePos) + case tree: RefTree => withPos(str, tree.sourcePos) + case tree: MemberDef => withPos(str, tree.sourcePos.withSpan(tree.nameSpan)) case _ => str } } diff --git a/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala b/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala index 989a3804e23a..96f091c392b3 100644 --- a/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala +++ b/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala @@ -7,7 +7,7 @@ import dotty.tools.dotc.parsing.Parsers.Parser import dotty.tools.dotc.parsing.Scanners.Scanner import dotty.tools.dotc.parsing.Tokens._ import dotty.tools.dotc.reporting.Reporter -import dotty.tools.dotc.util.Positions.Position +import dotty.tools.dotc.util.Spans.Span import dotty.tools.dotc.util.SourceFile import java.util.Arrays @@ -33,19 +33,19 @@ object SyntaxHighlighting { if (in.isEmpty || ctx.settings.color.value == "never") in else { implicit val ctx = freshCtx - val source = new SourceFile("", in) + val source = SourceFile.virtual("", in) val colorAt = Array.fill(in.length)(NoColor) def highlightRange(from: Int, to: Int, color: String) = Arrays.fill(colorAt.asInstanceOf[Array[AnyRef]], from, to, color) - def highlightPosition(pos: Position, color: String) = if (pos.exists) { - if (pos.start < 0 || pos.end > in.length) { + def highlightPosition(span: Span, color: String) = if (span.exists) { + if (span.start < 0 || span.end > in.length) { if (debug) - println(s"Trying to highlight erroneous position $pos. Input size: ${in.length}") + println(s"Trying to highlight erroneous position $span. Input size: ${in.length}") } else - highlightRange(pos.start, pos.end, color) + highlightRange(span.start, span.end, color) } val scanner = new Scanner(source) @@ -78,8 +78,8 @@ object SyntaxHighlighting { } } - for (pos <- scanner.commentPositions) - highlightPosition(pos, CommentColor) + for (span <- scanner.commentSpans) + highlightPosition(span, CommentColor) object TreeHighlighter extends untpd.UntypedTreeTraverser { import untpd._ @@ -92,7 +92,7 @@ object SyntaxHighlighting { def highlightAnnotations(tree: MemberDef): Unit = for (annotation <- tree.rawMods.annotations) - highlightPosition(annotation.pos, AnnotationColor) + highlightPosition(annotation.span, AnnotationColor) def highlight(trees: List[Tree])(implicit ctx: Context): Unit = trees.foreach(traverse) @@ -103,14 +103,14 @@ object SyntaxHighlighting { () case tree: ValOrDefDef => highlightAnnotations(tree) - highlightPosition(tree.namePos, ValDefColor) + highlightPosition(tree.nameSpan, ValDefColor) case tree: MemberDef /* ModuleDef | TypeDef */ => highlightAnnotations(tree) - highlightPosition(tree.namePos, TypeColor) + highlightPosition(tree.nameSpan, TypeColor) case tree: Ident if tree.isType => - highlightPosition(tree.pos, TypeColor) + highlightPosition(tree.span, TypeColor) case _: TypTree => - highlightPosition(tree.pos, TypeColor) + highlightPosition(tree.span, TypeColor) case _ => } traverseChildren(tree) diff --git a/compiler/src/dotty/tools/dotc/quoted/QuoteCompiler.scala b/compiler/src/dotty/tools/dotc/quoted/QuoteCompiler.scala index ad5a81b89f69..7d2650c5e0a6 100644 --- a/compiler/src/dotty/tools/dotc/quoted/QuoteCompiler.scala +++ b/compiler/src/dotty/tools/dotc/quoted/QuoteCompiler.scala @@ -15,7 +15,7 @@ import dotty.tools.dotc.core.Symbols.defn import dotty.tools.dotc.core.Types.ExprType import dotty.tools.dotc.core.quoted.PickledQuotes import dotty.tools.dotc.transform.Staging -import dotty.tools.dotc.util.Positions.Position +import dotty.tools.dotc.util.Spans.Span import dotty.tools.dotc.util.SourceFile import dotty.tools.io.{Path, VirtualFile} @@ -51,13 +51,13 @@ class QuoteCompiler extends Compiler { val tree = if (putInClass) inClass(exprUnit.expr) else PickledQuotes.quotedExprToTree(exprUnit.expr) - val source = new SourceFile("", "") - CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true) + val source = SourceFile.virtual("", "") + CompilationUnit(source, tree, forceTrees = true) case typeUnit: TypeCompilationUnit => assert(!putInClass) val tree = PickledQuotes.quotedTypeToTree(typeUnit.tpe) - val source = new SourceFile("", "") - CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true) + val source = SourceFile.virtual("", "") + CompilationUnit(source, tree, forceTrees = true) } } @@ -66,7 +66,7 @@ class QuoteCompiler extends Compiler { * `package __root__ { class ' { def apply: Any = } }` */ private def inClass(expr: Expr[_])(implicit ctx: Context): Tree = { - val pos = Position(0) + val pos = Span(0) val assocFile = new VirtualFile("") val cls = ctx.newCompleteClassSymbol(defn.RootClass, outputClassName, EmptyFlags, @@ -78,7 +78,7 @@ class QuoteCompiler extends Compiler { val run = DefDef(meth, quoted) val classTree = ClassDef(cls, DefDef(cls.primaryConstructor.asTerm), run :: Nil) - PackageDef(ref(defn.RootPackage).asInstanceOf[Ident], classTree :: Nil).withPos(pos) + PackageDef(ref(defn.RootPackage).asInstanceOf[Ident], classTree :: Nil).withSpan(pos) } def run(implicit ctx: Context): Unit = unsupported("run") diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index ef3352126100..47c4a34ad972 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -2093,7 +2093,7 @@ object messages { case _ /* Signature.FullMatch */ => "\nThe definitions have matching type signatures after erasure." } } else "" - hl"${decl.showLocated} is already defined as ${previousDecl.showDcl} ${if (previousDecl.pos.exists) s"at line ${previousDecl.pos.line + 1}" else ""}." + details + hl"${decl.showLocated} is already defined as ${previousDecl.showDcl} ${if (previousDecl.span.exists) s"at line ${previousDecl.sourcePos.line + 1}" else ""}." + details } val explanation: String = "" } diff --git a/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala b/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala index 34b29d7c54bf..d640544151ca 100644 --- a/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala +++ b/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala @@ -1,8 +1,8 @@ package dotty.tools.dotc package rewrites -import util.{SourceFile, Positions} -import Positions.Position +import util.{SourceFile, Spans} +import Spans.Span import core.Contexts.Context import collection.mutable import scala.annotation.tailrec @@ -12,36 +12,36 @@ import dotty.tools.dotc.reporting.Reporter object Rewrites { private class PatchedFiles extends mutable.HashMap[SourceFile, Patches] - private case class Patch(pos: Position, replacement: String) { - def delta = replacement.length - (pos.end - pos.start) + private case class Patch(span: Span, replacement: String) { + def delta = replacement.length - (span.end - span.start) } private class Patches(source: SourceFile) { private val pbuf = new mutable.ListBuffer[Patch]() - def addPatch(pos: Position, replacement: String): Unit = - pbuf += Patch(pos, replacement) + def addPatch(span: Span, replacement: String): Unit = + pbuf += Patch(span, replacement) def apply(cs: Array[Char]): Array[Char] = { val delta = pbuf.map(_.delta).sum - val patches = pbuf.toList.sortBy(_.pos.start) + val patches = pbuf.toList.sortBy(_.span.start) if (patches.nonEmpty) patches reduceLeft {(p1, p2) => - assert(p1.pos.end <= p2.pos.start, s"overlapping patches: $p1 and $p2") + assert(p1.span.end <= p2.span.start, s"overlapping patches: $p1 and $p2") p2 } val ds = new Array[Char](cs.length + delta) @tailrec def loop(ps: List[Patch], inIdx: Int, outIdx: Int): Unit = { def copy(upTo: Int): Int = { val untouched = upTo - inIdx - Array.copy(cs, inIdx, ds, outIdx, untouched) + System.arraycopy(cs, inIdx, ds, outIdx, untouched) outIdx + untouched } ps match { - case patch @ Patch(pos, replacement) :: ps1 => - val outNew = copy(pos.start) + case patch @ Patch(span, replacement) :: ps1 => + val outNew = copy(span.start) replacement.copyToArray(ds, outNew) - loop(ps1, pos.end, outNew + replacement.length) + loop(ps1, span.end, outNew + replacement.length) case Nil => val outNew = copy(cs.length) assert(outNew == ds.length, s"$outNew != ${ds.length}") @@ -61,18 +61,18 @@ object Rewrites { } /** If -rewrite is set, record a patch that replaces the range - * given by `pos` in `source` by `replacement` + * given by `span` in `source` by `replacement` */ - def patch(source: SourceFile, pos: Position, replacement: String)(implicit ctx: Context): Unit = + def patch(source: SourceFile, span: Span, replacement: String)(implicit ctx: Context): Unit = if (ctx.reporter != Reporter.NoReporter) // NoReporter is used for syntax highlighting for (rewrites <- ctx.settings.rewrite.value) rewrites.patched .getOrElseUpdate(source, new Patches(source)) - .addPatch(pos, replacement) + .addPatch(span, replacement) /** Patch position in `ctx.compilationUnit.source`. */ - def patch(pos: Position, replacement: String)(implicit ctx: Context): Unit = - patch(ctx.compilationUnit.source, pos, replacement) + def patch(span: Span, replacement: String)(implicit ctx: Context): Unit = + patch(ctx.compilationUnit.source, span, replacement) /** If -rewrite is set, apply all patches and overwrite patched source files. */ diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index 8634ad928920..00833d205d9e 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -246,7 +246,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder case ex: TypeError => // See neg/i1750a for an example where a cyclic error can arise. // The root cause in this example is an illegal "override" of an inner trait - ctx.error(ex.toMessage, csym.pos) + ctx.error(ex.toMessage, csym.sourcePos) defn.ObjectType :: Nil } if (ValueClasses.isDerivedValueClass(csym)) { diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala index 22b30e500e6e..8fb7a2cee309 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala @@ -235,7 +235,7 @@ private class ExtractDependenciesCollector extends tpd.TreeTraverser { thisTreeT ctx.warning("""|No class, trait or object is defined in the compilation unit. |The incremental compiler cannot record the dependency information in such case. |Some errors like unused import referring to a non-existent class might not be reported. - |""".stripMargin, tree.pos) + |""".stripMargin, tree.sourcePos) } _responsibleForImports } diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/ContextOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/ContextOpsImpl.scala index ef65bb4d9671..acac5c915e68 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/ContextOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/ContextOpsImpl.scala @@ -1,6 +1,6 @@ package dotty.tools.dotc.tastyreflect -import dotty.tools.dotc.util.{Positions, SourcePosition} +import dotty.tools.dotc.util.{Spans, SourcePosition} trait ContextOpsImpl extends scala.tasty.reflect.ContextOps with CoreImpl { @@ -12,6 +12,6 @@ trait ContextOpsImpl extends scala.tasty.reflect.ContextOps with CoreImpl { def source: java.nio.file.Path = ctx.compilationUnit.source.file.jpath } - def rootPosition: SourcePosition = SourcePosition(rootContext.source, Positions.NoPosition) + def rootPosition: SourcePosition = SourcePosition(rootContext.source, Spans.NoSpan) } diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/IdOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/IdOpsImpl.scala index e603babc3eb8..17330bae1a6b 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/IdOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/IdOpsImpl.scala @@ -5,7 +5,7 @@ import dotty.tools.dotc.core.Decorators._ trait IdOpsImpl extends scala.tasty.reflect.IdOps with CoreImpl { def IdDeco(id: Id): IdAPI = new IdAPI { - def pos(implicit ctx: Context): Position = id.pos + def pos(implicit ctx: Context): Position = id.sourcePos def name(implicit ctx: Context): String = id.name.toString } diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/PatternOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/PatternOpsImpl.scala index af972be8b896..88d6df9723dd 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/PatternOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/PatternOpsImpl.scala @@ -34,7 +34,7 @@ trait PatternOpsImpl extends scala.tasty.reflect.PatternOps with CoreImpl { // ----- Patterns ------------------------------------------------- def PatternDeco(pattern: Pattern): PatternAPI = new PatternAPI { - def pos(implicit ctx: Context): Position = pattern.pos + def pos(implicit ctx: Context): Position = pattern.sourcePos def tpe(implicit ctx: Context): Type = pattern.tpe.stripTypeVar } diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/QuotedOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/QuotedOpsImpl.scala index 0aee5d39f569..b527e12f44e8 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/QuotedOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/QuotedOpsImpl.scala @@ -51,8 +51,8 @@ trait QuotedOpsImpl extends scala.tasty.reflect.QuotedOps with CoreImpl { def TypeToQuoteDeco(tpe: Types.Type): TypeToQuotedAPI = new TypeToQuotedAPI { def seal(implicit ctx: Context): quoted.Type[_] = { - val dummyPos = ctx.owner.pos // FIXME - new scala.quoted.Types.TreeType(tpd.TypeTree(tpe).withPos(dummyPos)) + val dummySpan = ctx.owner.span // FIXME + new scala.quoted.Types.TreeType(tpd.TypeTree(tpe).withSpan(dummySpan)) } } } diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/SymbolOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/SymbolOpsImpl.scala index fcf3da51314a..9f57f543effe 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/SymbolOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/SymbolOpsImpl.scala @@ -26,7 +26,7 @@ trait SymbolOpsImpl extends scala.tasty.reflect.SymbolOps with CoreImpl { def name(implicit ctx: Context): String = symbol.name.toString def fullName(implicit ctx: Context): String = symbol.fullName.toString - def pos(implicit ctx: Context): Position = symbol.pos + def pos(implicit ctx: Context): Position = symbol.sourcePos def owner(implicit ctx: Context): Symbol = symbol.owner diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala index 49b221a22947..69788d1efcb4 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala @@ -10,7 +10,7 @@ import dotty.tools.dotc.tastyreflect.FromSymbol.{definitionFromSym, packageDefFr trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers { def TreeDeco(tree: Tree): TreeAPI = new TreeAPI { - def pos(implicit ctx: Context): Position = tree.pos + def pos(implicit ctx: Context): Position = tree.sourcePos def symbol(implicit ctx: Context): Symbol = tree.symbol } @@ -353,7 +353,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers def TermDeco(term: Term): TermAPI = new TermAPI { import tpd._ - def pos(implicit ctx: Context): Position = term.pos + def pos(implicit ctx: Context): Position = term.sourcePos def tpe(implicit ctx: Context): Type = term.tpe def underlyingArgument(implicit ctx: Context): Term = term.underlyingArgument def underlying(implicit ctx: Context): Term = term.underlying @@ -444,7 +444,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers def apply(cls: ClassSymbol)(implicit ctx: Context): This = tpd.This(cls) - def copy(original: Tree)(qual: Option[Id]): This = + def copy(original: Tree)(qual: Option[Id])(implicit ctx: Context): This = tpd.cpy.This(original)(qual.getOrElse(untpd.EmptyTypeIdent)) def unapply(x: Term)(implicit ctx: Context): Option[Option[Id]] = x match { @@ -555,7 +555,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers def apply(qual: Term, mix: Option[Id])(implicit ctx: Context): Super = tpd.Super(qual, mix.getOrElse(untpd.EmptyTypeIdent), false, NoSymbol) - def copy(original: Tree)(qual: Term, mix: Option[Id]): Super = + def copy(original: Tree)(qual: Term, mix: Option[Id])(implicit ctx: Context): Super = tpd.cpy.Super(original)(qual, mix.getOrElse(untpd.EmptyTypeIdent)) def unapply(x: Term)(implicit ctx: Context): Option[(Term, Option[Id])] = x match { diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala index 2bf439ba3d28..9072ee2a72e4 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala @@ -9,7 +9,7 @@ import dotty.tools.dotc.core.{Contexts, Types} trait TypeOrBoundsTreesOpsImpl extends scala.tasty.reflect.TypeOrBoundsTreeOps with CoreImpl { def TypeTreeDeco(tpt: TypeTree): TypeTreeAPI = new TypeTreeAPI { - def pos(implicit ctx: Context): Position = tpt.pos + def pos(implicit ctx: Context): Position = tpt.sourcePos def symbol(implicit ctx: Context): Symbol = tpt.symbol def tpe(implicit ctx: Context): Type = tpt.tpe.stripTypeVar } @@ -407,7 +407,7 @@ trait TypeOrBoundsTreesOpsImpl extends scala.tasty.reflect.TypeOrBoundsTreeOps w // TODO only enums generate this kind of type bounds. Is this possible without enums? If not generate tpd.TypeBoundsTree for enums instead x.tpe match { case tpe: Types.TypeBounds => - Some(tpd.TypeBoundsTree(tpd.TypeTree(tpe.lo).withPos(x.pos), tpd.TypeTree(tpe.hi).withPos(x.pos))) + Some(tpd.TypeBoundsTree(tpd.TypeTree(tpe.lo).withSpan(x.span), tpd.TypeTree(tpe.hi).withSpan(x.span))) case _ => None } case _ => None diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/package.scala b/compiler/src/dotty/tools/dotc/tastyreflect/package.scala index d13dc0f322b0..5fc55927136d 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/package.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/package.scala @@ -5,13 +5,15 @@ import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.Symbols.Symbol import dotty.tools.dotc.core.Types.Type import dotty.tools.dotc.core.SymDenotations.SymDenotation +import scala.annotation.constructorOnly +import util.SourceFile package object tastyreflect { type PackageDefinition = PackageDefinitionImpl[Type] /** Represents the symbol of a definition in tree form */ - case class PackageDefinitionImpl[-T >: Untyped] private[tastyreflect] (sym: Symbol) extends Tree[T] { + case class PackageDefinitionImpl[-T >: Untyped] private[tastyreflect] (sym: Symbol)(implicit @constructorOnly src: SourceFile) extends Tree[T] { type ThisTree[-T >: Untyped] = PackageDefinitionImpl[T] override def denot(implicit ctx: Context): SymDenotation = sym.denot diff --git a/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala b/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala index 03782a0436bc..5bad3e5d53ea 100644 --- a/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala +++ b/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala @@ -12,7 +12,7 @@ import TypeUtils._ import Types._ import NameKinds.ClassifiedNameKind import ast.Trees._ -import util.Positions.Position +import util.Spans.Span import config.Printers.transforms /** A utility class for generating access proxies. Currently used for @@ -53,7 +53,7 @@ abstract class AccessProxies { accessRef.becomes(forwardedArgss.head.head) else accessRef.appliedToTypes(forwardedTypes).appliedToArgss(forwardedArgss) - rhs.withPos(accessed.pos) + rhs.withSpan(accessed.span) }) /** Add all needed accessors to the `body` of class `cls` */ @@ -75,8 +75,8 @@ abstract class AccessProxies { } /** A fresh accessor symbol */ - private def newAccessorSymbol(owner: Symbol, name: TermName, info: Type, pos: Position)(implicit ctx: Context): TermSymbol = { - val sym = ctx.newSymbol(owner, name, Synthetic | Method, info, coord = pos).entered + private def newAccessorSymbol(owner: Symbol, name: TermName, info: Type, span: Span)(implicit ctx: Context): TermSymbol = { + val sym = ctx.newSymbol(owner, name, Synthetic | Method, info, coord = span).entered if (sym.allOverriddenSymbols.exists(!_.is(Deferred))) sym.setFlag(Override) sym } @@ -85,7 +85,7 @@ abstract class AccessProxies { protected def accessorSymbol(owner: Symbol, accessorName: TermName, accessorInfo: Type, accessed: Symbol)(implicit ctx: Context): Symbol = { def refersToAccessed(sym: Symbol) = accessedBy.get(sym).contains(accessed) owner.info.decl(accessorName).suchThat(refersToAccessed).symbol.orElse { - val acc = newAccessorSymbol(owner, accessorName, accessorInfo, accessed.pos) + val acc = newAccessorSymbol(owner, accessorName, accessorInfo, accessed.span) accessedBy(acc) = accessed acc } @@ -97,7 +97,7 @@ abstract class AccessProxies { case Select(qual, _) if qual.tpe.derivesFrom(accessor.owner) => qual.select(accessor) case _ => ref(accessor) } - }.withPos(reference.pos) + }.withSpan(reference.span) /** Given a reference to a getter accessor, the corresponding setter reference */ def useSetter(getterRef: Tree)(implicit ctx: Context): Tree = getterRef match { @@ -143,7 +143,7 @@ abstract class AccessProxies { def accessorIfNeeded(tree: Tree)(implicit ctx: Context): Tree = tree match { case tree: RefTree if needsAccessor(tree.symbol) => if (tree.symbol.isConstructor) { - ctx.error("Implementation restriction: cannot use private constructors in inlineable methods", tree.pos) + ctx.error("Implementation restriction: cannot use private constructors in inlineable methods", tree.sourcePos) tree // TODO: create a proper accessor for the private constructor } else useAccessor(tree) diff --git a/compiler/src/dotty/tools/dotc/transform/ArrayConstructors.scala b/compiler/src/dotty/tools/dotc/transform/ArrayConstructors.scala index b524d060d4a2..e234ab76213d 100644 --- a/compiler/src/dotty/tools/dotc/transform/ArrayConstructors.scala +++ b/compiler/src/dotty/tools/dotc/transform/ArrayConstructors.scala @@ -26,7 +26,7 @@ class ArrayConstructors extends MiniPhase { override def transformApply(tree: tpd.Apply)(implicit ctx: Context): tpd.Tree = { def expand(elemType: Type, dims: List[Tree]) = - tpd.newArray(elemType, tree.tpe, tree.pos, JavaSeqLiteral(dims, TypeTree(defn.IntClass.typeRef))) + tpd.newArray(elemType, tree.tpe, tree.span, JavaSeqLiteral(dims, TypeTree(defn.IntClass.typeRef))) if (tree.fun.symbol eq defn.ArrayConstructor) { val TypeApply(tycon, targ :: Nil) = tree.fun diff --git a/compiler/src/dotty/tools/dotc/transform/Bridges.scala b/compiler/src/dotty/tools/dotc/transform/Bridges.scala index ca9550f09400..884d5c71f2fd 100644 --- a/compiler/src/dotty/tools/dotc/transform/Bridges.scala +++ b/compiler/src/dotty/tools/dotc/transform/Bridges.scala @@ -8,7 +8,8 @@ import DenotTransformers._ import ast.untpd import collection.{mutable, immutable} import ShortcutImplicits._ -import util.Positions.Position +import util.Spans.Span +import util.SourcePosition /** A helper class for generating bridge methods in class `root`. */ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Context) { @@ -40,8 +41,8 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont private val bridgesScope = newScope private val bridgeTarget = newMutableSymbolMap[Symbol] - def bridgePosFor(member: Symbol): Position = - if (member.owner == root && member.pos.exists) member.pos else root.pos + def bridgePosFor(member: Symbol): SourcePosition = + (if (member.owner == root && member.span.exists) member else root).sourcePos /** Add a bridge between `member` and `other`, where `member` overrides `other` * before erasure, if the following conditions are satisfied. @@ -85,11 +86,11 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont owner = root, flags = (member.flags | Method | Bridge | Artifact) &~ (Accessor | ParamAccessor | CaseAccessor | Deferred | Lazy | Module), - coord = bridgePosFor(member)).enteredAfter(thisPhase).asTerm + coord = bridgePosFor(member).span).enteredAfter(thisPhase).asTerm ctx.debuglog( i"""generating bridge from ${other.showLocated}: ${other.info} - |to ${member.showLocated}: ${member.info} @ ${member.pos} + |to ${member.showLocated}: ${member.info} @ ${member.span} |bridge: ${bridge.showLocated} with flags: ${bridge.flags}""") bridgeTarget(bridge) = member @@ -106,7 +107,7 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont else ref.appliedToArgss(argss) } - bridges += DefDef(bridge, bridgeRhs(_).withPos(bridge.pos)) + bridges += DefDef(bridge, bridgeRhs(_).withSpan(bridge.span)) } /** Add all necessary bridges to template statements `stats`, and remove at the same diff --git a/compiler/src/dotty/tools/dotc/transform/ByNameClosures.scala b/compiler/src/dotty/tools/dotc/transform/ByNameClosures.scala index 8356539f9000..8db79ba87430 100644 --- a/compiler/src/dotty/tools/dotc/transform/ByNameClosures.scala +++ b/compiler/src/dotty/tools/dotc/transform/ByNameClosures.scala @@ -28,7 +28,7 @@ class ByNameClosures extends TransformByNameApply with IdentityDenotTransformer override def mkByNameClosure(arg: Tree, argType: Type)(implicit ctx: Context): Tree = { val meth = ctx.newSymbol( ctx.owner, nme.ANON_FUN, Synthetic | Method, MethodType(Nil, Nil, argType)) - Closure(meth, _ => arg.changeOwnerAfter(ctx.owner, meth, thisPhase)) + Closure(meth, _ => arg.changeOwnerAfter(ctx.owner, meth, thisPhase)).withSpan(arg.span) } } diff --git a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala index 9f03c39f92ac..6209acc906f6 100644 --- a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala +++ b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala @@ -107,7 +107,7 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisPhase = ref(vble.info.classSymbol.companionModule.info.member(name).symbol) cpy.ValDef(vdef)( rhs = boxMethod(nme.create).appliedTo(vdef.rhs), - tpt = TypeTree(vble.info).withPos(vdef.tpt.pos)) + tpt = TypeTree(vble.info).withSpan(vdef.tpt.span)) } else vdef } diff --git a/compiler/src/dotty/tools/dotc/transform/CheckStatic.scala b/compiler/src/dotty/tools/dotc/transform/CheckStatic.scala index 32dc78e0a81c..bd109c251b52 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckStatic.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckStatic.scala @@ -33,26 +33,26 @@ class CheckStatic extends MiniPhase { for(defn <- defns) { if (defn.symbol.hasAnnotation(ctx.definitions.ScalaStaticAnnot)) { if(!ctx.owner.is(Module)) { - ctx.error(StaticFieldsOnlyAllowedInObjects(defn.symbol), defn.pos) + ctx.error(StaticFieldsOnlyAllowedInObjects(defn.symbol), defn.sourcePos) } if (defn.isInstanceOf[ValDef] && hadNonStaticField) { - ctx.error(StaticFieldsShouldPrecedeNonStatic(defn.symbol, defns), defn.pos) + ctx.error(StaticFieldsShouldPrecedeNonStatic(defn.symbol, defns), defn.sourcePos) } val companion = ctx.owner.companionClass def clashes = companion.asClass.membersNamed(defn.name) if (!companion.exists) { - ctx.error(MissingCompanionForStatic(defn.symbol), defn.pos) + ctx.error(MissingCompanionForStatic(defn.symbol), defn.sourcePos) } else if (clashes.exists) { - ctx.error(MemberWithSameNameAsStatic(), defn.pos) + ctx.error(MemberWithSameNameAsStatic(), defn.sourcePos) } else if (defn.symbol.is(Flags.Mutable) && companion.is(Flags.Trait)) { - ctx.error(TraitCompanionWithMutableStatic(), defn.pos) + ctx.error(TraitCompanionWithMutableStatic(), defn.sourcePos) } else if (defn.symbol.is(Flags.Lazy)) { - ctx.error(LazyStaticField(), defn.pos) + ctx.error(LazyStaticField(), defn.sourcePos) } else if (defn.symbol.allOverriddenSymbols.nonEmpty) { - ctx.error(StaticOverridingNonStaticMembers(), defn.pos) + ctx.error(StaticOverridingNonStaticMembers(), defn.sourcePos) } } else hadNonStaticField = hadNonStaticField || defn.isInstanceOf[ValDef] diff --git a/compiler/src/dotty/tools/dotc/transform/ClassOf.scala b/compiler/src/dotty/tools/dotc/transform/ClassOf.scala index 4938d4a993d2..a9c171e65b7c 100644 --- a/compiler/src/dotty/tools/dotc/transform/ClassOf.scala +++ b/compiler/src/dotty/tools/dotc/transform/ClassOf.scala @@ -21,7 +21,7 @@ class ClassOf extends MiniPhase { override def transformTypeApply(tree: TypeApply)(implicit ctx: Context): Tree = if (tree.symbol eq defn.Predef_classOf) { val targ = tree.args.head.tpe - clsOf(targ).ensureConforms(tree.tpe).withPos(tree.pos) + clsOf(targ).ensureConforms(tree.tpe).withSpan(tree.span) } else tree } diff --git a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala index 8942d7ae6fcb..6679074bf0e3 100644 --- a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala +++ b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala @@ -11,7 +11,7 @@ import dotty.tools.dotc.core.Contexts.Context import Types._ import Decorators._ import StdNames._ -import dotty.tools.dotc.util.Positions.Position +import dotty.tools.dotc.util.SourcePosition import dotty.tools.dotc.config.JavaPlatform class CollectEntryPoints extends MiniPhase { @@ -38,10 +38,10 @@ class CollectEntryPoints extends MiniPhase { } def isJavaEntryPoint(sym: Symbol)(implicit ctx: Context): Boolean = { - def fail(msg: String, pos: Position = sym.pos) = { - ctx.warning(sym.name + - s" has a main method with parameter type Array[String], but ${sym.fullName} will not be a runnable program.\n Reason: $msg", - sourcePos(sym.pos) + def fail(msg: String, pos: SourcePosition = sym.sourcePos) = { + ctx.warning( + i"""${sym.name} has a main method with parameter type Array[String], but ${sym.fullName} will not be a runnable program. + |Reason: $msg""", sym.sourcePos // TODO: make this next claim true, if possible // by generating valid main methods as static in module classes // not sure what the jvm allows here @@ -80,11 +80,11 @@ class CollectEntryPoints extends MiniPhase { fail("main methods cannot be generic.") case t: MethodType => if (t.resultType :: t.paramInfos exists (_.typeSymbol.isAbstractType)) - fail("main methods cannot refer to type parameters or abstract types.", m.symbol.pos) + fail("main methods cannot refer to type parameters or abstract types.", m.symbol.sourcePos) else - ctx.platform.isMainMethod(m.symbol) || fail("main method must have exact signature (Array[String])Unit", m.symbol.pos) + ctx.platform.isMainMethod(m.symbol) || fail("main method must have exact signature (Array[String])Unit", m.symbol.sourcePos) case tp => - fail(s"don't know what this is: $tp", m.symbol.pos) + fail(s"don't know what this is: $tp", m.symbol.sourcePos) } } } diff --git a/compiler/src/dotty/tools/dotc/transform/Constructors.scala b/compiler/src/dotty/tools/dotc/transform/Constructors.scala index 78c440061db7..93045ba44686 100644 --- a/compiler/src/dotty/tools/dotc/transform/Constructors.scala +++ b/compiler/src/dotty/tools/dotc/transform/Constructors.scala @@ -149,7 +149,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = case Ident(_) | Select(This(_), _) => var sym = tree.symbol if (sym is (ParamAccessor, butNot = Mutable)) sym = sym.subst(accessors, paramSyms) - if (sym.owner.isConstructor) ref(sym).withPos(tree.pos) else tree + if (sym.owner.isConstructor) ref(sym).withSpan(tree.span) else tree case Apply(fn, Nil) => val fn1 = transform(fn) if ((fn1 ne fn) && fn1.symbol.is(Param) && fn1.symbol.owner.isPrimaryConstructor) @@ -195,7 +195,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = val sym = stat.symbol if (isRetained(sym)) { if (!stat.rhs.isEmpty && !isWildcardArg(stat.rhs)) - constrStats += Assign(ref(sym), intoConstr(stat.rhs, sym)).withPos(stat.pos) + constrStats += Assign(ref(sym), intoConstr(stat.rhs, sym)).withSpan(stat.span) clsStats += cpy.ValDef(stat)(rhs = EmptyTree) } else if (!stat.rhs.isEmpty) { @@ -224,11 +224,13 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = dropped += acc Nil } else { + if (acc.hasAnnotation(defn.TransientParamAnnot)) + ctx.error(em"transient parameter $acc is retained as field in class ${acc.owner}", acc.sourcePos) val target = if (acc.is(Method)) acc.field else acc if (!target.exists) Nil // this case arises when the parameter accessor is an alias else { val param = acc.subst(accessors, paramSyms) - val assigns = Assign(ref(target), ref(param)).withPos(tree.pos) :: Nil + val assigns = Assign(ref(target), ref(param)).withSpan(tree.span) :: Nil if (acc.name != nme.OUTER) assigns else { // insert test: if ($outer eq null) throw new NullPointerException diff --git a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala index d9327f53d145..ba9de3dacaaf 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala @@ -108,7 +108,7 @@ class ElimErasedValueType extends MiniPhase with InfoTransformer { |$sym1: $info1 in ${sym1.owner} and |$sym2: $info2 in ${sym2.owner} |have same type after erasure: $info""", - root.pos) + root.sourcePos) } val earlyCtx = ctx.withPhase(ctx.elimRepeatedPhase.next) while (opc.hasNext) { diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index bafea790faba..3e13e0ae3f1a 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -180,8 +180,7 @@ object Erasure { } def constant(tree: Tree, const: Tree)(implicit ctx: Context): Tree = - (if (isPureExpr(tree)) const else Block(tree :: Nil, const)) - .withPos(tree.pos) + (if (isPureExpr(tree)) const else Block(tree :: Nil, const)).withSpan(tree.span) final def box(tree: Tree, target: => String = "")(implicit ctx: Context): Tree = trace(i"boxing ${tree.showSummary}: ${tree.tpe} into $target") { tree.tpe.widen match { @@ -322,7 +321,7 @@ object Erasure { private def checkNotErased(tree: Tree)(implicit ctx: Context): tree.type = { if (tree.symbol.isEffectivelyErased && !ctx.mode.is(Mode.Type)) - ctx.error(em"${tree.symbol} is declared as erased, but is in fact used", tree.pos) + ctx.error(em"${tree.symbol} is declared as erased, but is in fact used", tree.sourcePos) tree } @@ -559,7 +558,7 @@ object Erasure { if (sym.isEffectivelyErased) erasedDef(sym) else super.typedValDef(untpd.cpy.ValDef(vdef)( - tpt = untpd.TypedSplice(TypeTree(sym.info).withPos(vdef.tpt.pos))), sym) + tpt = untpd.TypedSplice(TypeTree(sym.info).withSpan(vdef.tpt.span))), sym) /** Besides normal typing, this function also compacts anonymous functions * with more than `MaxImplementedFunctionArity` parameters to use a single @@ -592,7 +591,7 @@ object Erasure { val ddef1 = untpd.cpy.DefDef(ddef)( tparams = Nil, vparamss = vparamss1, - tpt = untpd.TypedSplice(TypeTree(restpe).withPos(ddef.tpt.pos)), + tpt = untpd.TypedSplice(TypeTree(restpe).withSpan(ddef.tpt.span)), rhs = rhs1) super.typedDefDef(ddef1, sym) } diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala b/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala index 6d945ef05f48..741d9aa92719 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala @@ -72,6 +72,7 @@ class ExpandPrivate extends MiniPhase with IdentityDenotTransformer { thisPhase // Paths `p1` and `p2` are similar if they have a common suffix that follows // possibly different directory paths. That is, their common suffix extends // in both cases either to the start of the path or to a file separator character. + // TODO: should we test absolute paths instead? def isSimilar(p1: String, p2: String): Boolean = { var i = p1.length - 1 var j = p2.length - 1 @@ -83,10 +84,10 @@ class ExpandPrivate extends MiniPhase with IdentityDenotTransformer { thisPhase (j < 0 || p1(j) == separatorChar) } - assert(d.symbol.sourceFile != null && - ctx.owner.sourceFile != null && - isSimilar(d.symbol.sourceFile.path, ctx.owner.sourceFile.path), - s"private ${d.symbol.showLocated} in ${d.symbol.sourceFile} accessed from ${ctx.owner.showLocated} in ${ctx.owner.sourceFile}") + assert(d.symbol.source.exists && + ctx.owner.source.exists && + isSimilar(d.symbol.source.path, ctx.owner.source.path), + s"private ${d.symbol.showLocated} in ${d.symbol.source} accessed from ${ctx.owner.showLocated} in ${ctx.owner.source}") d.ensureNotPrivate.installAfter(thisPhase) } diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 8e207d31ef5f..995c78c95cca 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -7,7 +7,7 @@ import MegaPhase._ import SymUtils._ import ast.Trees._ import dotty.tools.dotc.reporting.diagnostic.messages.TypeMismatch -import dotty.tools.dotc.util.Positions.Position +import dotty.tools.dotc.util.Spans.Span /** Expand SAM closures that cannot be represented by the JVM as lambdas to anonymous classes. * These fall into five categories @@ -39,13 +39,13 @@ class ExpandSAMs extends MiniPhase { case tpe if defn.isImplicitFunctionType(tpe) => tree case tpe @ SAMType(_) if tpe.isRef(defn.PartialFunctionClass) => - val tpe1 = checkRefinements(tpe, fn.pos) + val tpe1 = checkRefinements(tpe, fn) toPartialFunction(tree, tpe1) case tpe @ SAMType(_) if isPlatformSam(tpe.classSymbol.asClass) => - checkRefinements(tpe, fn.pos) + checkRefinements(tpe, fn) tree case tpe => - val tpe1 = checkRefinements(tpe, fn.pos) + val tpe1 = checkRefinements(tpe, fn) val Seq(samDenot) = tpe1.abstractTermMembers.filter(!_.symbol.isSuperAccessor) cpy.Block(tree)(stats, AnonClass(tpe1 :: Nil, fn.symbol.asTerm :: Nil, samDenot.symbol.asTerm.name :: Nil)) @@ -109,13 +109,13 @@ class ExpandSAMs extends MiniPhase { val anonSym = anon.symbol val parents = List(defn.AbstractPartialFunctionType.appliedTo(tpe.argInfos), defn.SerializableType) - val pfSym = ctx.newNormalizedClassSymbol(anonSym.owner, tpnme.ANON_CLASS, Synthetic | Final, parents, coord = tree.pos) + val pfSym = ctx.newNormalizedClassSymbol(anonSym.owner, tpnme.ANON_CLASS, Synthetic | Final, parents, coord = tree.span) def overrideSym(sym: Symbol) = sym.copy( owner = pfSym, flags = Synthetic | Method | Final | Override, info = tpe.memberInfo(sym), - coord = tree.pos).asTerm.entered + coord = tree.span).asTerm.entered val isDefinedAtFn = overrideSym(defn.PartialFunction_isDefinedAt) val applyOrElseFn = overrideSym(defn.PartialFunction_applyOrElse) @@ -161,16 +161,16 @@ class ExpandSAMs extends MiniPhase { case _ => val found = tpe.baseType(defn.FunctionClass(1)) - ctx.error(TypeMismatch(found, tpe), tree.pos) + ctx.error(TypeMismatch(found, tpe), tree.sourcePos) tree } } - private def checkRefinements(tpe: Type, pos: Position)(implicit ctx: Context): Type = tpe.dealias match { + private def checkRefinements(tpe: Type, tree: Tree)(implicit ctx: Context): Type = tpe.dealias match { case RefinedType(parent, name, _) => if (name.isTermName && tpe.member(name).symbol.ownersIterator.isEmpty) // if member defined in the refinement - ctx.error("Lambda does not define " + name, pos) - checkRefinements(parent, pos) + ctx.error("Lambda does not define " + name, tree.sourcePos) + checkRefinements(parent, tree) case tpe => tpe } diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 6a7e041e690a..ba1aefa1b502 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -105,7 +105,7 @@ class ExplicitOuter extends MiniPhase with InfoTransformer { thisPhase => parent } else parent match { // ensure class parent is a constructor - case parent: TypeTree => New(parent.tpe, Nil).withPos(impl.pos) + case parent: TypeTree => New(parent.tpe, Nil).withSpan(impl.span) case _ => parent } } @@ -118,7 +118,7 @@ class ExplicitOuter extends MiniPhase with InfoTransformer { thisPhase => if (tree.tpt ne EmptyTree) { val cls = tree.tpt.asInstanceOf[TypeTree].tpe.classSymbol if (cls.exists && hasOuter(cls.asClass)) - ctx.error("Not a single abstract method type, requires an outer pointer", tree.pos) + ctx.error("Not a single abstract method type, requires an outer pointer", tree.sourcePos) } tree } @@ -359,7 +359,7 @@ object ExplicitOuter { } if (hasOuterParam(cls)) methPart(fun) match { - case Select(receiver, _) => outerArg(receiver).withPos(fun.pos) :: Nil + case Select(receiver, _) => outerArg(receiver).withSpan(fun.span) :: Nil } else Nil } else Nil diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitSelf.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitSelf.scala index 7ab625ce2a17..0eeac5d97aff 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitSelf.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitSelf.scala @@ -29,7 +29,7 @@ class ExplicitSelf extends MiniPhase { override def transformIdent(tree: Ident)(implicit ctx: Context): Tree = tree.tpe match { case tp: ThisType => ctx.debuglog(s"owner = ${ctx.owner}, context = ${ctx}") - This(tp.cls) withPos tree.pos + This(tp.cls).withSpan(tree.span) case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index 6717b3499f05..84d6449ee747 100644 --- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -107,7 +107,7 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase => if (meth.hasAnnotation(defn.NativeAnnot)) { meth.resetFlag(Deferred) polyDefDef(meth, - _ => _ => ref(defn.Sys_errorR).withPos(ddef.pos) + _ => _ => ref(defn.Sys_errorR).withSpan(ddef.span) .appliedTo(Literal(Constant(s"native method stub")))) } @@ -133,7 +133,7 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase => */ private def toTypeTree(tree: Tree)(implicit ctx: Context) = { val binders = collectBinders.apply(Nil, tree) - val result: Tree = TypeTree(tree.tpe).withPos(tree.pos) + val result: Tree = TypeTree(tree.tpe).withSpan(tree.span) (result /: binders)(Annotated(_, _)) } diff --git a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala index bbad627150d4..c6c0e1d8b92f 100644 --- a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala +++ b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala @@ -240,7 +240,7 @@ trait FullParameterization { ref(vparam.symbol).ensureConforms(paramType) })) }) - }).withPos(originalDef.rhs.pos) + }).withSpan(originalDef.rhs.span) } } diff --git a/compiler/src/dotty/tools/dotc/transform/GetClass.scala b/compiler/src/dotty/tools/dotc/transform/GetClass.scala index 77ba6d1b618d..ff83968b80f9 100644 --- a/compiler/src/dotty/tools/dotc/transform/GetClass.scala +++ b/compiler/src/dotty/tools/dotc/transform/GetClass.scala @@ -26,7 +26,7 @@ class GetClass extends MiniPhase { import ast.Trees._ tree match { case Apply(Select(qual, nme.getClass_), Nil) if qual.tpe.widen.isPrimitiveValueType => - clsOf(qual.tpe.widen).withPos(tree.pos) + clsOf(qual.tpe.widen).withSpan(tree.span) case _ => tree } } diff --git a/compiler/src/dotty/tools/dotc/transform/Getters.scala b/compiler/src/dotty/tools/dotc/transform/Getters.scala index 60658f9bc460..aba65da831a6 100644 --- a/compiler/src/dotty/tools/dotc/transform/Getters.scala +++ b/compiler/src/dotty/tools/dotc/transform/Getters.scala @@ -78,10 +78,10 @@ class Getters extends MiniPhase with SymTransformer { private val NoGetterNeeded = Method | Param | JavaDefined | JavaStatic override def transformValDef(tree: ValDef)(implicit ctx: Context): Tree = - if (tree.symbol is Method) DefDef(tree.symbol.asTerm, tree.rhs).withPos(tree.pos) else tree + if (tree.symbol is Method) DefDef(tree.symbol.asTerm, tree.rhs).withSpan(tree.span) else tree override def transformAssign(tree: Assign)(implicit ctx: Context): Tree = - if (tree.lhs.symbol is Method) tree.lhs.becomes(tree.rhs).withPos(tree.pos) else tree + if (tree.lhs.symbol is Method) tree.lhs.becomes(tree.rhs).withSpan(tree.span) else tree } object Getters { diff --git a/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala.disabled b/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala.disabled index 4f6f8d3db3e4..481d0e23cf8b 100644 --- a/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala.disabled +++ b/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala.disabled @@ -50,7 +50,7 @@ class IsInstanceOfEvaluator extends MiniPhase { if (!scrutineeSubSelector && inMatch) { ctx.error( s"this case is unreachable due to `${selector.show}` not being a subclass of `${scrutinee.show}`", - Position(pos.start - 5, pos.end - 5) + Span(pos.start - 5, pos.end - 5) ) rewrite(qualifier, to = false) } else if (!scrutineeSubSelector && !inMatch) { @@ -73,7 +73,7 @@ class IsInstanceOfEvaluator extends MiniPhase { if (inMatch) { ctx.error( s"will never match since `${selector.show}` is not a subclass of `${scrutinee.show}`", - Position(qualifier.pos.start - 5, qualifier.pos.end - 5) // WHY 5? + Span(qualifier.pos.start - 5, qualifier.pos.end - 5) // WHY 5? ) rewrite(qualifier, to = false) } else { diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index 1c90a14f5cf6..ff4bd1ae37ba 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -424,7 +424,7 @@ object LambdaLift { case proxies => val sym = tree.symbol val freeParamDefs = proxies.map(proxy => - thisPhase.transformFollowingDeep(ValDef(proxy.asTerm).withPos(tree.pos)).asInstanceOf[ValDef]) + thisPhase.transformFollowingDeep(ValDef(proxy.asTerm).withSpan(tree.span)).asInstanceOf[ValDef]) def proxyInit(field: Symbol, param: Symbol) = thisPhase.transformFollowingDeep(memberRef(field).becomes(ref(param))) @@ -523,9 +523,9 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisPhase => val lft = lifter if (prefix eq NoPrefix) if (sym.enclosure != lft.currentEnclosure && !sym.isStatic) - (if (sym is Method) lft.memberRef(sym) else lft.proxyRef(sym)).withPos(tree.pos) + (if (sym is Method) lft.memberRef(sym) else lft.proxyRef(sym)).withSpan(tree.span) else if (sym.owner.isClass) // sym was lifted out - ref(sym).withPos(tree.pos) + ref(sym).withSpan(tree.span) else tree else if (!prefixIsElidable(tpe)) ref(tpe) @@ -536,7 +536,7 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisPhase => } override def transformApply(tree: Apply)(implicit ctx: Context): Apply = - cpy.Apply(tree)(tree.fun, lifter.addFreeArgs(tree.symbol, tree.args)).withPos(tree.pos) + cpy.Apply(tree)(tree.fun, lifter.addFreeArgs(tree.symbol, tree.args)).withSpan(tree.span) override def transformClosure(tree: Closure)(implicit ctx: Context): Closure = cpy.Closure(tree)(env = lifter.addFreeArgs(tree.meth.symbol, tree.env)) @@ -553,7 +553,7 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisPhase => override def transformReturn(tree: Return)(implicit ctx: Context): Tree = tree.expr match { case Block(stats, value) => - Block(stats, Return(value, tree.from)).withPos(tree.pos) + Block(stats, Return(value, tree.from)).withSpan(tree.span) case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index 9cd22a639b7a..f5c5c726bb07 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -149,11 +149,11 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { // val x$lzy = new scala.runtime.LazyInt() val holderName = LazyLocalName.fresh(xname) val holderImpl = defn.LazyHolder()(ctx)(tpe.typeSymbol) - val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.pos) + val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.span) val holderTree = ValDef(holderSymbol, New(holderImpl.typeRef, Nil)) val holderRef = ref(holderSymbol) - val getValue = holderRef.select(lazyNme.value).ensureApplied.withPos(x.pos) + val getValue = holderRef.select(lazyNme.value).ensureApplied.withSpan(x.span) val initialized = holderRef.select(lazyNme.initialized).ensureApplied // def x$lzycompute(): Int = x$lzy.synchronized { @@ -161,7 +161,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { // else x$lzy.initialize() // } val initName = LazyLocalInitName.fresh(xname) - val initSymbol = ctx.newSymbol(x.symbol.owner, initName, initFlags, MethodType(Nil, tpe), coord = x.pos) + val initSymbol = ctx.newSymbol(x.symbol.owner, initName, initFlags, MethodType(Nil, tpe), coord = x.span) val rhs = x.rhs.changeOwnerAfter(x.symbol, initSymbol, this) val initialize = holderRef.select(lazyNme.initialize).appliedTo(rhs) val initBody = holderRef diff --git a/compiler/src/dotty/tools/dotc/transform/LiftTry.scala b/compiler/src/dotty/tools/dotc/transform/LiftTry.scala index 5faf20ce7d00..a85676602c4d 100644 --- a/compiler/src/dotty/tools/dotc/transform/LiftTry.scala +++ b/compiler/src/dotty/tools/dotc/transform/LiftTry.scala @@ -64,10 +64,10 @@ class LiftTry extends MiniPhase with IdentityDenotTransformer { thisPhase => override def transformTry(tree: Try)(implicit ctx: Context): Tree = if (needLift && tree.cases.nonEmpty) { - ctx.debuglog(i"lifting tree at ${tree.pos}, current owner = ${ctx.owner}") + ctx.debuglog(i"lifting tree at ${tree.span}, current owner = ${ctx.owner}") val fn = ctx.newSymbol( ctx.owner, LiftedTreeName.fresh(), Synthetic | Method, - MethodType(Nil, tree.tpe.widenIfUnstable), coord = tree.pos) + MethodType(Nil, tree.tpe.widenIfUnstable), coord = tree.span) tree.changeOwnerAfter(ctx.owner, fn, thisPhase) Block(DefDef(fn, tree) :: Nil, ref(fn).appliedToNone) } diff --git a/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala b/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala index d90aa421a52a..a6768fced4ec 100644 --- a/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala +++ b/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala @@ -74,7 +74,7 @@ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhas case Apply(sel @ Select(Super(_, _), _), args) if sel.symbol.owner.is(Scala2xTrait) && currentClass.mixins.contains(sel.symbol.owner) => val impl = implMethod(sel.symbol) - if (impl.exists) Apply(ref(impl), This(currentClass) :: args).withPos(app.pos) + if (impl.exists) Apply(ref(impl), This(currentClass) :: args).withSpan(app.span) else app // could have been an abstract method in a trait linked to from a super constructor case Apply(sel, args) if sel.symbol.maybeOwner.is(ImplClass) && sel.symbol.owner.traitOfImplClass.is(Scala_2_12_Trait) => diff --git a/compiler/src/dotty/tools/dotc/transform/MacroTransform.scala b/compiler/src/dotty/tools/dotc/transform/MacroTransform.scala index e8bb69a12509..042e400bc3d0 100644 --- a/compiler/src/dotty/tools/dotc/transform/MacroTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/MacroTransform.scala @@ -63,7 +63,7 @@ abstract class MacroTransform extends Phase { } catch { case ex: TypeError => - ctx.error(ex.toMessage, tree.pos) + ctx.error(ex.toMessage, tree.sourcePos) tree } diff --git a/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala b/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala index 2af1f915265a..58e88b54acef 100644 --- a/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala +++ b/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala @@ -170,7 +170,7 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase { } catch { case ex: TypeError => - ctx.error(ex.toMessage, tree.pos) + ctx.error(ex.toMessage, tree.sourcePos) tree } def goUnnamed(tree: Tree, start: Int) = @@ -205,7 +205,7 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase { } catch { case ex: TypeError => - ctx.error(ex.toMessage, tree.pos) + ctx.error(ex.toMessage, tree.sourcePos) tree } if (tree.isInstanceOf[NameTree]) goNamed(tree, start) else goUnnamed(tree, start) @@ -388,8 +388,12 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase { goOther(tree, start) } - if (tree.isInstanceOf[NameTree]) transformNamed(tree, start, ctx) - else transformUnnamed(tree, start, ctx) + if (tree.source != ctx.source && tree.source.exists) + transformTree(tree, start)(ctx.withSource(tree.source)) + else if (tree.isInstanceOf[NameTree]) + transformNamed(tree, start, ctx) + else + transformUnnamed(tree, start, ctx) } def transformSpecificTree[T <: Tree](tree: T, start: Int)(implicit ctx: Context): T = diff --git a/compiler/src/dotty/tools/dotc/transform/Memoize.scala b/compiler/src/dotty/tools/dotc/transform/Memoize.scala index aa9414f4ffcf..7e058c8b131a 100644 --- a/compiler/src/dotty/tools/dotc/transform/Memoize.scala +++ b/compiler/src/dotty/tools/dotc/transform/Memoize.scala @@ -82,7 +82,7 @@ class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase => name = sym.name.asTermName.fieldName, flags = Private | (if (sym is Stable) EmptyFlags else Mutable), info = fieldType, - coord = tree.pos + coord = tree.span ).withAnnotationsCarrying(sym, defn.FieldMetaAnnot) .enteredAfter(thisPhase) } diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index 424b1fbab5b7..bc925f6a9aad 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -172,7 +172,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => case _ => val Apply(sel @ Select(New(_), nme.CONSTRUCTOR), args) = tree val (callArgs, initArgs) = if (tree.symbol.owner.is(Trait)) (Nil, args) else (args, Nil) - (superRef(tree.symbol, tree.pos).appliedToArgs(callArgs), initArgs) + (superRef(tree.symbol, tree.span).appliedToArgs(callArgs), initArgs) } val superCallsAndArgs = ( @@ -211,7 +211,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => ctx.error( em"""parameterized $mixin is indirectly implemented, |needs to be implemented directly so that arguments can be passed""", - cls.pos) + cls.sourcePos) EmptyTree } @@ -250,13 +250,13 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => def setters(mixin: ClassSymbol): List[Tree] = for (setter <- mixin.info.decls.filter(setr => setr.isSetter && !was(setr, Deferred))) - yield transformFollowing(DefDef(implementation(setter.asTerm), unitLiteral.withPos(cls.pos))) + yield transformFollowing(DefDef(implementation(setter.asTerm), unitLiteral.withSpan(cls.span))) cpy.Template(impl)( constr = if (cls.is(Trait)) cpy.DefDef(impl.constr)(vparamss = Nil :: Nil) else impl.constr, - parents = impl.parents.map(p => TypeTree(p.tpe).withPos(p.pos)), + parents = impl.parents.map(p => TypeTree(p.tpe).withSpan(p.span)), body = if (cls is Trait) traitDefs(impl.body) else { diff --git a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala index 35a6aa1b30f5..a78ee88886da 100644 --- a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala +++ b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala @@ -3,7 +3,7 @@ package transform import core._ import Symbols._, Types._, Contexts._, DenotTransformers._, Flags._ -import util.Positions._ +import util.Spans._ import SymUtils._ import StdNames._, NameOps._ import Decorators._ @@ -28,13 +28,13 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont res } - def superRef(target: Symbol, pos: Position = cls.pos): Tree = { + def superRef(target: Symbol, span: Span = cls.span): Tree = { val sup = if (target.isConstructor && !target.owner.is(Trait)) Super(This(cls), tpnme.EMPTY, true) else Super(This(cls), target.owner.name.asTypeName, false, target.owner) //println(i"super ref $target on $sup") - ast.untpd.Select(sup.withPos(pos), target.name) + ast.untpd.Select(sup.withSpan(span), target.name) .withType(NamedType(sup.tpe, target)) //sup.select(target) } diff --git a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala index 23c0fb222b6c..a1ecfb8b2986 100644 --- a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala +++ b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala @@ -37,7 +37,7 @@ class NonLocalReturns extends MiniPhase { private def nonLocalReturnKey(meth: Symbol)(implicit ctx: Context) = nonLocalReturnKeys.getOrElseUpdate(meth, ctx.newSymbol( - meth, NonLocalReturnKeyName.fresh(), Synthetic, defn.ObjectType, coord = meth.pos)) + meth, NonLocalReturnKeyName.fresh(), Synthetic, defn.ObjectType, coord = meth.span)) /** Generate a non-local return throw with given return expression from given method. * I.e. for the method's non-local return key, generate: @@ -68,7 +68,7 @@ class NonLocalReturns extends MiniPhase { private def nonLocalReturnTry(body: Tree, key: TermSymbol, meth: Symbol)(implicit ctx: Context) = { val keyDef = ValDef(key, New(defn.ObjectType, Nil)) val nonLocalReturnControl = defn.NonLocalReturnControlType - val ex = ctx.newSymbol(meth, nme.ex, EmptyFlags, nonLocalReturnControl, coord = body.pos) + val ex = ctx.newSymbol(meth, nme.ex, EmptyFlags, nonLocalReturnControl, coord = body.span) val pat = BindTyped(ex, nonLocalReturnControl) val rhs = If( ref(ex).select(nme.key).appliedToNone.select(nme.eq).appliedTo(ref(key)), @@ -86,6 +86,6 @@ class NonLocalReturns extends MiniPhase { } override def transformReturn(tree: Return)(implicit ctx: Context): Tree = - if (isNonLocalReturn(tree)) nonLocalReturnThrow(tree.expr, tree.from.symbol).withPos(tree.pos) + if (isNonLocalReturn(tree)) nonLocalReturnThrow(tree.expr, tree.from.symbol).withSpan(tree.span) else tree } diff --git a/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala b/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala index 9f73b4e53ae0..052216bcfb5e 100644 --- a/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala +++ b/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala @@ -134,7 +134,7 @@ object OverridingPairs { case ex: TypeError => // See neg/i1750a for an example where a cyclic error can arise. // The root cause in this example is an illegal "override" of an inner trait - ctx.error(ex.toMessage, base.pos) + ctx.error(ex.toMessage, base.sourcePos) } } else { curEntry = curEntry.prev diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index 138fe95114af..d32a0e6cd1af 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -70,7 +70,7 @@ class ParamForwarding(thisPhase: DenotTransformer) { val superAcc = Super(This(currentClass), tpnme.EMPTY, inConstrCall = false).select(alias) typr.println(i"adding param forwarder $superAcc") - DefDef(sym, superAcc.ensureConforms(sym.info.widen)).withPos(stat.pos) + DefDef(sym, superAcc.ensureConforms(sym.info.widen)).withSpan(stat.span) } return forwarder(ctx.withPhase(thisPhase.next)) } diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index e470af9c43cb..65aadb86ccb9 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -7,7 +7,7 @@ import MegaPhase._ import collection.mutable import Symbols._, Contexts._, Types._, StdNames._, NameOps._ import ast.Trees._ -import util.Positions._ +import util.Spans._ import typer.Applications.{isProductMatch, isGetMatch, productSelectors} import SymUtils._ import Flags._, Constants._ @@ -87,7 +87,7 @@ object PatternMatcher { private def newVar(rhs: Tree, flags: FlagSet): TermSymbol = ctx.newSymbol(ctx.owner, PatMatStdBinderName.fresh(), Synthetic | Case | flags, - sanitize(rhs.tpe), coord = rhs.pos) + sanitize(rhs.tpe), coord = rhs.span) // TODO: Drop Case once we use everywhere else `isPatmatGenerated`. /** The plan `let x = rhs in body(x)` where `x` is a fresh variable */ @@ -131,7 +131,7 @@ object PatternMatcher { /** The different kinds of plans */ sealed abstract class Plan { val id: Int = nxId; nxId += 1 } - case class TestPlan(test: Test, var scrutinee: Tree, pos: Position, + case class TestPlan(test: Test, var scrutinee: Tree, span: Span, var onSuccess: Plan) extends Plan { override def equals(that: Any): Boolean = that match { case that: TestPlan => this.scrutinee === that.scrutinee && this.test == that.test @@ -147,8 +147,8 @@ object PatternMatcher { case class ResultPlan(var tree: Tree) extends Plan object TestPlan { - def apply(test: Test, sym: Symbol, pos: Position, ons: Plan): TestPlan = - TestPlan(test, ref(sym), pos, ons) + def apply(test: Test, sym: Symbol, span: Span, ons: Plan): TestPlan = + TestPlan(test, ref(sym), span, ons) } /** The different kinds of tests */ @@ -256,7 +256,7 @@ object PatternMatcher { def matchElemsPlan(seqSym: Symbol, args: List[Tree], exact: Boolean, onSuccess: Plan) = { val selectors = args.indices.toList.map(idx => ref(seqSym).select(defn.Seq_apply.matchingMember(seqSym.info)).appliedTo(Literal(Constant(idx)))) - TestPlan(LengthTest(args.length, exact), seqSym, seqSym.pos, + TestPlan(LengthTest(args.length, exact), seqSym, seqSym.span, matchArgsPlan(selectors, args, onSuccess)) } @@ -297,7 +297,7 @@ object PatternMatcher { if (isSyntheticScala2Unapply(unapp.symbol) && caseAccessors.length == args.length) matchArgsPlan(caseAccessors.map(ref(scrutinee).select(_)), args, onSuccess) else if (unapp.tpe.widenSingleton.isRef(defn.BooleanClass)) - TestPlan(GuardTest, unapp, unapp.pos, onSuccess) + TestPlan(GuardTest, unapp, unapp.span, onSuccess) else { letAbstract(unapp) { unappResult => val isUnapplySeq = unapp.symbol.name == nme.unapplySeq @@ -320,7 +320,7 @@ object PatternMatcher { matchArgsPlan(selectors, args, onSuccess) } } - TestPlan(NonEmptyTest, unappResult, unapp.pos, argsPlan) + TestPlan(NonEmptyTest, unappResult, unapp.span, argsPlan) } } } @@ -329,7 +329,7 @@ object PatternMatcher { // begin patternPlan swapBind(tree) match { case Typed(pat, tpt) => - TestPlan(TypeTest(tpt), scrutinee, tree.pos, + TestPlan(TypeTest(tpt), scrutinee, tree.span, letAbstract(ref(scrutinee).asInstance(tpt.tpe)) { casted => nonNull += casted patternPlan(casted, pat, onSuccess) @@ -340,7 +340,7 @@ object PatternMatcher { if (implicits.nonEmpty) unapp = unapp.appliedToArgs(implicits) val unappPlan = unapplyPlan(unapp, args) if (scrutinee.info.isNotNull || nonNull(scrutinee)) unappPlan - else TestPlan(NonNullTest, scrutinee, tree.pos, unappPlan) + else TestPlan(NonNullTest, scrutinee, tree.span, unappPlan) case Bind(name, body) => if (name == nme.WILDCARD) patternPlan(scrutinee, body, onSuccess) else { @@ -365,14 +365,14 @@ object PatternMatcher { case SeqLiteral(pats, _) => matchElemsPlan(scrutinee, pats, exact = true, onSuccess) case _ => - TestPlan(EqualTest(tree), scrutinee, tree.pos, onSuccess) + TestPlan(EqualTest(tree), scrutinee, tree.span, onSuccess) } } private def caseDefPlan(scrutinee: Symbol, cdef: CaseDef): Plan = { var onSuccess: Plan = ResultPlan(cdef.body) if (!cdef.guard.isEmpty) - onSuccess = TestPlan(GuardTest, cdef.guard, cdef.guard.pos, onSuccess) + onSuccess = TestPlan(GuardTest, cdef.guard, cdef.guard.span, onSuccess) patternPlan(scrutinee, cdef.pat, onSuccess) } @@ -823,7 +823,7 @@ object PatternMatcher { case plan2: TestPlan => emitWithMashedConditions(plan2 :: plans) case _ => - def emitCondWithPos(plan: TestPlan) = emitCondition(plan).withPos(plan.pos) + def emitCondWithPos(plan: TestPlan) = emitCondition(plan).withSpan(plan.span) val conditions = plans.foldRight[Tree](EmptyTree) { (otherPlan, acc) => if (acc.isEmpty) emitCondWithPos(otherPlan) @@ -926,7 +926,7 @@ object PatternMatcher { patmatch.println(i"original types: ${typesInCases(original.cases)}%, %") patmatch.println(i"switch types : ${typesInCases(resultCases)}%, %") patmatch.println(i"tree = $result") - ctx.warning(UnableToEmitSwitch(numTypes(original.cases) < MinSwitchCases), original.pos) + ctx.warning(UnableToEmitSwitch(numTypes(original.cases) < MinSwitchCases), original.sourcePos) } case _ => } diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index 0abee9001ba9..400df66aaa7d 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -61,7 +61,7 @@ class Pickler extends Phase { treePkl.compactify() pickler.addrOfTree = treePkl.buf.addrOfTree pickler.addrOfSym = treePkl.addrOfSym - if (tree.pos.exists) + if (tree.span.exists) new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil) if (!ctx.settings.YdropComments.value) @@ -78,7 +78,7 @@ class Pickler extends Phase { // println(i"rawBytes = \n$rawBytes%\n%") // DEBUG if (pickling ne noPrinter) { println(i"**** pickled info of $cls") - new TastyPrinter(pickler.assembleParts()).printContents() + println(new TastyPrinter(pickler.assembleParts()).printContents()) } } } @@ -116,7 +116,7 @@ class Pickler extends Phase { if (previous != unpickled) { output("before-pickling.txt", previous) output("after-pickling.txt", unpickled) - ctx.error(s"""pickling difference for $cls in ${cls.sourceFile}, for details: + ctx.error(s"""pickling difference for $cls in ${cls.source}, for details: | | diff before-pickling.txt after-pickling.txt""".stripMargin) } diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 6cb00fad258f..979ccfa70584 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -154,7 +154,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case tp: PolyType if args.exists(isNamedArg) => val (namedArgs, otherArgs) = args.partition(isNamedArg) val args1 = reorderArgs(tp.paramNames, namedArgs.asInstanceOf[List[NamedArg]], otherArgs) - TypeApply(tycon, args1).withPos(tree.pos).withType(tree.tpe) + TypeApply(tycon, args1).withSpan(tree.span).withType(tree.tpe) case _ => tree } @@ -193,13 +193,13 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case tree: Ident if !tree.isType => handleMeta(tree.symbol) tree.tpe match { - case tpe: ThisType => This(tpe.cls).withPos(tree.pos) + case tpe: ThisType => This(tpe.cls).withSpan(tree.span) case _ => tree } case tree @ Select(qual, name) => handleMeta(tree.symbol) if (name.isTypeName) { - Checking.checkRealizable(qual.tpe, qual.pos.focus) + Checking.checkRealizable(qual.tpe, qual.posd) super.transform(tree)(ctx.addMode(Mode.Type)) } else @@ -211,7 +211,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase tpd.cpy.Apply(tree)( tree.fun, tree.args.mapConserve(arg => - if (methType.isImplicitMethod && arg.pos.isSynthetic) ref(defn.Predef_undefined) + if (methType.isImplicitMethod && arg.span.isSynthetic) ref(defn.Predef_undefined) else dropInlines.transform(arg))) else tree @@ -219,7 +219,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case Select(nu: New, nme.CONSTRUCTOR) if isCheckable(nu) => // need to check instantiability here, because the type of the New itself // might be a type constructor. - Checking.checkInstantiable(tree.tpe, nu.pos) + Checking.checkInstantiable(tree.tpe, nu.posd) withNoCheckNews(nu :: Nil)(super.transform(app)) case _ => super.transform(app) @@ -239,7 +239,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase super.transform(tree1) } case Inlined(call, bindings, expansion) if !call.isEmpty => - val callTrace = Inliner.inlineCallTrace(call.symbol, call.pos) + val callTrace = Inliner.inlineCallTrace(call.symbol, call.sourcePos) cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(inlineContext(call))) case tree: Template => withNoCheckNews(tree.parents.flatMap(newPart)) { @@ -266,10 +266,10 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase } processMemberDef(super.transform(tree)) case tree: New if isCheckable(tree) => - Checking.checkInstantiable(tree.tpe, tree.pos) + Checking.checkInstantiable(tree.tpe, tree.posd) super.transform(tree) case tree: Closure if !tree.tpt.isEmpty => - Checking.checkRealizable(tree.tpt.tpe, tree.pos, "SAM type") + Checking.checkRealizable(tree.tpt.tpe, tree.posd, "SAM type") super.transform(tree) case tree @ Annotated(annotated, annot) => cpy.Annotated(tree)(transform(annotated), transformAnnot(annot)) @@ -277,7 +277,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase Checking.checkAppliedType(tree, boundsCheck = !ctx.mode.is(Mode.Pattern)) super.transform(tree) case SingletonTypeTree(ref) => - Checking.checkRealizable(ref.tpe, ref.pos.focus) + Checking.checkRealizable(ref.tpe, ref.posd) super.transform(tree) case tree: TypeTree => tree.withType( @@ -289,7 +289,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case tree: AndTypeTree => // Ideally, this should be done by Typer, but we run into cyclic references // when trying to typecheck self types which are intersections. - Checking.checkNonCyclicInherited(tree.tpe, tree.left.tpe :: tree.right.tpe :: Nil, EmptyScope, tree.pos) + Checking.checkNonCyclicInherited(tree.tpe, tree.left.tpe :: tree.right.tpe :: Nil, EmptyScope, tree.posd) super.transform(tree) case tree: LambdaTypeTree => VarianceChecker.checkLambda(tree) @@ -300,9 +300,9 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase def checkIdent(ident: untpd.Ident): Unit = { val name = ident.name.asTermName if (name != nme.WILDCARD && !exprTpe.member(name).exists && !exprTpe.member(name.toTypeName).exists) - ctx.error(NotAMember(exprTpe, name, "value"), ident.pos) + ctx.error(NotAMember(exprTpe, name, "value"), ident.sourcePos) if (seen(ident.name)) - ctx.error(ImportRenamedTwice(ident), ident.pos) + ctx.error(ImportRenamedTwice(ident), ident.sourcePos) seen += ident.name } selectors.foreach { diff --git a/compiler/src/dotty/tools/dotc/transform/ProtectedAccessors.scala b/compiler/src/dotty/tools/dotc/transform/ProtectedAccessors.scala index dadd92fb11a8..59e38f232d6e 100644 --- a/compiler/src/dotty/tools/dotc/transform/ProtectedAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/ProtectedAccessors.scala @@ -60,7 +60,7 @@ class ProtectedAccessors extends MiniPhase { val curCls = ctx.owner.enclosingClass transforms.println(i"${curCls.ownersIterator.toList}%, %") ctx.error(i"illegal access to protected ${reference.symbol.showLocated} from $curCls", - reference.pos) + reference.sourcePos) reference } } diff --git a/compiler/src/dotty/tools/dotc/transform/Splicer.scala b/compiler/src/dotty/tools/dotc/transform/Splicer.scala index 5bd039fb2629..74d8f2cf7a20 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicer.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicer.scala @@ -142,7 +142,7 @@ object Splicer { } protected def unexpectedTree(tree: Tree)(implicit env: Env): Object = - throw new StopInterpretation("Unexpected tree could not be interpreted: " + tree, tree.pos) + throw new StopInterpretation("Unexpected tree could not be interpreted: " + tree, tree.sourcePos) private def loadModule(sym: Symbol): Object = { if (sym.owner.is(Package)) { diff --git a/compiler/src/dotty/tools/dotc/transform/Staging.scala b/compiler/src/dotty/tools/dotc/transform/Staging.scala index 510df2ef3f65..72c32ae68fde 100644 --- a/compiler/src/dotty/tools/dotc/transform/Staging.scala +++ b/compiler/src/dotty/tools/dotc/transform/Staging.scala @@ -5,7 +5,8 @@ import core._ import Decorators._, Flags._, Types._, Contexts._, Symbols._, Constants._ import ast.Trees._ import ast.{TreeTypeMap, untpd} -import util.Positions._ +import util.Spans._ +import util.SourcePosition import tasty.TreePickler.Hole import SymUtils._ import NameKinds._ @@ -255,14 +256,14 @@ class Staging extends MacroTransformWithImplicits { * @return Some(msg) if unsuccessful where `msg` is a potentially empty error message * to be added to the "inconsistent phase" message. */ - def tryHeal(tp: Type, pos: Position)(implicit ctx: Context): Option[String] = tp match { + def tryHeal(tp: Type, pos: SourcePosition)(implicit ctx: Context): Option[String] = tp match { case tp: TypeRef => if (level == -1) { assert(ctx.inInlineMethod) None } else { val reqType = defn.QuotedTypeType.appliedTo(tp) - val tag = ctx.typer.inferImplicitArg(reqType, pos) + val tag = ctx.typer.inferImplicitArg(reqType, pos.span) tag.tpe match { case fail: SearchFailureType => Some(i""" @@ -281,7 +282,7 @@ class Staging extends MacroTransformWithImplicits { /** Check reference to `sym` for phase consistency, where `tp` is the underlying type * by which we refer to `sym`. */ - def check(sym: Symbol, tp: Type, pos: Position)(implicit ctx: Context): Unit = { + def check(sym: Symbol, tp: Type, pos: SourcePosition)(implicit ctx: Context): Unit = { val isThis = tp.isInstanceOf[ThisType] def symStr = if (!isThis) sym.show @@ -299,7 +300,7 @@ class Staging extends MacroTransformWithImplicits { } /** Check all named types and this-types in a given type for phase consistency. */ - def checkType(pos: Position)(implicit ctx: Context): TypeAccumulator[Unit] = new TypeAccumulator[Unit] { + def checkType(pos: SourcePosition)(implicit ctx: Context): TypeAccumulator[Unit] = new TypeAccumulator[Unit] { def apply(acc: Unit, tp: Type): Unit = reporting.trace(i"check type level $tp at $level") { tp match { case tp: TypeRef if tp.symbol.isSplice => @@ -312,11 +313,11 @@ class Staging extends MacroTransformWithImplicits { tp } case tp: NamedType => - check(tp.symbol, tp, pos) + check(tp.symbol, tp, tp.symbol.sourcePos) if (!tp.symbol.is(Param)) foldOver(acc, tp) case tp: ThisType => - check(tp.cls, tp, pos) + check(tp.cls, tp, tp.cls.sourcePos) foldOver(acc, tp) case _ => foldOver(acc, tp) @@ -340,15 +341,15 @@ class Staging extends MacroTransformWithImplicits { private def checkLevel(tree: Tree)(implicit ctx: Context): Tree = { tree match { case (_: Ident) | (_: This) => - check(tree.symbol, tree.tpe, tree.pos) + check(tree.symbol, tree.tpe, tree.sourcePos) case (_: UnApply) | (_: TypeTree) => - checkType(tree.pos).apply((), tree.tpe) + checkType(tree.sourcePos).apply((), tree.tpe) case Select(qual, OuterSelectName(_, levels)) => - checkType(tree.pos).apply((), tree.tpe.widen) + checkType(tree.sourcePos).apply((), tree.tpe.widen) case _: Bind => - checkType(tree.pos).apply((), tree.symbol.info) + checkType(tree.sourcePos).apply((), tree.symbol.info) case _: Template => - checkType(tree.pos).apply((), tree.symbol.owner.asClass.givenSelfType) + checkType(tree.sourcePos).apply((), tree.symbol.owner.asClass.givenSelfType) case _ => } tree @@ -383,8 +384,8 @@ class Staging extends MacroTransformWithImplicits { if (level == 0 && !ctx.inInlineMethod) { val body2 = if (body1.isType) body1 - else Inlined(Inliner.inlineCallTrace(ctx.owner, quote.pos), Nil, body1) - pickledQuote(body2, splices, body.tpe, isType).withPos(quote.pos) + else Inlined(Inliner.inlineCallTrace(ctx.owner, quote.sourcePos), Nil, body1) + pickledQuote(body2, splices, body.tpe, isType).withSpan(quote.span) } else { // In top-level splice in an inline def. Keep the tree as it is, it will be transformed at inline site. @@ -436,22 +437,22 @@ class Staging extends MacroTransformWithImplicits { else if (level == 1) { val (body1, quotes) = nested(isQuote = false).split(splice.qualifier) val tpe = outer.embedded.getHoleType(splice) - val hole = makeHole(body1, quotes, tpe).withPos(splice.pos) + val hole = makeHole(body1, quotes, tpe).withSpan(splice.span) // We do not place add the inline marker for trees that where lifted as they come from the same file as their // enclosing quote. Any intemediate splice will add it's own Inlined node and cancel it before splicig the lifted tree. - // Note that lifted trees are not necessarily expressions and that Inlined nodes are expected to be expressions. + // Note that lifted trees are not necessarily expressions and that Inlined nodes are expected to be expressions. // For example we can have a lifted tree containing the LHS of an assignment (see tests/run-with-compiler/quote-var.scala). if (splice.isType || outer.embedded.isLiftedSymbol(splice.qualifier.symbol)) hole - else Inlined(EmptyTree, Nil, hole) + else Inlined(EmptyTree, Nil, hole).withSpan(splice.span) } else if (enclosingInlineds.nonEmpty) { // level 0 in an inlined call val spliceCtx = ctx.outer // drop the last `inlineContext` - val pos: SourcePosition = Decorators.sourcePos(enclosingInlineds.head.pos)(spliceCtx) - val evaluatedSplice = Splicer.splice(splice.qualifier, pos, macroClassLoader)(spliceCtx).withPos(splice.pos) + val pos: SourcePosition = spliceCtx.source.atSpan(enclosingInlineds.head.span) + val evaluatedSplice = Splicer.splice(splice.qualifier, pos, macroClassLoader)(spliceCtx).withSpan(splice.span) if (ctx.reporter.hasErrors) splice else transform(evaluatedSplice) } else if (!ctx.owner.isInlineMethod) { // level 0 outside an inline method - ctx.error(i"splice outside quotes or inline method", splice.pos) + ctx.error(i"splice outside quotes or inline method", splice.sourcePos) splice } else if (Splicer.canBeSpliced(splice.qualifier)) { // level 0 inside an inline definition @@ -459,7 +460,9 @@ class Staging extends MacroTransformWithImplicits { splice } else { // level 0 inside an inline definition - ctx.error("Malformed macro call. The contents of the ~ must call a static method and arguments must be quoted or inline.".stripMargin, splice.pos) + ctx.error( + "Malformed macro call. The contents of the ~ must call a static method and arguments must be quoted or inline.".stripMargin, + splice.sourcePos) splice } } @@ -512,7 +515,8 @@ class Staging extends MacroTransformWithImplicits { captured.put(tree.symbol, capturedArg) capturedArg } - ref(captured.getOrElseUpdate(tree.symbol, newCapture).symbol) + val refSym = captured.getOrElseUpdate(tree.symbol, newCapture).symbol + ref(refSym).withSpan(tree.span) } } ) @@ -574,7 +578,7 @@ class Staging extends MacroTransformWithImplicits { quotation(quotedTree, tree) case tree: TypeTree if tree.tpe.typeSymbol.isSplice => val splicedType = tree.tpe.stripTypeVar.asInstanceOf[TypeRef].prefix.termSymbol - splice(ref(splicedType).select(tpnme.UNARY_~).withPos(tree.pos)) + splice(ref(splicedType).select(tpnme.UNARY_~).withSpan(tree.span)) case tree: Select if tree.symbol.isSplice => splice(tree) case tree: RefTree if tree.symbol.is(Inline) && tree.symbol.is(Param) => @@ -615,7 +619,7 @@ class Staging extends MacroTransformWithImplicits { | | * The contents of the splice must call a static method | * All arguments must be quoted or inline - """.stripMargin, tree.rhs.pos) + """.stripMargin, tree.rhs.sourcePos) EmptyTree } case _ => diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index d647127a68c3..6f7681141974 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -9,7 +9,7 @@ import Contexts._, Flags._, Symbols._, NameOps._, Trees._ import TypeUtils._, SymUtils._ import DenotTransformers.DenotTransformer import Symbols._ -import util.Positions._ +import util.Spans._ import Decorators._ import NameKinds.SuperAccessorName @@ -70,7 +70,7 @@ class SuperAccessors(thisPhase: DenotTransformer) { if (clazz is Trait) superName = superName.expandedName(clazz) val superInfo = sel.tpe.widenSingleton.ensureMethodic - val accPos = sel.pos.focus + val accRange = sel.span.focus val superAcc = clazz.info.decl(superName) .suchThat(_.signature == superInfo.signature).symbol .orElse { @@ -78,15 +78,17 @@ class SuperAccessors(thisPhase: DenotTransformer) { val maybeDeferred = if (clazz is Trait) Deferred else EmptyFlags val acc = ctx.newSymbol( clazz, superName, Artifact | Method | maybeDeferred, - superInfo, coord = accPos).enteredAfter(thisPhase) + superInfo, coord = accRange).enteredAfter(thisPhase) // Diagnostic for SI-7091 if (!accDefs.contains(clazz)) - ctx.error(s"Internal error: unable to store accessor definition in ${clazz}. clazz.hasPackageFlag=${clazz is Package}. Accessor required for ${sel} (${sel.show})", sel.pos) - else accDefs(clazz) += DefDef(acc, EmptyTree).withPos(accPos) + ctx.error( + s"Internal error: unable to store accessor definition in ${clazz}. clazz.hasPackageFlag=${clazz is Package}. Accessor required for ${sel} (${sel.show})", + sel.sourcePos) + else accDefs(clazz) += DefDef(acc, EmptyTree).withSpan(accRange) acc } - This(clazz).select(superAcc).withPos(sel.pos) + This(clazz).select(superAcc).withSpan(sel.span) } /** Check selection `super.f` for conforming to rules. If necessary, @@ -100,9 +102,9 @@ class SuperAccessors(thisPhase: DenotTransformer) { if (sym.isTerm && !sym.is(Method, butNot = Accessor) && !ctx.owner.is(ParamForwarder)) // ParamForwaders as installed ParamForwarding.scala do use super calls to vals - ctx.error(s"super may be not be used on ${sym.underlyingSymbol}", sel.pos) + ctx.error(s"super may be not be used on ${sym.underlyingSymbol}", sel.sourcePos) else if (isDisallowed(sym)) - ctx.error(s"super not allowed here: use this.${sel.name} instead", sel.pos) + ctx.error(s"super not allowed here: use this.${sel.name} instead", sel.sourcePos) else if (sym is Deferred) { val member = sym.overridingSymbol(clazz.asClass) if (!mix.name.isEmpty || @@ -110,7 +112,7 @@ class SuperAccessors(thisPhase: DenotTransformer) { !((member is AbsOverride) && member.isIncompleteIn(clazz))) ctx.error( i"${sym.showLocated} is accessed from super. It may not be abstract unless it is overridden by a member declared `abstract' and `override'", - sel.pos) + sel.sourcePos) else ctx.log(i"ok super $sel ${sym.showLocated} $member $clazz ${member.isIncompleteIn(clazz)}") } else if (mix.name.isEmpty && !(sym.owner is Trait)) @@ -120,8 +122,7 @@ class SuperAccessors(thisPhase: DenotTransformer) { if ((overriding is (Deferred, butNot = AbsOverride)) && !(overriding.owner is Trait)) ctx.error( s"${sym.showLocated} cannot be directly accessed from ${clazz} because ${overriding.owner} redeclares it as abstract", - sel.pos) - + sel.sourcePos) } if (name.isTermName && mix.name.isEmpty && ((clazz is Trait) || clazz != ctx.owner.enclosingClass || !validCurrentClass)) diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala index 0b9dde117732..04b68a932ac0 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala @@ -94,7 +94,7 @@ class SyntheticMethods(thisPhase: DenotTransformer) { case nme.productElement => vrefss => productElementBody(accessors.length, vrefss.head.head) } ctx.log(s"adding $synthetic to $clazz at ${ctx.phase}") - DefDef(synthetic, syntheticRHS(ctx.withOwner(synthetic))).withPos(ctx.owner.pos.focus) + DefDef(synthetic, syntheticRHS(ctx.withOwner(synthetic))).withSpan(ctx.owner.span.focus) } /** The class @@ -158,7 +158,7 @@ class SyntheticMethods(thisPhase: DenotTransformer) { * */ def equalsBody(that: Tree)(implicit ctx: Context): Tree = { - val thatAsClazz = ctx.newSymbol(ctx.owner, nme.x_0, Synthetic, clazzType, coord = ctx.owner.pos) // x$0 + val thatAsClazz = ctx.newSymbol(ctx.owner, nme.x_0, Synthetic, clazzType, coord = ctx.owner.span) // x$0 def wildcardAscription(tp: Type) = Typed(Underscore(tp), TypeTree(tp)) val pattern = Bind(thatAsClazz, wildcardAscription(AnnotatedType(clazzType, Annotation(defn.UncheckedAnnot)))) // x$0 @ (_: C @unchecked) val comparisons = accessors map { accessor => @@ -213,7 +213,7 @@ class SyntheticMethods(thisPhase: DenotTransformer) { def caseHashCodeBody(implicit ctx: Context): Tree = { val seed = clazz.fullName.toString.hashCode if (accessors.nonEmpty) { - val acc = ctx.newSymbol(ctx.owner, "acc".toTermName, Mutable | Synthetic, defn.IntType, coord = ctx.owner.pos) + val acc = ctx.newSymbol(ctx.owner, "acc".toTermName, Mutable | Synthetic, defn.IntType, coord = ctx.owner.span) val accDef = ValDef(acc, Literal(Constant(seed))) val mixes = for (accessor <- accessors) yield Assign(ref(acc), ref(defn.staticsMethod("mix")).appliedTo(ref(acc), hashImpl(accessor))) diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index bc3a251065cf..48761a2142e6 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -117,13 +117,13 @@ class TailRec extends MiniPhase { val method = tree.symbol val mandatory = method.hasAnnotation(defn.TailrecAnnot) def noTailTransform(failureReported: Boolean) = { - // FIXME: want to report this error on `tree.namePos`, but - // because of extension method getting a weird pos, it is + // FIXME: want to report this error on `tree.nameSpan`, but + // because of extension method getting a weird position, it is // better to report on method symbol so there's no overlap. // We don't report a new error if failures were reported // during the transformation. if (mandatory && !failureReported) - ctx.error(TailrecNotApplicable(method), method.pos) + ctx.error(TailrecNotApplicable(method), method.sourcePos) tree } @@ -282,10 +282,10 @@ class TailRec extends MiniPhase { def fail(reason: String) = { if (isMandatory) { failureReported = true - ctx.error(s"Cannot rewrite recursive call: $reason", tree.pos) + ctx.error(s"Cannot rewrite recursive call: $reason", tree.sourcePos) } else - tailrec.println("Cannot rewrite recursive call at: " + tree.pos + " because: " + reason) + tailrec.println("Cannot rewrite recursive call at: " + tree.span + " because: " + reason) continue } @@ -303,7 +303,7 @@ class TailRec extends MiniPhase { if (isRecursiveCall) { if (inTailPosition) { - tailrec.println("Rewriting tail recursive call: " + tree.pos) + tailrec.println("Rewriting tail recursive call: " + tree.span) rewrote = true val assignParamPairs = for { @@ -330,7 +330,7 @@ class TailRec extends MiniPhase { case _ :: _ => val (tempValDefs, assigns) = (for ((lhs, rhs) <- assignThisAndParamPairs) yield { val temp = ctx.newSymbol(method, TailTempName.fresh(lhs.name.toTermName), Synthetic, lhs.info) - (ValDef(temp, rhs), Assign(ref(lhs), ref(temp)).withPos(tree.pos)) + (ValDef(temp, rhs), Assign(ref(lhs), ref(temp)).withSpan(tree.span)) }).unzip tempValDefs ::: assigns case nil => @@ -342,7 +342,7 @@ class TailRec extends MiniPhase { * which can cause Ycheck errors. */ val tpt = TypeTree(method.info.resultType) - seq(assignments, Typed(Return(unitLiteral.withPos(tree.pos), continueLabel), tpt)) + seq(assignments, Typed(Return(unitLiteral.withSpan(tree.span), continueLabel), tpt)) } else fail("it is not in tail position") } diff --git a/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala b/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala index dc9317f0028a..c58c19c834a1 100644 --- a/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala +++ b/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala @@ -43,7 +43,8 @@ abstract class TransformByNameApply extends MiniPhase { thisPhase: DenotTransfor case formalExpr: ExprType => var argType = arg.tpe.widenIfUnstable if (defn.isBottomType(argType)) argType = formal.widenExpr - def wrap(arg: Tree) = ref(defn.cbnArg).appliedToType(argType).appliedTo(arg) + def wrap(arg: Tree) = + ref(defn.cbnArg).appliedToType(argType).appliedTo(arg).withSpan(arg.span) arg match { case Apply(Select(qual, nme.apply), Nil) if qual.tpe.derivesFrom(defn.FunctionClass(0)) && isPureExpr(qual) => diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 07b71670c5d4..0ec7aa5217e5 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -180,7 +180,7 @@ class TreeChecker extends Phase with SymTransformer { def assertDefined(tree: untpd.Tree)(implicit ctx: Context): Unit = if (tree.symbol.maybeOwner.isTerm) - assert(nowDefinedSyms contains tree.symbol, i"undefined symbol ${tree.symbol} at line " + tree.pos.line) + assert(nowDefinedSyms contains tree.symbol, i"undefined symbol ${tree.symbol} at line " + tree.sourcePos.line) /** assert Java classes are not used as objects */ def assertIdentNotJavaClass(tree: Tree)(implicit ctx: Context): Unit = tree match { diff --git a/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala b/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala index 827b2bd6c57e..b4cf235168e0 100644 --- a/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala +++ b/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala @@ -9,7 +9,7 @@ import core.NameKinds.ExceptionBinderName import dotty.tools.dotc.core.Flags import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.transform.MegaPhase.MiniPhase -import dotty.tools.dotc.util.Positions.Position +import dotty.tools.dotc.util.Spans.Span /** Compiles the cases that can not be handled by primitive catch cases as a common pattern match. * @@ -59,7 +59,7 @@ class TryCatchPatterns extends MiniPhase { override def transformTry(tree: Try)(implicit ctx: Context): Tree = { val (tryCases, patternMatchCases) = tree.cases.span(isCatchCase) - val fallbackCase = mkFallbackPatterMatchCase(patternMatchCases, tree.pos) + val fallbackCase = mkFallbackPatterMatchCase(patternMatchCases, tree.span) cpy.Try(tree)(cases = tryCases ++ fallbackCase) } @@ -81,17 +81,17 @@ class TryCatchPatterns extends MiniPhase { false } - private def mkFallbackPatterMatchCase(patternMatchCases: List[CaseDef], pos: Position)( + private def mkFallbackPatterMatchCase(patternMatchCases: List[CaseDef], span: Span)( implicit ctx: Context): Option[CaseDef] = { if (patternMatchCases.isEmpty) None else { val exName = ExceptionBinderName.fresh() val fallbackSelector = - ctx.newSymbol(ctx.owner, exName, Flags.Synthetic | Flags.Case, defn.ThrowableType, coord = pos) - val sel = Ident(fallbackSelector.termRef).withPos(pos) + ctx.newSymbol(ctx.owner, exName, Flags.Synthetic | Flags.Case, defn.ThrowableType, coord = span) + val sel = Ident(fallbackSelector.termRef).withSpan(span) val rethrow = CaseDef(EmptyTree, EmptyTree, Throw(ref(fallbackSelector))) Some(CaseDef( - Bind(fallbackSelector, Underscore(fallbackSelector.info).withPos(pos)), + Bind(fallbackSelector, Underscore(fallbackSelector.info).withSpan(span)), EmptyTree, transformFollowing(Match(sel, patternMatchCases ::: rethrow :: Nil))) ) diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index da67a64e60ad..3af74f4a7de0 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -10,7 +10,7 @@ import TypeErasure._ import ValueClasses._ import SymUtils._ import core.Flags._ -import util.Positions._ +import util.Spans._ import reporting.diagnostic.messages.TypeTestAlwaysSucceeds import reporting.trace import config.Printers.{ transforms => debug } @@ -53,7 +53,7 @@ object TypeTestsCasts { * 7. if `P` is a refinement type, FALSE * 8. otherwise, TRUE */ - def checkable(X: Type, P: Type, pos: Position)(implicit ctx: Context): Boolean = { + def checkable(X: Type, P: Type, span: Span)(implicit ctx: Context): Boolean = { def isAbstract(P: Type) = !P.dealias.typeSymbol.isClass def isPatternTypeSymbol(sym: Symbol) = !sym.isClass && sym.is(Case) @@ -103,7 +103,7 @@ object TypeTestsCasts { P1 <:< X // constraint P1 // use fromScala2x to avoid generating pattern bound symbols - maximizeType(P1, pos, fromScala2x = true) + maximizeType(P1, span, fromScala2x = true) val res = P1 <:< P debug.println("P1 : " + P1) @@ -147,7 +147,7 @@ object TypeTestsCasts { def isPrimitive(tp: Type) = tp.classSymbol.isPrimitiveValueClass def derivedTree(expr1: Tree, sym: Symbol, tp: Type) = - cpy.TypeApply(tree)(expr1.select(sym).withPos(expr.pos), List(TypeTree(tp))) + cpy.TypeApply(tree)(expr1.select(sym).withSpan(expr.span), List(TypeTree(tp))) def effectiveClass(tp: Type): Symbol = if (tp.isRef(defn.PairClass)) effectiveClass(erasure(tp)) @@ -165,8 +165,8 @@ object TypeTestsCasts { def unreachable(why: => String) = if (flagUnrelated) - if (inMatch) ctx.error(em"this case is unreachable since $why", expr.pos) - else ctx.warning(em"this will always yield false since $why", expr.pos) + if (inMatch) ctx.error(em"this case is unreachable since $why", expr.sourcePos) + else ctx.warning(em"this will always yield false since $why", expr.sourcePos) /** Are `foundCls` and `testCls` classes that allow checks * whether a test would be always false? @@ -186,7 +186,7 @@ object TypeTestsCasts { def checkSensical: Boolean = if (!isCheckable) true else if (foundCls.isPrimitiveValueClass && !testCls.isPrimitiveValueClass) { - ctx.error("cannot test if value types are references", tree.pos) + ctx.error("cannot test if value types are references", tree.sourcePos) false } else if (!foundCls.derivesFrom(testCls)) { @@ -206,7 +206,7 @@ object TypeTestsCasts { if (expr.tpe <:< testType) if (expr.tpe.isNotNull) { - ctx.warning(TypeTestAlwaysSucceeds(foundCls, testCls), tree.pos) + ctx.warning(TypeTestAlwaysSucceeds(foundCls, testCls), tree.sourcePos) constant(expr, Literal(Constant(true))) } else expr.testNotNull @@ -248,7 +248,7 @@ object TypeTestsCasts { */ def transformTypeTest(expr: Tree, testType: Type, flagUnrelated: Boolean): Tree = testType.dealias match { case _: SingletonType => - expr.isInstance(testType).withPos(tree.pos) + expr.isInstance(testType).withSpan(tree.span) case OrType(tp1, tp2) => evalOnce(expr) { e => transformTypeTest(e, tp1, flagUnrelated = false) @@ -273,8 +273,8 @@ object TypeTestsCasts { if (sym.isTypeTest) { val argType = tree.args.head.tpe - if (!checkable(expr.tpe, argType, tree.pos)) - ctx.warning(i"the type test for $argType cannot be checked at runtime", tree.pos) + if (!checkable(expr.tpe, argType, tree.span)) + ctx.warning(i"the type test for $argType cannot be checked at runtime", tree.sourcePos) transformTypeTest(expr, tree.args.head.tpe, flagUnrelated = true) } else if (sym eq defn.Any_asInstanceOf) diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 42c2580f78c4..57ab59897e73 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -924,7 +924,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { } if (uncovered.nonEmpty) - ctx.warning(PatternMatchExhaustivity(show(Or(uncovered))), sel.pos) + ctx.warning(PatternMatchExhaustivity(show(Or(uncovered))), sel.sourcePos) } private def redundancyCheckable(sel: Tree): Boolean = @@ -973,14 +973,14 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { if (covered == Empty) covered = curr if (isSubspace(covered, prevs)) { - ctx.warning(MatchCaseUnreachable(), pat.pos) + ctx.warning(MatchCaseUnreachable(), pat.sourcePos) } // if last case is `_` and only matches `null`, produce a warning if (i == cases.length - 1 && !isNull(pat) ) { simplify(minus(covered, prevs)) match { case Typ(`nullType`, _) => - ctx.warning(MatchCaseOnlyNullWarning(), pat.pos) + ctx.warning(MatchCaseOnlyNullWarning(), pat.sourcePos) case _ => } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index a0793360827c..8969a0088739 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -4,8 +4,9 @@ package typer import core._ import ast.{Trees, tpd, untpd} -import util.Positions._ +import util.Spans._ import util.Stats.track +import util.{SourcePosition, NoSourcePosition, SourceFile} import Trees.Untyped import Contexts._ import Flags._ @@ -29,6 +30,7 @@ import reporting.trace import Constants.{Constant, IntTag, LongTag} import dotty.tools.dotc.reporting.diagnostic.messages.{NotAnExtractor, UnapplyInvalidNumberOfArguments} import Denotations.SingleDenotation +import annotation.constructorOnly object Applications { import tpd._ @@ -36,7 +38,7 @@ object Applications { def extractorMember(tp: Type, name: Name)(implicit ctx: Context): SingleDenotation = tp.member(name).suchThat(_.info.isParameterless) - def extractorMemberType(tp: Type, name: Name, errorPos: Position = NoPosition)(implicit ctx: Context): Type = { + def extractorMemberType(tp: Type, name: Name, errorPos: SourcePosition)(implicit ctx: Context): Type = { val ref = extractorMember(tp, name) if (ref.isOverloaded) errorType(i"Overloaded reference to $ref is not allowed in extractor", errorPos) @@ -47,18 +49,18 @@ object Applications { * for a pattern with `numArgs` subpatterns? * This is the case of `tp` has members `_1` to `_N` where `N == numArgs`. */ - def isProductMatch(tp: Type, numArgs: Int)(implicit ctx: Context): Boolean = - numArgs > 0 && productArity(tp) == numArgs + def isProductMatch(tp: Type, numArgs: Int, errorPos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Boolean = + numArgs > 0 && productArity(tp, errorPos) == numArgs /** Does `tp` fit the "get match" conditions as an unapply result type? * This is the case of `tp` has a `get` member as well as a * parameterless `isEmpty` member of result type `Boolean`. */ - def isGetMatch(tp: Type, errorPos: Position = NoPosition)(implicit ctx: Context): Boolean = + def isGetMatch(tp: Type, errorPos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Boolean = extractorMemberType(tp, nme.isEmpty, errorPos).isRef(defn.BooleanClass) && extractorMemberType(tp, nme.get, errorPos).exists - def productSelectorTypes(tp: Type, errorPos: Position = NoPosition)(implicit ctx: Context): List[Type] = { + def productSelectorTypes(tp: Type, errorPos: SourcePosition)(implicit ctx: Context): List[Type] = { def tupleSelectors(n: Int, tp: Type): List[Type] = { val sel = extractorMemberType(tp, nme.selectorName(n), errorPos) // extractorMemberType will return NoType if this is the tail of tuple with an unknown tail @@ -74,8 +76,8 @@ object Applications { genTupleSelectors(0, tp) } - def productArity(tp: Type)(implicit ctx: Context): Int = - if (defn.isProductSubType(tp)) productSelectorTypes(tp).size else -1 + def productArity(tp: Type, errorPos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Int = + if (defn.isProductSubType(tp)) productSelectorTypes(tp, errorPos).size else -1 def productSelectors(tp: Type)(implicit ctx: Context): List[Symbol] = { val sels = for (n <- Iterator.from(0)) yield @@ -83,14 +85,14 @@ object Applications { sels.takeWhile(_.exists).toList } - def getUnapplySelectors(tp: Type, args: List[untpd.Tree], pos: Position = NoPosition)(implicit ctx: Context): List[Type] = + def getUnapplySelectors(tp: Type, args: List[untpd.Tree], pos: SourcePosition)(implicit ctx: Context): List[Type] = if (args.length > 1 && !(tp.derivesFrom(defn.SeqClass))) { val sels = productSelectorTypes(tp, pos) if (sels.length == args.length) sels else tp :: Nil } else tp :: Nil - def unapplyArgs(unapplyResult: Type, unapplyFn: Tree, args: List[untpd.Tree], pos: Position = NoPosition)(implicit ctx: Context): List[Type] = { + def unapplyArgs(unapplyResult: Type, unapplyFn: Tree, args: List[untpd.Tree], pos: SourcePosition)(implicit ctx: Context): List[Type] = { val unapplyName = unapplyFn.symbol.name def seqSelector = defn.RepeatedParamType.appliedTo(unapplyResult.elemType :: Nil) @@ -148,14 +150,14 @@ object Applications { } else { assert(unapplyName == nme.unapply) - if (isProductMatch(unapplyResult, args.length)) - productSelectorTypes(unapplyResult) + if (isProductMatch(unapplyResult, args.length, pos)) + productSelectorTypes(unapplyResult, pos) else if (isGetMatch(unapplyResult, pos)) getUnapplySelectors(getTp, args, pos) else if (unapplyResult.widenSingleton isRef defn.BooleanClass) Nil else if (defn.isProductSubType(unapplyResult)) - productSelectorTypes(unapplyResult) + productSelectorTypes(unapplyResult, pos) // this will cause a "wrong number of arguments in pattern" error later on, // which is better than the message in `fail`. else fail @@ -167,8 +169,8 @@ object Applications { /** A wrapper indicating that its argument is an application of an extension method. */ - class ExtMethodApply(val app: Tree) extends tpd.Tree { - override def pos = app.pos + class ExtMethodApply(val app: Tree)(implicit @constructorOnly src: SourceFile) extends tpd.Tree { + override def span = app.span def canEqual(that: Any): Boolean = app.canEqual(that) def productArity: Int = app.productArity @@ -180,7 +182,7 @@ object Applications { * A test case is i5606.scala */ object ExtMethodApply { - def apply(app: Tree) = new ExtMethodApply(app) + def apply(app: Tree)(implicit ctx: Context) = new ExtMethodApply(app) def unapply(tree: Tree)(implicit ctx: Context): Option[Tree] = tree match { case tree: ExtMethodApply => Some(tree.app) case Block(stats, ExtMethodApply(app)) => Some(tpd.cpy.Block(tree)(stats, app)) @@ -189,7 +191,6 @@ object Applications { } } - trait Applications extends Compatibility { self: Typer with Dynamic => import Applications._ @@ -239,7 +240,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => /** Signal failure with given message at position of the application itself */ protected def fail(msg: => Message): Unit - protected def appPos: Position + protected def appPos: SourcePosition /** The current function part, which might be affected by lifting. */ @@ -520,7 +521,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => if (getter.isEmpty) missingArg(n) else { val substParam = addTyped( - treeToArg(spliceMeth(getter withPos normalizedFun.pos, normalizedFun)), + treeToArg(spliceMeth(getter.withSpan(normalizedFun.span), normalizedFun)), formal) matchArgs(args1, formals1.mapconserve(substParam), n + 1) } @@ -588,7 +589,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => ok = false def fail(msg: => Message): Unit = ok = false - def appPos: Position = NoPosition + def appPos: SourcePosition = NoSourcePosition lazy val normalizedFun: Tree = ref(methRef) init() } @@ -647,15 +648,15 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def harmonizeArgs(args: List[TypedArg]): List[Tree] = harmonize(args) - override def appPos: Position = app.pos + override def appPos: SourcePosition = app.sourcePos def fail(msg: => Message, arg: Trees.Tree[T]): Unit = { - ctx.error(msg, arg.pos) + ctx.error(msg, arg.sourcePos) ok = false } def fail(msg: => Message): Unit = { - ctx.error(msg, app.pos) + ctx.error(msg, app.sourcePos) ok = false } @@ -869,7 +870,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => case Apply(fn @ Select(left, _), right :: Nil) if fn.hasType => val op = fn.symbol if (op == defn.Any_== || op == defn.Any_!=) - checkCanEqual(left.tpe.widen, right.tpe.widen, app.pos) + checkCanEqual(left.tpe.widen, right.tpe.widen, app.span) case _ => } app @@ -906,7 +907,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => if (typedArgs.length <= pt.paramInfos.length && !isNamed) if (typedFn.symbol == defn.Predef_classOf && typedArgs.nonEmpty) { val arg = typedArgs.head - checkClassType(arg.tpe, arg.pos, traitReq = false, stablePrefixReq = false) + checkClassType(arg.tpe, arg.posd, traitReq = false, stablePrefixReq = false) } case _ => } @@ -925,11 +926,11 @@ trait Applications extends Compatibility { self: Typer with Dynamic => */ def convertNewGenericArray(tree: Tree)(implicit ctx: Context): Tree = tree match { case Apply(TypeApply(tycon, targs@(targ :: Nil)), args) if tycon.symbol == defn.ArrayConstructor => - fullyDefinedType(tree.tpe, "array", tree.pos) + fullyDefinedType(tree.tpe, "array", tree.span) def newGenericArrayCall = ref(defn.DottyArraysModule) - .select(defn.newGenericArrayMethod).withPos(tree.pos) + .select(defn.newGenericArrayMethod).withSpan(tree.span) .appliedToTypeTrees(targs).appliedToArgs(args) if (TypeErasure.isGeneric(targ.tpe)) @@ -957,7 +958,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => ttree.tpe match { case alias: TypeRef if alias.info.isTypeAlias && !nestedCtx.reporter.hasErrors => companionRef(alias) match { - case companion: TermRef => return untpd.ref(companion) withPos tree.pos + case companion: TermRef => return untpd.ref(companion).withSpan(tree.span) case _ => } case _ => @@ -1053,10 +1054,10 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val ownType = if (selType <:< unapplyArgType) { unapp.println(i"case 1 $unapplyArgType ${ctx.typerState.constraint}") - fullyDefinedType(unapplyArgType, "pattern selector", tree.pos) + fullyDefinedType(unapplyArgType, "pattern selector", tree.span) selType } else if (isSubTypeOfParent(unapplyArgType, selType)(ctx.addMode(Mode.GADTflexible))) { - val patternBound = maximizeType(unapplyArgType, tree.pos, fromScala2x) + val patternBound = maximizeType(unapplyArgType, tree.span, fromScala2x) if (patternBound.nonEmpty) unapplyFn = addBinders(unapplyFn, patternBound) unapp.println(i"case 2 $unapplyArgType ${ctx.typerState.constraint}") unapplyArgType @@ -1065,7 +1066,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => unapp.println(TypeComparer.explained(implicit ctx => unapplyArgType <:< selType)) errorType( ex"Pattern type $unapplyArgType is neither a subtype nor a supertype of selector type $selType", - tree.pos) + tree.sourcePos) } val dummyArg = dummyTreeOfType(ownType) val unapplyApp = typedExpr(untpd.TypedSplice(Apply(unapplyFn, dummyArg :: Nil))) @@ -1076,7 +1077,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => case _ => Nil.assertingErrorsReported } - var argTypes = unapplyArgs(unapplyApp.tpe, unapplyFn, args, tree.pos) + var argTypes = unapplyArgs(unapplyApp.tpe, unapplyFn, args, tree.sourcePos) for (argType <- argTypes) assert(!argType.isInstanceOf[TypeBounds], unapplyApp.tpe.show) val bunchedArgs = if (argTypes.nonEmpty && argTypes.last.isRepeatedParam) @@ -1085,14 +1086,14 @@ trait Applications extends Compatibility { self: Typer with Dynamic => args.init :+ argSeq case _ => val (regularArgs, varArgs) = args.splitAt(argTypes.length - 1) - regularArgs :+ untpd.SeqLiteral(varArgs, untpd.TypeTree()).withPos(tree.pos) + regularArgs :+ untpd.SeqLiteral(varArgs, untpd.TypeTree()).withSpan(tree.span) } else if (argTypes.lengthCompare(1) == 0 && args.lengthCompare(1) > 0 && ctx.canAutoTuple) untpd.Tuple(args) :: Nil else args if (argTypes.length != bunchedArgs.length) { - ctx.error(UnapplyInvalidNumberOfArguments(qual, argTypes), tree.pos) + ctx.error(UnapplyInvalidNumberOfArguments(qual, argTypes), tree.sourcePos) argTypes = argTypes.take(args.length) ++ List.fill(argTypes.length - args.length)(WildcardType) } @@ -1233,7 +1234,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => // `isSubType` as a TypeVar might get constrained by a TypeRef it's // part of. val tp1Params = tp1.newLikeThis(tp1.paramNames, tp1.paramInfos, defn.AnyType) - fullyDefinedType(tp1Params, "type parameters of alternative", alt1.symbol.pos) + fullyDefinedType(tp1Params, "type parameters of alternative", alt1.symbol.span) val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags, tp1.instantiateParamInfos(_)) isAsSpecific(alt1, tp1.instantiate(tparams.map(_.typeRef)), alt2, tp2) @@ -1692,7 +1693,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => typed(untpd.Apply(core, untpd.TypedSplice(receiver) :: Nil), pt1, ctx.typerState.ownedVars)( ctx.addMode(Mode.FixedQualifier)) if (!app.symbol.is(Extension)) - ctx.error(em"not an extension method: $methodRef", receiver.pos) + ctx.error(em"not an extension method: $methodRef", receiver.sourcePos) app } } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 8293e0a99ee0..766ce1f7f5e0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -17,7 +17,7 @@ import Scopes._ import CheckRealizable._ import ErrorReporting.errorTree -import util.Positions._ +import util.SourcePosition import transform.SymUtils._ import Decorators._ import ErrorReporting.{err, errorType} @@ -41,13 +41,13 @@ object Checking { (args, boundss).zipped.foreach { (arg, bound) => if (!bound.isLambdaSub && !arg.tpe.hasSimpleKind) { // see MissingTypeParameterFor - ctx.error(ex"missing type parameter(s) for $arg", arg.pos) + ctx.error(ex"missing type parameter(s) for $arg", arg.sourcePos) } } for ((arg, which, bound) <- ctx.boundsViolations(args, boundss, instantiate)) ctx.error( DoesNotConformToBound(arg.tpe, which, bound)(err), - arg.pos.focus) + arg.sourcePos.focus) } /** Check that type arguments `args` conform to corresponding bounds in `tl` @@ -79,16 +79,16 @@ object Checking { HKTypeLambda.fromParams(tparams, bound).appliedTo(args) if (boundsCheck) checkBounds(orderedArgs, bounds, instantiate) - def checkWildcardApply(tp: Type, pos: Position): Unit = tp match { + def checkWildcardApply(tp: Type): Unit = tp match { case tp @ AppliedType(tycon, args) => if (tycon.isLambdaSub && args.exists(_.isInstanceOf[TypeBounds])) ctx.errorOrMigrationWarning( ex"unreducible application of higher-kinded type $tycon to wildcard arguments", - pos) + tree.sourcePos) case _ => } def checkValidIfApply(implicit ctx: Context): Unit = - checkWildcardApply(tycon.tpe.appliedTo(args.map(_.tpe)), tree.pos) + checkWildcardApply(tycon.tpe.appliedTo(args.map(_.tpe))) checkValidIfApply(ctx.addMode(Mode.AllowLambdaWildcardApply)) } @@ -118,28 +118,28 @@ object Checking { /** Check that `tp` refers to a nonAbstract class * and that the instance conforms to the self type of the created class. */ - def checkInstantiable(tp: Type, pos: Position)(implicit ctx: Context): Unit = + def checkInstantiable(tp: Type, posd: Positioned)(implicit ctx: Context): Unit = tp.underlyingClassRef(refinementOK = false) match { case tref: TypeRef => val cls = tref.symbol if (cls.is(AbstractOrTrait)) - ctx.error(CantInstantiateAbstractClassOrTrait(cls, isTrait = cls.is(Trait)), pos) + ctx.error(CantInstantiateAbstractClassOrTrait(cls, isTrait = cls.is(Trait)), posd.sourcePos) if (!cls.is(Module)) { // Create a synthetic singleton type instance, and check whether // it conforms to the self type of the class as seen from that instance. val stp = SkolemType(tp) val selfType = cls.asClass.givenSelfType.asSeenFrom(stp, cls) if (selfType.exists && !(stp <:< selfType)) - ctx.error(DoesNotConformToSelfTypeCantBeInstantiated(tp, selfType), pos) + ctx.error(DoesNotConformToSelfTypeCantBeInstantiated(tp, selfType), posd.sourcePos) } case _ => } /** Check that type `tp` is realizable. */ - def checkRealizable(tp: Type, pos: Position, what: String = "path")(implicit ctx: Context): Unit = { + def checkRealizable(tp: Type, posd: Positioned, what: String = "path")(implicit ctx: Context): Unit = { val rstatus = realizability(tp) if (rstatus ne Realizable) - ctx.errorOrMigrationWarning(em"$tp is not a legal $what\nsince it${rstatus.msg}", pos) + ctx.errorOrMigrationWarning(em"$tp is not a legal $what\nsince it${rstatus.msg}", posd.sourcePos) } /** A type map which checks that the only cycles in a type are F-bounds @@ -270,7 +270,7 @@ object Checking { catch { case ex: CyclicReference => if (reportErrors) { - errorType(i"illegal cyclic reference: ${checker.where} ${checker.lastChecked} of $sym refers back to the type itself", sym.pos) + errorType(i"illegal cyclic reference: ${checker.where} ${checker.lastChecked} of $sym refers back to the type itself", sym.sourcePos) } else info } @@ -288,7 +288,7 @@ object Checking { def checkRefinementNonCyclic(refinement: Tree, refineCls: ClassSymbol, seen: mutable.Set[Symbol]) (implicit ctx: Context): Unit = { def flag(what: String, tree: Tree) = - ctx.warning(i"$what reference in refinement is deprecated", tree.pos) + ctx.warning(i"$what reference in refinement is deprecated", tree.sourcePos) def forwardRef(tree: Tree) = flag("forward", tree) def selfRef(tree: Tree) = flag("self", tree) val checkTree = new TreeAccumulator[Unit] { @@ -332,7 +332,7 @@ object Checking { * unless a type with the same name aleadry appears in `decls`. * @return true iff no cycles were detected */ - def checkNonCyclicInherited(joint: Type, parents: List[Type], decls: Scope, pos: Position)(implicit ctx: Context): Unit = { + def checkNonCyclicInherited(joint: Type, parents: List[Type], decls: Scope, posd: Positioned)(implicit ctx: Context): Unit = { def qualifies(sym: Symbol) = sym.name.isTypeName && !sym.is(Private) val abstractTypeNames = for (parent <- parents; mbr <- parent.abstractTypeMembers if qualifies(mbr.symbol)) @@ -350,14 +350,14 @@ object Checking { } catch { case ex: RecursionOverflow => - ctx.error(em"cyclic reference involving type $name", pos) + ctx.error(em"cyclic reference involving type $name", posd.sourcePos) false } } /** Check that symbol's definition is well-formed. */ def checkWellFormed(sym: Symbol)(implicit ctx: Context): Unit = { - def fail(msg: Message) = ctx.error(msg, sym.pos) + def fail(msg: Message) = ctx.error(msg, sym.sourcePos) def checkWithDeferred(flag: FlagSet) = if (sym.is(flag)) @@ -442,7 +442,7 @@ object Checking { * * @return The `info` of `sym`, with problematic aliases expanded away. */ - def checkNoPrivateLeaks(sym: Symbol, pos: Position)(implicit ctx: Context): Type = { + def checkNoPrivateLeaks(sym: Symbol, pos: SourcePosition)(implicit ctx: Context): Type = { class NotPrivate extends TypeMap { var errors: List[() => String] = Nil @@ -511,25 +511,25 @@ object Checking { def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context): Unit = { def checkValueClassMember(stat: Tree) = stat match { case _: TypeDef if stat.symbol.isClass => - ctx.error(ValueClassesMayNotDefineInner(clazz, stat.symbol), stat.pos) + ctx.error(ValueClassesMayNotDefineInner(clazz, stat.symbol), stat.sourcePos) case _: ValDef if !stat.symbol.is(ParamAccessor) => - ctx.error(ValueClassesMayNotDefineNonParameterField(clazz, stat.symbol), stat.pos) + ctx.error(ValueClassesMayNotDefineNonParameterField(clazz, stat.symbol), stat.sourcePos) case _: DefDef if stat.symbol.isConstructor => - ctx.error(ValueClassesMayNotDefineASecondaryConstructor(clazz, stat.symbol), stat.pos) + ctx.error(ValueClassesMayNotDefineASecondaryConstructor(clazz, stat.symbol), stat.sourcePos) case _: MemberDef | _: Import | EmptyTree => // ok case _ => - ctx.error(ValueClassesMayNotContainInitalization(clazz), stat.pos) + ctx.error(ValueClassesMayNotContainInitalization(clazz), stat.sourcePos) } if (isDerivedValueClass(clazz)) { if (clazz.is(Trait)) - ctx.error(CannotExtendAnyVal(clazz), clazz.pos) + ctx.error(CannotExtendAnyVal(clazz), clazz.sourcePos) if (clazz.is(Abstract)) - ctx.error(ValueClassesMayNotBeAbstract(clazz), clazz.pos) + ctx.error(ValueClassesMayNotBeAbstract(clazz), clazz.sourcePos) if (!clazz.isStatic) - ctx.error(ValueClassesMayNotBeContainted(clazz), clazz.pos) + ctx.error(ValueClassesMayNotBeContainted(clazz), clazz.sourcePos) if (isCyclic(clazz.asClass)) - ctx.error(ValueClassesMayNotWrapItself(clazz), clazz.pos) + ctx.error(ValueClassesMayNotWrapItself(clazz), clazz.sourcePos) else { val clParamAccessors = clazz.asClass.paramAccessors.filter { param => param.isTerm && !param.is(Flags.Accessor) @@ -537,17 +537,17 @@ object Checking { clParamAccessors match { case param :: params => if (param.is(Mutable)) - ctx.error(ValueClassParameterMayNotBeAVar(clazz, param), param.pos) + ctx.error(ValueClassParameterMayNotBeAVar(clazz, param), param.sourcePos) if (param.info.isInstanceOf[ExprType]) - ctx.error(ValueClassParameterMayNotBeCallByName(clazz, param), param.pos) + ctx.error(ValueClassParameterMayNotBeCallByName(clazz, param), param.sourcePos) if (param.is(Erased)) - ctx.error("value class first parameter cannot be `erased`", param.pos) + ctx.error("value class first parameter cannot be `erased`", param.sourcePos) else { for (p <- params if !p.is(Erased)) - ctx.error("value class can only have one non `erased` parameter", p.pos) + ctx.error("value class can only have one non `erased` parameter", p.sourcePos) } case Nil => - ctx.error(ValueClassNeedsOneValParam(clazz), clazz.pos) + ctx.error(ValueClassNeedsOneValParam(clazz), clazz.sourcePos) } } stats.foreach(checkValueClassMember) @@ -562,8 +562,8 @@ trait Checking { def checkNonCyclic(sym: Symbol, info: TypeBounds, reportErrors: Boolean)(implicit ctx: Context): Type = Checking.checkNonCyclic(sym, info, reportErrors) - def checkNonCyclicInherited(joint: Type, parents: List[Type], decls: Scope, pos: Position)(implicit ctx: Context): Unit = - Checking.checkNonCyclicInherited(joint, parents, decls, pos) + def checkNonCyclicInherited(joint: Type, parents: List[Type], decls: Scope, posd: Positioned)(implicit ctx: Context): Unit = + Checking.checkNonCyclicInherited(joint, parents, decls, posd) /** Check that Java statics and packages can only be used in selections. */ @@ -572,17 +572,17 @@ trait Checking { val sym = tree.tpe.termSymbol // The check is avoided inside Java compilation units because it always fails // on the singleton type Module.type. - if ((sym is Package) || ((sym is JavaModule) && !ctx.compilationUnit.isJava)) ctx.error(JavaSymbolIsNotAValue(sym), tree.pos) + if ((sym is Package) || ((sym is JavaModule) && !ctx.compilationUnit.isJava)) ctx.error(JavaSymbolIsNotAValue(sym), tree.sourcePos) } tree } /** Check that type `tp` is stable. */ - def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = - if (!tp.isStable) ctx.error(ex"$tp is not stable", pos) + def checkStable(tp: Type, posd: Positioned)(implicit ctx: Context): Unit = + if (!tp.isStable) ctx.error(ex"$tp is not stable", posd.sourcePos) /** Check that all type members of `tp` have realizable bounds */ - def checkRealizableBounds(cls: Symbol, pos: Position)(implicit ctx: Context): Unit = { + def checkRealizableBounds(cls: Symbol, pos: SourcePosition)(implicit ctx: Context): Unit = { val rstatus = boundsRealizability(cls.thisType) if (rstatus ne Realizable) ctx.error(ex"$cls cannot be instantiated since it${rstatus.msg}", pos) @@ -594,14 +594,14 @@ trait Checking { * check that class prefix is stable. * @return `tp` itself if it is a class or trait ref, ObjectType if not. */ - def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = + def checkClassType(tp: Type, posd: Positioned, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp.underlyingClassRef(refinementOK = false) match { case tref: TypeRef => - if (traitReq && !(tref.symbol is Trait)) ctx.error(TraitIsExpected(tref.symbol), pos) - if (stablePrefixReq && ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, pos) + if (traitReq && !(tref.symbol is Trait)) ctx.error(TraitIsExpected(tref.symbol), posd.sourcePos) + if (stablePrefixReq && ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, posd) tp case _ => - ctx.error(ex"$tp is not a class type", pos) + ctx.error(ex"$tp is not a class type", posd.sourcePos) defn.ObjectType } @@ -614,7 +614,7 @@ trait Checking { defn.LanguageModuleClass, nme.implicitConversions, i"Definition of implicit conversion $sym", ctx.owner.topLevelClass, - sym.pos) + sym.sourcePos) } sym.info.stripPoly match { @@ -634,7 +634,7 @@ trait Checking { * - it is defined in Predef * - it is the scala.reflect.Selectable.reflectiveSelectable conversion */ - def checkImplicitConversionUseOK(sym: Symbol, pos: Position)(implicit ctx: Context): Unit = { + def checkImplicitConversionUseOK(sym: Symbol, posd: Positioned)(implicit ctx: Context): Unit = { val conversionOK = !sym.exists || sym.is(Synthetic) || @@ -643,7 +643,7 @@ trait Checking { sym.name == nme.reflectiveSelectable && sym.maybeOwner.maybeOwner.maybeOwner == defn.ScalaPackageClass if (!conversionOK) checkFeature(defn.LanguageModuleClass, nme.implicitConversions, - i"Use of implicit conversion ${sym.showLocated}", NoSymbol, pos) + i"Use of implicit conversion ${sym.showLocated}", NoSymbol, posd.sourcePos) } /** Issue a feature warning if feature is not enabled */ @@ -651,7 +651,7 @@ trait Checking { name: TermName, description: => String, featureUseSite: Symbol, - pos: Position)(implicit ctx: Context): Unit = + pos: SourcePosition)(implicit ctx: Context): Unit = if (!ctx.featureEnabled(base, name)) ctx.featureWarning(name.toString, description, isScala2Feature = base.isContainedIn(defn.LanguageModuleClass), @@ -661,7 +661,7 @@ trait Checking { * are feasible, i.e. that their lower bound conforms to their upper bound. If a type * argument is infeasible, issue and error and continue with upper bound. */ - def checkFeasibleParent(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = { + def checkFeasibleParent(tp: Type, pos: SourcePosition, where: => String = "")(implicit ctx: Context): Type = { def checkGoodBounds(tp: Type) = tp match { case tp @ TypeBounds(lo, hi) if !(lo <:< hi) => ctx.error(ex"no type exists between low bound $lo and high bound $hi$where", pos) @@ -711,7 +711,7 @@ trait Checking { (tree.symbol.isStatic && isCaseObject(tree.symbol) || isCaseClassApply(tree.symbol)) || isCaseClassNew(tree.symbol) - if (!allow) ctx.error(em"$what must be a known value", tree.pos) + if (!allow) ctx.error(em"$what must be a known value", tree.sourcePos) else { def checkArgs(tree: Tree): Unit = tree match { case Apply(fn, args) => @@ -741,12 +741,12 @@ trait Checking { if (decl.matches(other)) { def doubleDefError(decl: Symbol, other: Symbol): Unit = if (!decl.info.isErroneous && !other.info.isErroneous) - ctx.error(DoubleDeclaration(decl, other), decl.pos) + ctx.error(DoubleDeclaration(decl, other), decl.sourcePos) if (decl is Synthetic) doubleDefError(other, decl) else doubleDefError(decl, other) } if ((decl is HasDefaultParams) && (other is HasDefaultParams)) { - ctx.error(em"two or more overloaded variants of $decl have default arguments", decl.pos) + ctx.error(em"two or more overloaded variants of $decl have default arguments", decl.sourcePos) decl resetFlag HasDefaultParams } } @@ -765,10 +765,10 @@ trait Checking { if (!ctx.isAfterTyper) { val called = call.tpe.classSymbol if (caller is Trait) - ctx.error(i"$caller may not call constructor of $called", call.pos) + ctx.error(i"$caller may not call constructor of $called", call.sourcePos) else if (called.is(Trait) && !caller.mixins.contains(called)) ctx.error(i"""$called is already implemented by super${caller.superClass}, - |its constructor cannot be called again""", call.pos) + |its constructor cannot be called again""", call.sourcePos) } /** Check that `tpt` does not define a higher-kinded type */ @@ -800,7 +800,7 @@ trait Checking { * * The standard library relies on this idiom. */ - def checkTraitInheritance(parent: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit = + def checkTraitInheritance(parent: Symbol, cls: ClassSymbol, pos: SourcePosition)(implicit ctx: Context): Unit = parent match { case parent: ClassSymbol if parent is Trait => val psuper = parent.superClass @@ -815,7 +815,7 @@ trait Checking { /** Check that case classes are not inherited by case classes. */ - def checkCaseInheritance(parent: Symbol, caseCls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit = + def checkCaseInheritance(parent: Symbol, caseCls: ClassSymbol, pos: SourcePosition)(implicit ctx: Context): Unit = parent match { case parent: ClassSymbol => if (parent is Case) @@ -833,7 +833,7 @@ trait Checking { val check = new TreeTraverser { def traverse(tree: Tree)(implicit ctx: Context) = tree match { case id: Ident if vparams.exists(_.symbol == id.symbol) => - ctx.error("illegal forward reference to method parameter", id.pos) + ctx.error("illegal forward reference to method parameter", id.sourcePos) case _ => traverseChildren(tree) } @@ -849,7 +849,7 @@ trait Checking { * of the self type, yet is no longer visible once the `this` has been replaced * by some other prefix. See neg/i3083.scala */ - def checkMembersOK(tp: Type, pos: Position)(implicit ctx: Context): Type = { + def checkMembersOK(tp: Type, pos: SourcePosition)(implicit ctx: Context): Type = { var ok = true val check: Type => Unit = { case ref: NamedType => @@ -873,10 +873,10 @@ trait Checking { val checker = new TreeTraverser { def traverse(t: Tree)(implicit ctx: Context) = { def check(owner: Symbol, checkedSym: Symbol) = - if (t.pos.isSourceDerived && owner == badOwner) + if (t.span.isSourceDerived && owner == badOwner) t match { case t: RefTree if allowed(t.name, checkedSym) => - case _ => ctx.error(i"illegal reference to $checkedSym from $where", t.pos) + case _ => ctx.error(i"illegal reference to $checkedSym from $where", t.sourcePos) } val sym = t.symbol t match { @@ -890,14 +890,14 @@ trait Checking { } /** Check that we are in an inline context (inside an inline method or in inline code) */ - def checkInInlineContext(what: String, pos: Position)(implicit ctx: Context): Unit = + def checkInInlineContext(what: String, posd: Positioned)(implicit ctx: Context): Unit = if (!ctx.inInlineMethod && !ctx.isInlineContext) { val inInlineUnapply = ctx.owner.ownersIterator.exists(owner => owner.name == nme.unapply && owner.is(Inline) && owner.is(Method)) val msg = if (inInlineUnapply) "cannot be used in an inline unapply" else "can only be used in an inline method" - ctx.error(em"$what $msg", pos) + ctx.error(em"$what $msg", posd.sourcePos) } /** Check that all case classes that extend `scala.Enum` are `enum` cases */ @@ -908,7 +908,7 @@ trait Checking { cls.owner.isTerm && (cls.owner.flagsUNSAFE.is(Case) || cls.owner.name == nme.DOLLAR_NEW) if (!cdef.mods.isEnumCase && !isEnumAnonCls) - ctx.error(CaseClassCannotExtendEnum(cls, parent), cdef.pos) + ctx.error(CaseClassCannotExtendEnum(cls, parent), cdef.sourcePos) } /** Check that all references coming from enum cases in an enum companion object @@ -994,23 +994,23 @@ trait ReChecking extends Checking { trait NoChecking extends ReChecking { import tpd._ override def checkNonCyclic(sym: Symbol, info: TypeBounds, reportErrors: Boolean)(implicit ctx: Context): Type = info - override def checkNonCyclicInherited(joint: Type, parents: List[Type], decls: Scope, pos: Position)(implicit ctx: Context): Unit = () + override def checkNonCyclicInherited(joint: Type, parents: List[Type], decls: Scope, posd: Positioned)(implicit ctx: Context): Unit = () override def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = tree - override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = () - override def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp + override def checkStable(tp: Type, posd: Positioned)(implicit ctx: Context): Unit = () + override def checkClassType(tp: Type, posd: Positioned, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp override def checkImplicitConversionDefOK(sym: Symbol)(implicit ctx: Context): Unit = () - override def checkImplicitConversionUseOK(sym: Symbol, pos: Position)(implicit ctx: Context): Unit = () - override def checkFeasibleParent(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp + override def checkImplicitConversionUseOK(sym: Symbol, posd: Positioned)(implicit ctx: Context): Unit = () + override def checkFeasibleParent(tp: Type, pos: SourcePosition, where: => String = "")(implicit ctx: Context): Type = tp override def checkInlineConformant(tree: Tree, isFinal: Boolean, what: => String)(implicit ctx: Context): Unit = () override def checkNoDoubleDeclaration(cls: Symbol)(implicit ctx: Context): Unit = () override def checkParentCall(call: Tree, caller: ClassSymbol)(implicit ctx: Context): Unit = () override def checkSimpleKinded(tpt: Tree)(implicit ctx: Context): Tree = tpt override def checkNotSingleton(tpt: Tree, where: String)(implicit ctx: Context): Tree = tpt override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context): Unit = () - override def checkTraitInheritance(parentSym: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit = () - override def checkCaseInheritance(parentSym: Symbol, caseCls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit = () + override def checkTraitInheritance(parentSym: Symbol, cls: ClassSymbol, pos: SourcePosition)(implicit ctx: Context): Unit = () + override def checkCaseInheritance(parentSym: Symbol, caseCls: ClassSymbol, pos: SourcePosition)(implicit ctx: Context): Unit = () override def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = () - override def checkMembersOK(tp: Type, pos: Position)(implicit ctx: Context): Type = tp - override def checkInInlineContext(what: String, pos: Position)(implicit ctx: Context): Unit = () - override def checkFeature(base: ClassSymbol, name: TermName, description: => String, featureUseSite: Symbol, pos: Position)(implicit ctx: Context): Unit = () + override def checkMembersOK(tp: Type, pos: SourcePosition)(implicit ctx: Context): Type = tp + override def checkInInlineContext(what: String, posd: Positioned)(implicit ctx: Context): Unit = () + override def checkFeature(base: ClassSymbol, name: TermName, description: => String, featureUseSite: Symbol, pos: SourcePosition)(implicit ctx: Context): Unit = () } diff --git a/compiler/src/dotty/tools/dotc/typer/Docstrings.scala b/compiler/src/dotty/tools/dotc/typer/Docstrings.scala index 65e68a1df4e4..ef61df2f8141 100644 --- a/compiler/src/dotty/tools/dotc/typer/Docstrings.scala +++ b/compiler/src/dotty/tools/dotc/typer/Docstrings.scala @@ -38,7 +38,7 @@ object Docstrings { case List(df: tpd.DefDef) => usecase.typed(df) case _ => - ctx.error("`@usecase` was not a valid definition", usecase.codePos) + ctx.error("`@usecase` was not a valid definition", ctx.source.atSpan(usecase.codePos)) usecase } } diff --git a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala index ac452780ccc4..75ba92e4e032 100644 --- a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala +++ b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala @@ -11,7 +11,7 @@ import dotty.tools.dotc.core.Names.{Name, TermName} import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.core.Types._ import dotty.tools.dotc.core.Decorators._ -import util.Positions._ +import util.Spans._ import core.Symbols._ import core.Definitions import ErrorReporting._ @@ -49,7 +49,7 @@ trait Dynamic { self: Typer with Applications => * foo.bar[T0, ...](x = bazX, y = bazY, baz, ...) ~~> foo.applyDynamicNamed[T0, ...]("bar")(("x", bazX), ("y", bazY), ("", baz), ...) */ def typedDynamicApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { - def typedDynamicApply(qual: untpd.Tree, name: Name, selPos: Position, targs: List[untpd.Tree]): Tree = { + def typedDynamicApply(qual: untpd.Tree, name: Name, selSpan: Span, targs: List[untpd.Tree]): Tree = { def isNamedArg(arg: untpd.Tree): Boolean = arg match { case NamedArg(_, _) => true; case _ => false } val args = tree.args val dynName = if (args.exists(isNamedArg)) nme.applyDynamicNamed else nme.applyDynamic @@ -62,19 +62,19 @@ trait Dynamic { self: Typer with Applications => case arg => namedArgTuple("", arg) } val args1 = if (dynName == nme.applyDynamic) args else namedArgs - typedApply(untpd.Apply(coreDynamic(qual, dynName, name, selPos, targs), args1), pt) + typedApply(untpd.Apply(coreDynamic(qual, dynName, name, selSpan, targs), args1), pt) } } tree.fun match { case sel @ Select(qual, name) if !isDynamicMethod(name) => - typedDynamicApply(qual, name, sel.pos, Nil) + typedDynamicApply(qual, name, sel.span, Nil) case TypeApply(sel @ Select(qual, name), targs) if !isDynamicMethod(name) => - typedDynamicApply(qual, name, sel.pos, targs) + typedDynamicApply(qual, name, sel.span, targs) case TypeApply(fun, targs) => - typedDynamicApply(fun, nme.apply, fun.pos, targs) + typedDynamicApply(fun, nme.apply, fun.span, targs) case fun => - typedDynamicApply(fun, nme.apply, fun.pos, Nil) + typedDynamicApply(fun, nme.apply, fun.span, Nil) } } @@ -86,26 +86,26 @@ trait Dynamic { self: Typer with Applications => * through an existing transformation of in typedAssign [foo.bar(baz) = quux ~~> foo.bar.update(baz, quux)]. */ def typedDynamicSelect(tree: untpd.Select, targs: List[Tree], pt: Type)(implicit ctx: Context): Tree = - typedApply(coreDynamic(tree.qualifier, nme.selectDynamic, tree.name, tree.pos, targs), pt) + typedApply(coreDynamic(tree.qualifier, nme.selectDynamic, tree.name, tree.span, targs), pt) /** Translate selection that does not typecheck according to the normal rules into a updateDynamic. * foo.bar = baz ~~> foo.updateDynamic(bar)(baz) */ def typedDynamicAssign(tree: untpd.Assign, pt: Type)(implicit ctx: Context): Tree = { - def typedDynamicAssign(qual: untpd.Tree, name: Name, selPos: Position, targs: List[untpd.Tree]): Tree = - typedApply(untpd.Apply(coreDynamic(qual, nme.updateDynamic, name, selPos, targs), tree.rhs), pt) + def typedDynamicAssign(qual: untpd.Tree, name: Name, selSpan: Span, targs: List[untpd.Tree]): Tree = + typedApply(untpd.Apply(coreDynamic(qual, nme.updateDynamic, name, selSpan, targs), tree.rhs), pt) tree.lhs match { case sel @ Select(qual, name) if !isDynamicMethod(name) => - typedDynamicAssign(qual, name, sel.pos, Nil) + typedDynamicAssign(qual, name, sel.span, Nil) case TypeApply(sel @ Select(qual, name), targs) if !isDynamicMethod(name) => - typedDynamicAssign(qual, name, sel.pos, targs) + typedDynamicAssign(qual, name, sel.span, targs) case _ => errorTree(tree, ReassignmentToVal(tree.lhs.symbol.name)) } } - private def coreDynamic(qual: untpd.Tree, dynName: Name, name: Name, selPos: Position, targs: List[untpd.Tree])(implicit ctx: Context): untpd.Apply = { - val select = untpd.Select(qual, dynName).withPos(selPos) + private def coreDynamic(qual: untpd.Tree, dynName: Name, name: Name, selSpan: Span, targs: List[untpd.Tree])(implicit ctx: Context): untpd.Apply = { + val select = untpd.Select(qual, dynName).withSpan(selSpan) val selectWithTypes = if (targs.isEmpty) select else untpd.TypeApply(select, targs) @@ -144,7 +144,7 @@ trait Dynamic { self: Typer with Applications => // ($qual: Selectable).$selectorName("$name", ..$ctags) val base = untpd.Apply( - untpd.TypedSplice(selectable.select(selectorName)).withPos(fun.pos), + untpd.TypedSplice(selectable.select(selectorName)).withSpan(fun.span), (Literal(Constant(name.toString)) :: ctags).map(untpd.TypedSplice(_))) val scall = @@ -175,7 +175,7 @@ trait Dynamic { self: Typer with Applications => fail(name, i"has a method type with inter-parameter dependencies") else { val ctags = tpe.paramInfoss.flatten.map(pt => - implicitArgTree(defn.ClassTagType.appliedTo(pt.widenDealias :: Nil), fun.pos.endPos)) + implicitArgTree(defn.ClassTagType.appliedTo(pt.widenDealias :: Nil), fun.span.endPos)) structuralCall(nme.applyDynamic, ctags).asInstance(tpe.finalResultType) } diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index e9f9d6d5ea50..a582aac88060 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -6,7 +6,8 @@ import ast._ import core._ import Types._, ProtoTypes._, Contexts._, Decorators._, Denotations._, Symbols._ import Implicits._, Flags._ -import util.Positions._ +import util.Spans._ +import util.SourcePosition import java.util.regex.Matcher.quoteReplacement import reporting.diagnostic.Message import reporting.diagnostic.messages._ @@ -15,18 +16,18 @@ object ErrorReporting { import tpd._ - def errorTree(tree: untpd.Tree, msg: => Message, pos: Position)(implicit ctx: Context): tpd.Tree = - tree withType errorType(msg, pos) + def errorTree(tree: untpd.Tree, msg: => Message, pos: SourcePosition)(implicit ctx: Context): tpd.Tree = + tree.withType(errorType(msg, pos)) def errorTree(tree: untpd.Tree, msg: => Message)(implicit ctx: Context): tpd.Tree = - errorTree(tree, msg, tree.pos) + errorTree(tree, msg, tree.sourcePos) - def errorType(msg: => Message, pos: Position)(implicit ctx: Context): ErrorType = { + def errorType(msg: => Message, pos: SourcePosition)(implicit ctx: Context): ErrorType = { ctx.error(msg, pos) ErrorType(msg) } - def wrongNumberOfTypeArgs(fntpe: Type, expectedArgs: List[ParamInfo], actual: List[untpd.Tree], pos: Position)(implicit ctx: Context): ErrorType = + def wrongNumberOfTypeArgs(fntpe: Type, expectedArgs: List[ParamInfo], actual: List[untpd.Tree], pos: SourcePosition)(implicit ctx: Context): ErrorType = errorType(WrongNumberOfTypeArgs(fntpe, expectedArgs, actual)(ctx), pos) class Errors(implicit ctx: Context) { @@ -79,8 +80,10 @@ object ErrorReporting { def takesNoParamsStr(tree: Tree, kind: String): String = if (tree.tpe.widen.exists) i"${exprStr(tree)} does not take ${kind}parameters" - else + else { + new FatalError("").printStackTrace() i"undefined: $tree # ${tree.uniqueId}: ${tree.tpe.toString} at ${ctx.phase}" + } def patternConstrStr(tree: Tree): String = ??? diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index b6d16782a0bd..9ea893283d2b 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -11,7 +11,7 @@ import Symbols._ import Names._ import StdNames._ import NameKinds.UniqueName -import util.Positions._ +import util.Spans._ import collection.mutable import Trees._ @@ -46,9 +46,9 @@ abstract class Lifter { // don't instantiate here, as the type params could be further constrained, see tests/pos/pickleinf.scala var liftedType = expr.tpe.widen if (liftedFlags.is(Method)) liftedType = ExprType(liftedType) - val lifted = ctx.newSymbol(ctx.owner, name, liftedFlags | Synthetic, liftedType, coord = positionCoord(expr.pos)) - defs += liftedDef(lifted, expr).withPos(expr.pos) - ref(lifted.termRef).withPos(expr.pos.focus) + val lifted = ctx.newSymbol(ctx.owner, name, liftedFlags | Synthetic, liftedType, coord = spanCoord(expr.span)) + defs += liftedDef(lifted, expr).withSpan(expr.span) + ref(lifted.termRef).withSpan(expr.span.focus) } /** Lift out common part of lhs tree taking part in an operator assignment such as @@ -208,8 +208,8 @@ object EtaExpansion extends LiftImpure { var paramFlag = Synthetic | Param if (mt.isImplicitMethod) paramFlag |= Implicit val params = (mt.paramNames, paramTypes).zipped.map((name, tpe) => - ValDef(name, tpe, EmptyTree).withFlags(paramFlag).withPos(tree.pos.startPos)) - var ids: List[Tree] = mt.paramNames map (name => Ident(name).withPos(tree.pos.startPos)) + ValDef(name, tpe, EmptyTree).withFlags(paramFlag).withSpan(tree.span.startPos)) + var ids: List[Tree] = mt.paramNames map (name => Ident(name).withSpan(tree.span.startPos)) if (mt.paramInfos.nonEmpty && mt.paramInfos.last.isRepeatedParam) ids = ids.init :+ repeated(ids.last) var body: Tree = Apply(lifted, ids) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index aef040c5df78..44dcfdd15f3e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -4,7 +4,7 @@ package typer import core._ import ast.{Trees, TreeTypeMap, untpd, tpd} -import util.Positions._ +import util.Spans._ import util.Stats.{track, record, monitored} import printing.{Showable, Printer} import printing.Texts._ @@ -28,7 +28,7 @@ import reporting.diagnostic.Message import Inferencing.fullyDefinedType import Trees._ import Hashable._ -import util.Property +import util.{Property, SourceFile, NoSource} import config.Config import config.Printers.{implicits, implicitsDetailed} import collection.mutable @@ -41,13 +41,6 @@ import scala.annotation.internal.sharable object Implicits { import tpd._ - /** A flag indicating that this an application of an extension method - * with the given name - */ - case class ExtMethodResult(app: Tree) extends tpd.Tree { - override def pos = app.pos - } - /** An implicit definition `implicitRef` that is visible under a different name, `alias`. * Gets generated if an implicit ref is imported via a renaming import. */ @@ -355,7 +348,7 @@ object Implicits { } object SearchFailure { - def apply(tpe: SearchFailureType): SearchFailure = { + def apply(tpe: SearchFailureType)(implicit src: SourceFile): SearchFailure = { val id = if (tpe.isInstanceOf[AmbiguousImplicits]) "/* ambiguous */" else "/* missing */" @@ -394,7 +387,7 @@ object Implicits { @sharable object NoMatchingImplicits extends NoMatchingImplicits(NoType, EmptyTree) @sharable val NoMatchingImplicitsFailure: SearchFailure = - SearchFailure(NoMatchingImplicits) + SearchFailure(NoMatchingImplicits)(NoSource) /** An ambiguous implicits failure */ class AmbiguousImplicits(val alt1: SearchSuccess, val alt2: SearchSuccess, val expectedType: Type, val argument: Tree) extends SearchFailureType { @@ -604,7 +597,7 @@ trait Implicits { self: Typer => SelectionProto(name, memberProto, compat, privateOK = false) case tp => tp } - try inferImplicit(adjust(to), from, from.pos) + try inferImplicit(adjust(to), from, from.span) catch { case ex: AssertionError => implicits.println(s"view $from ==> $to") @@ -618,27 +611,26 @@ trait Implicits { self: Typer => /** Find an implicit argument for parameter `formal`. * Return a failure as a SearchFailureType in the type of the returned tree. */ - def inferImplicitArg(formal: Type, pos: Position)(implicit ctx: Context): Tree = { + def inferImplicitArg(formal: Type, span: Span)(implicit ctx: Context): Tree = { /** If `formal` is of the form ClassTag[T], where `T` is a class type, * synthesize a class tag for `T`. */ def synthesizedClassTag(formal: Type): Tree = formal.argInfos match { case arg :: Nil => - fullyDefinedType(arg, "ClassTag argument", pos) match { + fullyDefinedType(arg, "ClassTag argument", span) match { case defn.ArrayOf(elemTp) => - val etag = inferImplicitArg(defn.ClassTagType.appliedTo(elemTp), pos) + val etag = inferImplicitArg(defn.ClassTagType.appliedTo(elemTp), span) if (etag.tpe.isError) EmptyTree else etag.select(nme.wrap) case tp if hasStableErasure(tp) && !defn.isBottomClass(tp.typeSymbol) => val sym = tp.typeSymbol - if (sym == defn.UnitClass || sym == defn.AnyClass || sym == defn.AnyValClass) - ref(defn.ClassTagModule).select(sym.name.toTermName).withPos(pos) - else - ref(defn.ClassTagModule) - .select(nme.apply) - .appliedToType(tp) - .appliedTo(clsOf(erasure(tp))) - .withPos(pos) + val classTag = ref(defn.ClassTagModule) + val tag = + if (sym == defn.UnitClass || sym == defn.AnyClass || sym == defn.AnyValClass) + classTag.select(sym.name.toTermName) + else + classTag.select(nme.apply).appliedToType(tp).appliedTo(clsOf(erasure(tp))) + tag.withSpan(span) case tp => EmptyTree } @@ -652,7 +644,7 @@ trait Implicits { self: Typer => var ok = true def apply(t: Type) = t match { case t @ TypeRef(NoPrefix, _) => - inferImplicit(defn.QuotedTypeType.appliedTo(t), EmptyTree, pos) match { + inferImplicit(defn.QuotedTypeType.appliedTo(t), EmptyTree, span) match { case SearchSuccess(tag, _, _) if tag.tpe.isStable => tag.tpe.select(defn.QuotedType_~) case _ => @@ -684,7 +676,7 @@ trait Implicits { self: Typer => case args @ (arg1 :: arg2 :: Nil) if !ctx.featureEnabled(defn.LanguageModuleClass, nme.strictEquality) && ctx.test(implicit ctx => validEqAnyArgs(arg1, arg2)) => - ref(defn.Eq_eqAny).appliedToTypes(args).withPos(pos) + ref(defn.Eq_eqAny).appliedToTypes(args).withSpan(span) case _ => EmptyTree } @@ -694,11 +686,11 @@ trait Implicits { self: Typer => * An EmptyTree is returned if materialization fails. */ def synthesizedValueOf(formal: Type)(implicit ctx: Context): Tree = { - def success(t: Tree) = New(defn.ValueOfClass.typeRef.appliedTo(t.tpe), t :: Nil).withPos(pos) + def success(t: Tree) = New(defn.ValueOfClass.typeRef.appliedTo(t.tpe), t :: Nil).withSpan(span) formal.argTypes match { case arg :: Nil => - fullyDefinedType(arg.dealias, "ValueOf argument", pos) match { + fullyDefinedType(arg.dealias, "ValueOf argument", span) match { case ConstantType(c: Constant) => success(Literal(c)) case TypeRef(_, sym) if sym == defn.UnitClass => @@ -714,14 +706,14 @@ trait Implicits { self: Typer => } def hasEq(tp: Type): Boolean = - inferImplicit(defn.EqType.appliedTo(tp, tp), EmptyTree, pos).isSuccess + inferImplicit(defn.EqType.appliedTo(tp, tp), EmptyTree, span).isSuccess def validEqAnyArgs(tp1: Type, tp2: Type)(implicit ctx: Context) = { - List(tp1, tp2).foreach(fullyDefinedType(_, "eqAny argument", pos)) + List(tp1, tp2).foreach(fullyDefinedType(_, "eqAny argument", span)) assumedCanEqual(tp1, tp2) || !hasEq(tp1) && !hasEq(tp2) } - inferImplicit(formal, EmptyTree, pos)(ctx) match { + inferImplicit(formal, EmptyTree, span)(ctx) match { case SearchSuccess(arg, _, _) => arg case fail @ SearchFailure(failed) => def trySpecialCase(cls: ClassSymbol, handler: Type => Tree, ifNot: => Tree) = { @@ -743,9 +735,10 @@ trait Implicits { self: Typer => } /** Search an implicit argument and report error if not found */ - def implicitArgTree(formal: Type, pos: Position)(implicit ctx: Context): Tree = { - val arg = inferImplicitArg(formal, pos) - if (arg.tpe.isInstanceOf[SearchFailureType]) ctx.error(missingArgMsg(arg, formal, ""), pos) + def implicitArgTree(formal: Type, span: Span)(implicit ctx: Context): Tree = { + val arg = inferImplicitArg(formal, span) + if (arg.tpe.isInstanceOf[SearchFailureType]) + ctx.error(missingArgMsg(arg, formal, ""), ctx.source.atSpan(span)) arg } @@ -794,7 +787,7 @@ trait Implicits { self: Typer => case _ => Nil } def resolveTypes(targs: List[Tree])(implicit ctx: Context) = - targs.map(a => fullyDefinedType(a.tpe, "type argument", a.pos)) + targs.map(a => fullyDefinedType(a.tpe, "type argument", a.span)) // We can extract type arguments from: // - a function call: @@ -874,9 +867,9 @@ trait Implicits { self: Typer => } /** Check that equality tests between types `ltp` and `rtp` make sense */ - def checkCanEqual(ltp: Type, rtp: Type, pos: Position)(implicit ctx: Context): Unit = + def checkCanEqual(ltp: Type, rtp: Type, span: Span)(implicit ctx: Context): Unit = if (!ctx.isAfterTyper && !assumedCanEqual(ltp, rtp)) { - val res = implicitArgTree(defn.EqType.appliedTo(ltp, rtp), pos) + val res = implicitArgTree(defn.EqType.appliedTo(ltp, rtp), span) implicits.println(i"Eq witness found for $ltp / $rtp: $res: ${res.tpe}") } @@ -884,16 +877,16 @@ trait Implicits { self: Typer => * @param pt The expected type of the parameter or conversion. * @param argument If an implicit conversion is searched, the argument to which * it should be applied, EmptyTree otherwise. - * @param pos The position where errors should be reported. + * @param span The position where errors should be reported. */ - def inferImplicit(pt: Type, argument: Tree, pos: Position)(implicit ctx: Context): SearchResult = track("inferImplicit") { + def inferImplicit(pt: Type, argument: Tree, span: Span)(implicit ctx: Context): SearchResult = track("inferImplicit") { assert(ctx.phase.allowsImplicitSearch, if (argument.isEmpty) i"missing implicit parameter of type $pt after typer" else i"type error: ${argument.tpe} does not conform to $pt${err.whyNoMatchStr(argument.tpe, pt)}") trace(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) { val result0 = try { - new ImplicitSearch(pt, argument, pos).bestImplicit(contextual = true) + new ImplicitSearch(pt, argument, span).bestImplicit(contextual = true) } catch { case ce: CyclicReference => ce.inImplicitSearch = true @@ -910,13 +903,13 @@ trait Implicits { self: Typer => result case result: SearchFailure if result.isAmbiguous => val deepPt = pt.deepenProto - if (deepPt ne pt) inferImplicit(deepPt, argument, pos) + if (deepPt ne pt) inferImplicit(deepPt, argument, span) else if (ctx.scala2Mode && !ctx.mode.is(Mode.OldOverloadingResolution)) { - inferImplicit(pt, argument, pos)(ctx.addMode(Mode.OldOverloadingResolution)) match { + inferImplicit(pt, argument, span)(ctx.addMode(Mode.OldOverloadingResolution)) match { case altResult: SearchSuccess => ctx.migrationWarning( s"According to new implicit resolution rules, this will be ambiguous:\n${result.reason.explanation}", - pos) + ctx.source.atSpan(span)) altResult case _ => result @@ -927,12 +920,12 @@ trait Implicits { self: Typer => result0 } // If we are at the outermost implicit search then emit the implicit dictionary, if any. - ctx.searchHistory.emitDictionary(pos, result) + ctx.searchHistory.emitDictionary(span, result) } } /** An implicit search; parameters as in `inferImplicit` */ - class ImplicitSearch(protected val pt: Type, protected val argument: Tree, pos: Position)(implicit ctx: Context) { + class ImplicitSearch(protected val pt: Type, protected val argument: Tree, span: Span)(implicit ctx: Context) { assert(argument.isEmpty || argument.tpe.isValueType || argument.tpe.isInstanceOf[ExprType], em"found: $argument: ${argument.tpe}, expected: $pt") @@ -961,7 +954,7 @@ trait Implicits { self: Typer => /** Try to typecheck an implicit reference */ def typedImplicit(cand: Candidate, contextual: Boolean)(implicit ctx: Context): SearchResult = track("typedImplicit") { trace(i"typed implicit ${cand.ref}, pt = $pt, implicitsEnabled == ${ctx.mode is ImplicitsEnabled}", implicits, show = true) { val ref = cand.ref - var generated: Tree = tpd.ref(ref).withPos(pos.startPos) + var generated: Tree = tpd.ref(ref).withSpan(span.startPos) val locked = ctx.typerState.ownedVars val generated1 = if (argument.isEmpty) @@ -986,7 +979,7 @@ trait Implicits { self: Typer => else tryConversion } lazy val shadowing = - typedUnadapted(untpd.Ident(cand.implicitRef.implicitName) withPos pos.toSynthetic)( + typedUnadapted(untpd.Ident(cand.implicitRef.implicitName).withSpan(span.toSynthetic))( nestedContext().addMode(Mode.ImplicitShadowing).setExploreTyperState()) /** Is candidate reference the same as the `shadowing` reference? (i.e. @@ -1159,7 +1152,8 @@ trait Implicits { self: Typer => |According to the new implicit resolution rules this is no longer possible; |the search will fail with a global ambiguity error instead. | - |Consider using the scala.implicits.Not class to implement similar functionality.""", pos) + |Consider using the scala.implicits.Not class to implement similar functionality.""", + ctx.source.atSpan(span)) /** A relation that imfluences the order in which implicits are tried. * We prefer (in order of importance) @@ -1216,7 +1210,7 @@ trait Implicits { self: Typer => // other candidates need to be considered. ctx.searchHistory.recursiveRef(pt) match { case ref: TermRef => - SearchSuccess(tpd.ref(ref).withPos(pos.startPos), ref, 0)(ctx.typerState, ctx.gadt) + SearchSuccess(tpd.ref(ref).withSpan(span.startPos), ref, 0)(ctx.typerState, ctx.gadt) case _ => val eligible = if (contextual) ctx.implicits.eligible(wildProto) @@ -1386,7 +1380,7 @@ abstract class SearchHistory { outer => def defineBynameImplicit(tpe: Type, result: SearchSuccess)(implicit ctx: Context): SearchResult = root.defineBynameImplicit(tpe, result) // This is NOOP unless at the root of this search history. - def emitDictionary(pos: Position, result: SearchResult)(implicit ctx: Context): SearchResult = result + def emitDictionary(span: Span, result: SearchResult)(implicit ctx: Context): SearchResult = result override def toString: String = s"SearchHistory(open = $open, byname = $byname)" } @@ -1456,7 +1450,7 @@ final class SearchRoot extends SearchHistory { implicitDictionary.get(tpe) match { case Some((ref, _)) => implicitDictionary.put(tpe, (ref, result.tree)) - SearchSuccess(tpd.ref(ref).withPos(result.tree.pos), result.ref, result.level)(result.tstate, result.gstate) + SearchSuccess(tpd.ref(ref).withSpan(result.tree.span), result.ref, result.level)(result.tstate, result.gstate) case None => result } } @@ -1464,12 +1458,12 @@ final class SearchRoot extends SearchHistory { /** * Emit the implicit dictionary at the completion of an implicit search. * - * @param pos The position at which the search is elaborated. + * @param span The position at which the search is elaborated. * @param result The result of the search prior to substitution of recursive references. * @result The elaborated result, comprising the implicit dictionary and a result tree * substituted with references into the dictionary. */ - override def emitDictionary(pos: Position, result: SearchResult)(implicit ctx: Context): SearchResult = { + override def emitDictionary(span: Span, result: SearchResult)(implicit ctx: Context): SearchResult = { if (implicitDictionary == null || implicitDictionary.isEmpty) result else { result match { @@ -1522,9 +1516,9 @@ final class SearchRoot extends SearchHistory { // } val parents = List(defn.ObjectType, defn.SerializableType) - val classSym = ctx.newNormalizedClassSymbol(ctx.owner, LazyImplicitName.fresh().toTypeName, Synthetic | Final, parents, coord = pos) + val classSym = ctx.newNormalizedClassSymbol(ctx.owner, LazyImplicitName.fresh().toTypeName, Synthetic | Final, parents, coord = span) val vsyms = pruned.map(_._1.symbol) - val nsyms = vsyms.map(vsym => ctx.newSymbol(classSym, vsym.name, EmptyFlags, vsym.info, coord = pos).entered) + val nsyms = vsyms.map(vsym => ctx.newSymbol(classSym, vsym.name, EmptyFlags, vsym.info, coord = span).entered) val vsymMap = (vsyms zip nsyms).toMap val rhss = pruned.map(_._2) @@ -1543,7 +1537,7 @@ final class SearchRoot extends SearchHistory { val constr = ctx.newConstructor(classSym, Synthetic, Nil, Nil).entered val classDef = ClassDef(classSym, DefDef(constr), vdefs) - val valSym = ctx.newLazyImplicit(classSym.typeRef, pos) + val valSym = ctx.newLazyImplicit(classSym.typeRef, span) val inst = ValDef(valSym, New(classSym.typeRef, Nil)) // Substitute dictionary references into outermost result term. diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index c49bf8ef0ad6..389fe82c2732 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -8,7 +8,7 @@ import Contexts._, Types._, Flags._, Symbols._ import Trees._ import ProtoTypes._ import NameKinds.UniqueName -import util.Positions._ +import util.Spans._ import util.{Stats, SimpleIdentityMap} import Decorators._ import config.Printers.{gadts, typr} @@ -38,9 +38,9 @@ object Inferencing { /** The fully defined type, where all type variables are forced. * Throws an error if type contains wildcards. */ - def fullyDefinedType(tp: Type, what: String, pos: Position)(implicit ctx: Context): Type = + def fullyDefinedType(tp: Type, what: String, span: Span)(implicit ctx: Context): Type = if (isFullyDefined(tp, ForceDegree.all)) tp - else throw new Error(i"internal error: type of $what $tp is not fully defined, pos = $pos") // !!! DEBUG + else throw new Error(i"internal error: type of $what $tp is not fully defined, pos = $span") // !!! DEBUG /** Instantiate selected type variables `tvars` in type `tp` */ @@ -144,7 +144,7 @@ object Inferencing { val (tl1, tvars) = constrained(tl, tree) var tree1 = AppliedTypeTree(tree.withType(tl1), tvars) tree1.tpe <:< pt - fullyDefinedType(tree1.tpe, "template parent", tree.pos) + fullyDefinedType(tree1.tpe, "template parent", tree.span) tree1 case _ => tree @@ -288,7 +288,7 @@ object Inferencing { * @return The list of type symbols that were created * to instantiate undetermined type variables that occur non-variantly */ - def maximizeType(tp: Type, pos: Position, fromScala2x: Boolean)(implicit ctx: Context): List[Symbol] = Stats.track("maximizeType") { + def maximizeType(tp: Type, span: Span, fromScala2x: Boolean)(implicit ctx: Context): List[Symbol] = Stats.track("maximizeType") { val vs = variances(tp) val patternBound = new mutable.ListBuffer[Symbol] vs foreachBinding { (tvar, v) => @@ -299,7 +299,7 @@ object Inferencing { if (bounds.hi <:< bounds.lo || bounds.hi.classSymbol.is(Final) || fromScala2x) tvar.instantiate(fromBelow = false) else { - val wildCard = ctx.newPatternBoundSymbol(UniqueName.fresh(tvar.origin.paramName), bounds, pos) + val wildCard = ctx.newPatternBoundSymbol(UniqueName.fresh(tvar.origin.paramName), bounds, span) tvar.instantiateWith(wildCard.typeRef) patternBound += wildCard } diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index d27a6199f957..658ca818d807 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -24,7 +24,9 @@ import dotty.tools.dotc.util.{SimpleIdentityMap, SimpleIdentitySet} import collection.mutable import reporting.trace -import util.Positions.Position +import util.Spans.Span +import util.SourcePosition +import ast.TreeInfo object Inliner { import tpd._ @@ -61,15 +63,15 @@ object Inliner { */ def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree = { - /** Set the position of all trees logically contained in the expansion of - * inlined call `call` to the position of `call`. This transform is necessary - * when lifting bindings from the expansion to the outside of the call. - */ + /** Set the position of all trees logically contained in the expansion of + * inlined call `call` to the position of `call`. This transform is necessary + * when lifting bindings from the expansion to the outside of the call. + */ def liftFromInlined(call: Tree) = new TreeMap { override def transform(t: Tree)(implicit ctx: Context) = { t match { case Inlined(t, Nil, expr) if t.isEmpty => expr - case _ => super.transform(t.withPos(call.pos)) + case _ => super.transform(t.withSpan(call.span)) } } } @@ -112,7 +114,7 @@ object Inliner { i"""|Maximal number of successive inlines (${ctx.settings.XmaxInlines.value}) exceeded, |Maybe this is caused by a recursive inline method? |You can use -Xmax-inlines to change the limit.""", - (tree :: enclosingInlineds).last.pos + (tree :: enclosingInlineds).last.sourcePos ) } @@ -120,27 +122,25 @@ object Inliner { def dropInlined(inlined: Inlined)(implicit ctx: Context): Tree = { if (enclosingInlineds.nonEmpty) inlined // Remove in the outer most inlined call else { - val inlinedAtPos = inlined.call.pos - val callSourceFile = ctx.source.file + val inlinedAtPos = inlined.call.sourcePos + val curSource = ctx.compilationUnit.source /** Removes all Inlined trees, replacing them with blocks. * Repositions all trees directly inside an inlined expansion of a non empty call to the position of the call. * Any tree directly inside an empty call (inlined in the inlined code) retains their position. */ class Reposition extends TreeMap { - override def transform(tree: Tree)(implicit ctx: Context): Tree = { - tree match { - case tree: Inlined => transformInline(tree) - case _ => - val transformed = super.transform(tree) - enclosingInlineds match { - case call :: _ if call.symbol.sourceFile != callSourceFile => - // Until we implement JSR-45, we cannot represent in output positions in other source files. - // So, reposition inlined code from other files with the call position: - transformed.withPos(inlinedAtPos) - case _ => transformed - } - } + override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match { + case tree: Inlined => transformInline(tree) + case _ => + val transformed = super.transform(tree) + enclosingInlineds match { + case call :: _ if call.symbol.source != curSource => + // Until we implement JSR-45, we cannot represent in output positions in other source files. + // So, reposition inlined code from other files with the call position: + transformed.withSpan(inlined.call.span) + case _ => transformed + } } def transformInline(tree: Inlined)(implicit ctx: Context): Tree = { tpd.seq(transformSub(tree.bindings), transform(tree.expansion)(inlineContext(tree.call))) @@ -157,8 +157,10 @@ object Inliner { * in the call field of an Inlined node. * The trace has enough info to completely reconstruct positions. */ - def inlineCallTrace(callSym: Symbol, pos: Position)(implicit ctx: Context): Tree = - Ident(callSym.topLevelClass.typeRef).withPos(pos) + def inlineCallTrace(callSym: Symbol, pos: SourcePosition)(implicit ctx: Context): Tree = { + implicit val src = pos.source + Ident(callSym.topLevelClass.typeRef).withSpan(pos.span) + } } /** Produces an inlined version of `call` via its `inlined` method. @@ -175,7 +177,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { private val inlineCallPrefix = qualifier(methPart) // Make sure all type arguments to the call are fully determined - for (targ <- callTypeArgs) fullyDefinedType(targ.tpe, "inlined type argument", targ.pos) + for (targ <- callTypeArgs) fullyDefinedType(targ.tpe, "inlined type argument", targ.span) /** A map from parameter names of the inlineable method to references of the actual arguments. * For a type argument this is the full argument type. @@ -209,7 +211,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { private val bindingsBuf = new mutable.ListBuffer[MemberDef] private def newSym(name: Name, flags: FlagSet, info: Type): Symbol = - ctx.newSymbol(ctx.owner, name, flags, info, coord = call.pos) + ctx.newSymbol(ctx.owner, name, flags, info, coord = call.span) /** A binding for the parameter of an inline method. This is a `val` def for * by-value parameters and a `def` def for by-name parameters. `val` defs inherit @@ -233,7 +235,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { val binding = { if (isByName) DefDef(boundSym, arg.changeOwner(ctx.owner, boundSym)) else ValDef(boundSym, arg) - }.withPos(boundSym.pos) + }.withSpan(boundSym.span) boundSym.defTree = binding bindingsBuf += binding binding @@ -287,7 +289,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { ref(rhsClsSym.sourceModule) else inlineCallPrefix - val binding = ValDef(selfSym.asTerm, rhs).withPos(selfSym.pos) + val binding = ValDef(selfSym.asTerm, rhs).withSpan(selfSym.span) bindingsBuf += binding selfSym.defTree = binding inlining.println(i"proxy at $level: $selfSym = ${bindingsBuf.last}") @@ -345,13 +347,14 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { */ def integrate(tree: Tree, originalOwner: Symbol)(implicit ctx: Context): Tree = { val result = tree.changeOwner(originalOwner, ctx.owner) - if (!originalOwner.isContainedIn(inlinedMethod)) Inlined(EmptyTree, Nil, result) + if (!originalOwner.isContainedIn(inlinedMethod)) + Inlined(EmptyTree, Nil, result).withSpan(tree.span) else result } def tryConstValue: Tree = ctx.typeComparer.constValue(callTypeArgs.head.tpe) match { - case Some(c) => Literal(c).withPos(call.pos) + case Some(c) => Literal(c).withSpan(call.span) case _ => EmptyTree } @@ -362,7 +365,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { if (inlinedMethod == defn.Typelevel_constValue) { val constVal = tryConstValue if (!constVal.isEmpty) return constVal - ctx.error(i"not a constant type: ${callTypeArgs.head}; cannot take constValue", call.pos) + ctx.error(i"not a constant type: ${callTypeArgs.head}; cannot take constValue", call.sourcePos) } else if (inlinedMethod == defn.Typelevel_constValueOpt) { val constVal = tryConstValue @@ -408,15 +411,17 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { tree.tpe match { case thistpe: ThisType => thisProxy.get(thistpe.cls) match { - case Some(t) => ref(t).withPos(tree.pos) + case Some(t) => ref(t).withSpan(tree.span) case None => tree } case _ => tree } case tree: Ident => paramProxy.get(tree.tpe) match { - case Some(t) if tree.isTerm && t.isSingleton => singleton(t.dealias).withPos(tree.pos) - case Some(t) if tree.isType => TypeTree(t).withPos(tree.pos) + case Some(t) if tree.isTerm && t.isSingleton => + singleton(t.dealias).withSpan(tree.span) + case Some(t) if tree.isType => + TypeTree(t).withSpan(tree.span) case _ => tree } case tree => tree @@ -427,7 +432,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { // Apply inliner to `rhsToInline`, split off any implicit bindings from result, and // make them part of `bindingsBuf`. The expansion is then the tree that remains. - val expansion = inliner.transform(rhsToInline.withPos(call.pos)) + val expansion = inliner.transform(rhsToInline).withSpan(call.span) def issueError() = callValueArgss match { case (msgArg :: rest) :: Nil => @@ -449,7 +454,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { case _ => arg.show } } - ctx.error(s"$msg${rest.map(decompose).mkString(", ")}", callToReport.pos) + ctx.error(s"$msg${rest.map(decompose).mkString(", ")}", callToReport.sourcePos) } issueInCtx(ctxToReport) case _ => @@ -593,7 +598,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { case _ => binding } - binding1.withPos(call.pos) + binding1.withSpan(call.span) } /** An extractor for references to inlineable arguments. These are : @@ -701,15 +706,15 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { */ def newBinding(sym: TermSymbol, rhs: Tree): Unit = { sym.info = rhs.tpe.widenTermRefExpr - bindingsBuf += ValDef(sym, constToLiteral(rhs)).withPos(sym.pos) + bindingsBuf += ValDef(sym, constToLiteral(rhs)).withSpan(sym.span) } def searchImplicit(sym: TermSymbol, tpt: Tree) = { val evTyper = new Typer - val evidence = evTyper.inferImplicitArg(tpt.tpe, tpt.pos)(ctx.fresh.setTyper(evTyper)) + val evidence = evTyper.inferImplicitArg(tpt.tpe, tpt.span)(ctx.fresh.setTyper(evTyper)) evidence.tpe match { case fail: Implicits.AmbiguousImplicits => - ctx.error(evTyper.missingArgMsg(evidence, tpt.tpe, ""), tpt.pos) + ctx.error(evTyper.missingArgMsg(evidence, tpt.tpe, ""), tpt.sourcePos) true // hard error: return true to stop implicit search here case fail: Implicits.SearchFailureType => false @@ -874,7 +879,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { if (from.isEmpty) Some((caseBindings, cdef.body)) else { val Block(stats, expr) = tpd.Block(caseBindings, cdef.body).subst(from, to) - val typeDefs = to.collect { case sym if sym.name != tpnme.WILDCARD => tpd.TypeDef(sym).withPos(sym.pos) } + val typeDefs = to.collect { case sym if sym.name != tpnme.WILDCARD => tpd.TypeDef(sym).withSpan(sym.span) } Some((typeDefs ::: stats.asInstanceOf[List[MemberDef]], expr)) } } @@ -903,7 +908,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { class InlineTyper extends ReTyper { import reducer._ - override def ensureAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = { + override def ensureAccessible(tpe: Type, superAccess: Boolean, pos: SourcePosition)(implicit ctx: Context): Type = { tpe match { case tpe: NamedType if tpe.symbol.exists && !tpe.symbol.isAccessibleFrom(tpe.prefix, superAccess) => tpe.info match { @@ -923,7 +928,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { assert(tree.hasType, tree) val qual1 = typed(tree.qualifier, selectionProto(tree.name, pt, this)) val res = untpd.cpy.Select(tree)(qual1, tree.name).withType(tree.typeOpt) - ensureAccessible(res.tpe, tree.qualifier.isInstanceOf[untpd.Super], tree.pos) + ensureAccessible(res.tpe, tree.qualifier.isInstanceOf[untpd.Super], tree.sourcePos) res } @@ -958,7 +963,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { // drop type ascriptions/casts hiding pattern-bound types (which are now aliases after reducing the match) // note that any actually necessary casts will be reinserted by the typing pass below val rhs1 = rhs0 match { - case Block(stats, t) if t.pos.isSynthetic => + case Block(stats, t) if t.span.isSynthetic => t match { case Typed(expr, _) => Block(stats, expr) @@ -1094,7 +1099,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { treeMap = { case ident: Ident if ident.isType && typeBindingsSet.contains(ident.symbol) => val TypeAlias(r) = ident.symbol.info - TypeTree(r).withPos(ident.pos) + TypeTree(r).withSpan(ident.span) case tree => tree } ) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index fa881495dcf9..90611e820dda 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -9,7 +9,7 @@ import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Fla import NameKinds.DefaultGetterName import ast.desugar, ast.desugar._ import ProtoTypes._ -import util.Positions._ +import util.Spans._ import util.Property import collection.mutable import tpd.ListOfTreeDecorator @@ -243,11 +243,12 @@ class Namer { typer: Typer => } /** The enclosing class with given name; error if none exists */ - def enclosingClassNamed(name: TypeName, pos: Position)(implicit ctx: Context): Symbol = { + def enclosingClassNamed(name: TypeName, span: Span)(implicit ctx: Context): Symbol = { if (name.isEmpty) NoSymbol else { val cls = ctx.owner.enclosingClassNamed(name) - if (!cls.exists) ctx.error(s"no enclosing class or object is named $name", pos) + if (!cls.exists) + ctx.error(s"no enclosing class or object is named $name", ctx.source.atSpan(span)) cls } } @@ -265,7 +266,7 @@ class Namer { typer: Typer => def createSymbol(tree: Tree)(implicit ctx: Context): Symbol = { def privateWithinClass(mods: Modifiers) = - enclosingClassNamed(mods.privateWithin, mods.pos) + enclosingClassNamed(mods.privateWithin, tree.span) /** Check that flags are OK for symbol. This is done early to avoid * catastrophic failure when we create a TermSymbol with TypeFlags, or vice versa. @@ -279,7 +280,7 @@ class Namer { typer: Typer => case _ => (flags.isTermFlags, flags.toTermFlags, "value") } if (!ok) - ctx.error(i"modifier(s) `$flags' incompatible with $kind definition", tree.pos) + ctx.error(i"modifier(s) `$flags' incompatible with $kind definition", tree.sourcePos) adapted } @@ -292,7 +293,7 @@ class Namer { typer: Typer => def checkNoConflict(name: Name): Name = { def errorName(msg: => String) = { - ctx.error(msg, tree.pos) + ctx.error(msg, tree.sourcePos) name.freshened } def preExisting = ctx.effectiveScope.lookup(name) @@ -331,7 +332,7 @@ class Namer { typer: Typer => val cls = createOrRefine[ClassSymbol](tree, name, flags, cls => adjustIfModule(new ClassCompleter(cls, tree)(ctx), tree), - ctx.newClassSymbol(ctx.owner, name, _, _, _, tree.namePos, ctx.source.file)) + ctx.newClassSymbol(ctx.owner, name, _, _, _, tree.nameSpan, ctx.source.file)) cls.completer.asInstanceOf[ClassCompleter].init() cls case tree: MemberDef => @@ -363,9 +364,9 @@ class Namer { typer: Typer => val info = adjustIfModule(completer, tree) createOrRefine[Symbol](tree, name, flags | deferred | method | higherKinded, _ => info, - (fs, _, pwithin) => ctx.newSymbol(ctx.owner, name, fs, info, pwithin, tree.namePos)) + (fs, _, pwithin) => ctx.newSymbol(ctx.owner, name, fs, info, pwithin, tree.nameSpan)) case tree: Import => - recordSym(ctx.newImportSymbol(ctx.owner, new Completer(tree), tree.pos), tree) + recordSym(ctx.newImportSymbol(ctx.owner, new Completer(tree), tree.span), tree) case _ => NoSymbol } @@ -404,7 +405,7 @@ class Namer { typer: Typer => /** If there's already an existing type, then the package is a dup of this type */ val existingType = pkgOwner.info.decls.lookup(pid.name.toTypeName) if (existingType.exists) { - ctx.error(PkgDuplicateSymbol(existingType), pid.pos) + ctx.error(PkgDuplicateSymbol(existingType), pid.sourcePos) ctx.newCompletePackageSymbol(pkgOwner, (pid.name ++ "$_error_").toTermName).entered } else ctx.newCompletePackageSymbol(pkgOwner, pid.name.asTermName).entered @@ -693,7 +694,7 @@ class Namer { typer: Typer => } def missingType(sym: Symbol, modifier: String)(implicit ctx: Context): Unit = { - ctx.error(s"${modifier}type of implicit definition needs to be given explicitly", sym.pos) + ctx.error(s"${modifier}type of implicit definition needs to be given explicitly", sym.sourcePos) sym.resetFlag(Implicit) } @@ -796,7 +797,7 @@ class Namer { typer: Typer => denot.info = typeSig(sym) invalidateIfClashingSynthetic(denot) Checking.checkWellFormed(sym) - denot.info = avoidPrivateLeaks(sym, sym.pos) + denot.info = avoidPrivateLeaks(sym, sym.sourcePos) } } @@ -869,7 +870,7 @@ class Namer { typer: Typer => else { if (denot.is(ModuleClass) && denot.sourceModule.is(Implicit)) missingType(denot.symbol, "parent ")(creationContext) - fullyDefinedType(typedAheadExpr(parent).tpe, "class parent", parent.pos) + fullyDefinedType(typedAheadExpr(parent).tpe, "class parent", parent.span) } case _ => UnspecifiedErrorType.assertingErrorsReported @@ -886,7 +887,7 @@ class Namer { typer: Typer => val ptype = parentType(parent)(ctx.superCallContext).dealiasKeepAnnots if (cls.isRefinementClass) ptype else { - val pt = checkClassType(ptype, parent.pos, + val pt = checkClassType(ptype, parent.posd, traitReq = parent ne parents.head, stablePrefixReq = true) if (pt.derivesFrom(cls)) { val addendum = parent match { @@ -894,15 +895,15 @@ class Namer { typer: Typer => "\n(Note that inheriting a class of the same name is no longer allowed)" case _ => "" } - ctx.error(CyclicInheritance(cls, addendum), parent.pos) + ctx.error(CyclicInheritance(cls, addendum), parent.sourcePos) defn.ObjectType } else { val pclazz = pt.typeSymbol if (pclazz.is(Final)) - ctx.error(ExtendFinalClass(cls, pclazz), cls.pos) + ctx.error(ExtendFinalClass(cls, pclazz), cls.sourcePos) if (pclazz.is(Sealed) && pclazz.associatedFile != cls.associatedFile) - ctx.error(UnableToExtendSealedClass(pclazz), cls.pos) + ctx.error(UnableToExtendSealedClass(pclazz), cls.sourcePos) pt } } @@ -916,7 +917,7 @@ class Namer { typer: Typer => val moduleType = cls.owner.thisType select sourceModule if (self.name == nme.WILDCARD) moduleType else recordSym( - ctx.newSymbol(cls, self.name, self.mods.flags, moduleType, coord = self.pos), + ctx.newSymbol(cls, self.name, self.mods.flags, moduleType, coord = self.span), self) } else createSymbol(self) @@ -935,7 +936,7 @@ class Namer { typer: Typer => symbolOfTree(constr).ensureCompleted() val parentTypes = defn.adjustForTuple(cls, cls.typeParams, - ensureFirstIsClass(parents.map(checkedParentType(_)), cls.pos)) + ensureFirstIsClass(parents.map(checkedParentType(_)), cls.span)) typr.println(i"completing $denot, parents = $parents%, %, parentTypes = $parentTypes%, %") val finalSelfInfo: TypeOrSymbol = @@ -970,7 +971,7 @@ class Namer { typer: Typer => Checking.checkWellFormed(cls) if (isDerivedValueClass(cls)) cls.setFlag(Final) - cls.info = avoidPrivateLeaks(cls, cls.pos) + cls.info = avoidPrivateLeaks(cls, cls.sourcePos) cls.baseClasses.foreach(_.invalidateBaseTypeCache()) // we might have looked before and found nothing cls.setNoInitsFlags(parentsKind(parents), bodyKind(rest)) if (cls.isNoInitsClass) cls.primaryConstructor.setFlag(Stable) @@ -1129,7 +1130,7 @@ class Namer { typer: Typer => } def cookedRhsType = deskolemize(dealiasIfUnit(widenRhs(rhsType))) - def lhsType = fullyDefinedType(cookedRhsType, "right-hand side", mdef.pos) + def lhsType = fullyDefinedType(cookedRhsType, "right-hand side", mdef.span) //if (sym.name.toString == "y") println(i"rhs = $rhsType, cooked = $cookedRhsType") if (inherited.exists) { if (sym.is(Final, butNot = Method)) { @@ -1155,7 +1156,7 @@ class Namer { typer: Typer => case _: untpd.DerivedTypeTree => WildcardType case TypeTree() => - checkMembersOK(inferredType, mdef.pos) + checkMembersOK(inferredType, mdef.sourcePos) case DependentTypeTree(tpFun) => val tpe = tpFun(paramss.head) if (isFullyDefined(tpe, ForceDegree.none)) tpe @@ -1167,7 +1168,7 @@ class Namer { typer: Typer => val hygienicType = avoid(rhsType, paramss.flatten) if (!hygienicType.isValueType || !(hygienicType <:< tpt.tpe)) ctx.error(i"return type ${tpt.tpe} of lambda cannot be made hygienic;\n" + - i"it is not a supertype of the hygienic type $hygienicType", mdef.pos) + i"it is not a supertype of the hygienic type $hygienicType", mdef.sourcePos) //println(i"lifting $rhsType over $paramss -> $hygienicType = ${tpt.tpe}") //println(TypeComparer.explained { implicit ctx => hygienicType <:< tpt.tpe }) case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala index ef8e4b42c06d..1b9765f3dfd2 100644 --- a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala +++ b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala @@ -84,7 +84,7 @@ object PrepareInlineable { def preTransform(tree: Tree)(implicit ctx: Context): Tree = tree match { case tree: RefTree if needsAccessor(tree.symbol) => if (tree.symbol.isConstructor) { - ctx.error("Implementation restriction: cannot use private constructors in inlineinline methods", tree.pos) + ctx.error("Implementation restriction: cannot use private constructors in inlineinline methods", tree.sourcePos) tree // TODO: create a proper accessor for the private constructor } else useAccessor(tree) @@ -168,7 +168,7 @@ object PrepareInlineable { ref(accessor) .appliedToTypeTrees(localRefs.map(TypeTree(_)) ++ targs) .appliedToArgss((qual :: Nil) :: argss) - .withPos(tree.pos) + .withSpan(tree.span) // TODO: Handle references to non-public types. // This is quite tricky, as such types can appear anywhere, including as parts @@ -178,7 +178,7 @@ object PrepareInlineable { // // val accessor = accessorSymbol(tree, TypeAlias(tree.tpe)).asType // myAccessors += TypeDef(accessor).withPos(tree.pos.focus) - // ref(accessor).withPos(tree.pos) + // ref(accessor).withSpan(tree.span) // case _ => tree } @@ -243,10 +243,10 @@ object PrepareInlineable { def checkInlineMethod(inlined: Symbol, body: Tree)(implicit ctx: Context): Unit = { if (ctx.outer.inInlineMethod) - ctx.error(ex"implementation restriction: nested inline methods are not supported", inlined.pos) + ctx.error(ex"implementation restriction: nested inline methods are not supported", inlined.sourcePos) if (inlined.name == nme.unapply && tupleArgs(body).isEmpty) ctx.warning( em"inline unapply method can be rewritten only if its right hand side is a tuple (e1, ..., eN)", - body.pos) + body.sourcePos) } } diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 9c3af1eef743..f68793b41f2f 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -12,6 +12,7 @@ import util.{Stats, SimpleIdentityMap} import Decorators._ import Uniques._ import config.Printers.typr +import util.SourceFile import scala.annotation.internal.sharable @@ -410,7 +411,7 @@ object ProtoTypes { } class UnapplyFunProto(argType: Type, typer: Typer)(implicit ctx: Context) extends FunProto( - untpd.TypedSplice(dummyTreeOfType(argType))(ctx) :: Nil, WildcardType)(typer) + untpd.TypedSplice(dummyTreeOfType(argType)(ctx.source))(ctx) :: Nil, WildcardType)(typer) /** A prototype for expressions [] that are type-parameterized: * @@ -471,7 +472,7 @@ object ProtoTypes { def newTypeVars(tl: TypeLambda): List[TypeTree] = for (paramRef <- tl.paramRefs) yield { - val tt = new TypeVarBinder().withPos(owningTree.pos) + val tt = new TypeVarBinder().withSpan(owningTree.span) val tvar = new TypeVar(paramRef, state) state.ownedVars += tvar tt.withType(tvar) @@ -652,7 +653,7 @@ object ProtoTypes { /** Dummy tree to be used as an argument of a FunProto or ViewProto type */ object dummyTreeOfType { - def apply(tp: Type): Tree = untpd.Literal(Constant(null)) withTypeUnchecked tp + def apply(tp: Type)(implicit src: SourceFile): Tree = untpd.Literal(Constant(null)) withTypeUnchecked tp def unapply(tree: untpd.Tree): Option[Type] = tree match { case Literal(Constant(null)) => Some(tree.typeOpt) case _ => None diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index e3d2f4232dd0..0a84f1e92da0 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -10,7 +10,7 @@ import Decorators._ import typer.ProtoTypes._ import ast.{tpd, untpd} import scala.util.control.NonFatal -import util.Positions.Position +import util.Spans.Span /** A version of Typer that keeps all symbols defined and referenced in a * previously typed tree. @@ -120,7 +120,7 @@ class ReTyper extends Typer with ReChecking { override def checkVariance(tree: Tree)(implicit ctx: Context): Unit = () override def inferView(from: Tree, to: Type)(implicit ctx: Context): Implicits.SearchResult = Implicits.NoMatchingImplicitsFailure - override def checkCanEqual(ltp: Type, rtp: Type, pos: Position)(implicit ctx: Context): Unit = () + override def checkCanEqual(ltp: Type, rtp: Type, span: Span)(implicit ctx: Context): Unit = () override protected def addAccessorDefs(cls: Symbol, body: List[Tree])(implicit ctx: Context): List[Tree] = body override protected def checkEqualityEvidence(tree: tpd.Tree, pt: Type)(implicit ctx: Context): Unit = () } diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 1d84c3478d33..9944e2ce3b3a 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -7,8 +7,8 @@ import Symbols._, Types._, Contexts._, Flags._, Names._, NameOps._ import StdNames._, Denotations._, SymUtils._ import NameKinds.DefaultGetterName import Annotations._ -import util.Positions._ -import util.Store +import util.Spans._ +import util.{Store, SourcePosition} import scala.collection.{ mutable, immutable } import ast._ import Trees._ @@ -59,7 +59,7 @@ object RefChecks { " define default arguments" + ( if (owners.forall(_ == clazz)) "." else ".\nThe members with defaults are defined in " + owners.map(_.showLocated).mkString("", " and ", ".")), - clazz.pos) + clazz.sourcePos) } } } @@ -68,7 +68,7 @@ object RefChecks { if (clazz derivesFrom defn.DynamicClass) { for ((_, m1 :: m2 :: _) <- (clazz.info member nme.applyDynamic).alternatives groupBy (_.symbol.typeParams.length)) { ctx.error("implementation restriction: applyDynamic cannot be overloaded except by methods with different numbers of type parameters, e.g. applyDynamic[T1](method: String)(arg: T1) and applyDynamic[T1, T2](method: String)(arg1: T1, arg2: T2)", - m1.symbol.pos) + m1.symbol.sourcePos) } } } @@ -98,7 +98,7 @@ object RefChecks { val otherSelf = other.givenSelfType.asSeenFrom(cls.thisType, other.classSymbol) if (otherSelf.exists && !(cinfo.selfType <:< otherSelf)) ctx.error(DoesNotConformToSelfType(category, cinfo.selfType, cls, otherSelf, relation, other.classSymbol), - cls.pos) + cls.sourcePos) } for (parent <- cinfo.classParents) checkSelfConforms(parent.classSymbol.asClass, "illegal inheritance", "parent") @@ -117,7 +117,7 @@ object RefChecks { case TypeRef(ref: TermRef, _) => val paramRefs = ref.namedPartsWith(ntp => ntp.symbol.enclosingClass == cls) if (paramRefs.nonEmpty) - ctx.error("trait parameters cannot be used as parent prefixes", parent.pos) + ctx.error("trait parameters cannot be used as parent prefixes", parent.sourcePos) case _ => } @@ -132,7 +132,7 @@ object RefChecks { val others = cls.owner.linkedClass.info.decls.filter(clashes) others.foreach { other => - ctx.error(ClassAndCompanionNameClash(cls, other), cls.pos) + ctx.error(ClassAndCompanionNameClash(cls, other), cls.sourcePos) } } @@ -182,7 +182,7 @@ object RefChecks { mixinOverrideErrors.toList match { case List() => case List(MixinOverrideError(_, msg)) => - ctx.error(msg, clazz.pos) + ctx.error(msg, clazz.sourcePos) case MixinOverrideError(member, msg) :: others => val others1 = others.map(_.member).filter(_.name != member.name).distinct def othersMsg = { @@ -192,7 +192,7 @@ object RefChecks { if (others1.isEmpty) "" else i";\nother members with override errors are:: $others1%, %" } - ctx.error(msg + othersMsg, clazz.pos) + ctx.error(msg + othersMsg, clazz.sourcePos) } } @@ -244,7 +244,7 @@ object RefChecks { if (!(hasErrors && member.is(Synthetic) && member.is(Module))) { // suppress errors relating toi synthetic companion objects if other override // errors (e.g. relating to the companion class) have already been reported. - if (member.owner == clazz) ctx.error(fullmsg, member.pos) + if (member.owner == clazz) ctx.error(fullmsg, member.sourcePos) else mixinOverrideErrors += new MixinOverrideError(member, fullmsg) hasErrors = true } @@ -283,7 +283,7 @@ object RefChecks { memberTp.overrides(otherTp, member.matchNullaryLoosely || other.matchNullaryLoosely || ctx.testScala2Mode(overrideErrorMsg("no longer has compatible type"), - (if (member.owner == clazz) member else clazz).pos)) + (if (member.owner == clazz) member else clazz).sourcePos)) catch { case ex: MissingType => // can happen when called with upwardsSelf as qualifier of memberTp and otherTp, @@ -355,7 +355,8 @@ object RefChecks { // Also exclusion for implicit shortcut methods // Also excluded under Scala2 mode are overrides of default methods of Java traits. if (autoOverride(member) || - other.owner.is(JavaTrait) && ctx.testScala2Mode("`override' modifier required when a Java 8 default method is re-implemented", member.pos)) + other.owner.is(JavaTrait) && + ctx.testScala2Mode("`override' modifier required when a Java 8 default method is re-implemented", member.sourcePos)) member.setFlag(Override) else if (member.isType && self.memberInfo(member) =:= self.memberInfo(other)) () // OK, don't complain about type aliases which are equal @@ -386,7 +387,7 @@ object RefChecks { } else if (member.is(ModuleVal) && !other.isRealMethod && !other.is(Deferred | Lazy)) { overrideError("may not override a concrete non-lazy value") } else if (member.is(Lazy, butNot = Module) && !other.isRealMethod && !other.is(Lazy) && - !ctx.testScala2Mode("may not override a non-lazy value", member.pos)) { + !ctx.testScala2Mode("may not override a non-lazy value", member.sourcePos)) { overrideError("may not override a non-lazy value") } else if (other.is(Lazy) && !other.isRealMethod && !member.is(Lazy)) { overrideError("must be declared lazy to override a lazy value") @@ -431,7 +432,7 @@ object RefChecks { "\n(Note that having same-named member classes in types of a mixin composition is no longer allowed)" case _ => "" } - ctx.error(ex.getMessage + addendum, clazz.pos) + ctx.error(ex.getMessage + addendum, clazz.sourcePos) } printMixinOverrideErrors() @@ -659,7 +660,7 @@ object RefChecks { em"""${mbr.showLocated} is not a legal implementation of `$name' in $clazz | its type $mbrType | does not conform to ${mbrd.info}""", - (if (mbr.owner == clazz) mbr else clazz).pos) + (if (mbr.owner == clazz) mbr else clazz).sourcePos) } } } @@ -673,14 +674,14 @@ object RefChecks { for (baseCls <- caseCls.info.baseClasses.tail) if (baseCls.typeParams.exists(_.paramVariance != 0)) for (problem <- variantInheritanceProblems(baseCls, caseCls, "non-variant", "case ")) - ctx.errorOrMigrationWarning(problem(), clazz.pos) + ctx.errorOrMigrationWarning(problem(), clazz.sourcePos) } checkNoAbstractMembers() if (abstractErrors.isEmpty) checkNoAbstractDecls(clazz) if (abstractErrors.nonEmpty) - ctx.error(abstractErrorMessage, clazz.pos) + ctx.error(abstractErrorMessage, clazz.sourcePos) checkMemberTypesOK() checkCaseClassInheritanceInvariant() @@ -693,7 +694,7 @@ object RefChecks { // override a concrete method in Object. The jvm, however, does not. val overridden = decl.matchingDecl(defn.ObjectClass, defn.ObjectType) if (overridden.is(Final)) - ctx.error(TraitRedefinedFinalMethodFromAnyRef(overridden), decl.pos) + ctx.error(TraitRedefinedFinalMethodFromAnyRef(overridden), decl.sourcePos) } } @@ -715,7 +716,7 @@ object RefChecks { cls <- clazz.info.baseClasses.tail if cls.paramAccessors.nonEmpty && !mixins.contains(cls) problem <- variantInheritanceProblems(cls, clazz.asClass.superClass, "parameterized", "super") - } ctx.error(problem(), clazz.pos) + } ctx.error(problem(), clazz.sourcePos) } checkParameterizedTraitsOK() @@ -794,9 +795,9 @@ object RefChecks { val nonMatching = clazz.info.member(member.name).altsWith(alt => alt.owner != clazz) nonMatching match { case Nil => - ctx.error(OverridesNothing(member), member.pos) + ctx.error(OverridesNothing(member), member.sourcePos) case ms => - ctx.error(OverridesNothingButNameExists(member, ms), member.pos) + ctx.error(OverridesNothingButNameExists(member, ms), member.sourcePos) } member.resetFlag(Override) member.resetFlag(AbsOverride) @@ -808,7 +809,7 @@ object RefChecks { // I assume that's a consequence of some code trying to avoid noise by suppressing // warnings after the first, but I think it'd be better if we didn't have to // arbitrarily choose one as more important than the other. - private def checkUndesiredProperties(sym: Symbol, pos: Position)(implicit ctx: Context): Unit = { + private def checkUndesiredProperties(sym: Symbol, pos: SourcePosition)(implicit ctx: Context): Unit = { // If symbol is deprecated, and the point of reference is not enclosed // in either a deprecated member or a scala bridge method, issue a warning. if (sym.isDeprecated && !ctx.owner.ownersIterator.exists(_.isDeprecated)) { @@ -852,7 +853,7 @@ object RefChecks { if (!concrOvers.isEmpty) ctx.deprecationWarning( symbol.toString + " overrides concrete, non-deprecated symbol(s):" + - concrOvers.map(_.name).mkString(" ", ", ", ""), tree.pos) + concrOvers.map(_.name).mkString(" ", ", ", ""), tree.sourcePos) } } @@ -860,7 +861,7 @@ object RefChecks { class OptLevelInfo { def levelAndIndex: LevelAndIndex = Map() - def enterReference(sym: Symbol, pos: Position): Unit = () + def enterReference(sym: Symbol, span: Span): Unit = () } /** A class to help in forward reference checking */ @@ -876,15 +877,15 @@ object RefChecks { (m1, idx + 1) }._1 var maxIndex: Int = Int.MinValue - var refPos: Position = _ + var refSpan: Span = _ var refSym: Symbol = _ - override def enterReference(sym: Symbol, pos: Position): Unit = + override def enterReference(sym: Symbol, span: Span): Unit = if (sym.exists && sym.owner.isTerm) levelAndIndex.get(sym) match { case Some((level, idx)) if (level.maxIndex < idx) => level.maxIndex = idx - level.refPos = pos + level.refSpan = span level.refSym = sym case _ => } @@ -951,13 +952,14 @@ class RefChecks extends MiniPhase { thisPhase => val sym = tree.symbol if (sym.exists && sym.owner.isTerm) { tree.rhs match { - case Ident(nme.WILDCARD) => ctx.error(UnboundPlaceholderParameter(), sym.pos) + case Ident(nme.WILDCARD) => ctx.error(UnboundPlaceholderParameter(), sym.sourcePos) case _ => } if (!sym.is(Lazy)) { currentLevel.levelAndIndex.get(sym) match { case Some((level, symIdx)) if symIdx <= level.maxIndex => - ctx.error(ForwardReferenceExtendsOverDefinition(sym, level.refSym), level.refPos) + ctx.error(ForwardReferenceExtendsOverDefinition(sym, level.refSym), + ctx.source.atSpan(level.refSpan)) case _ => } } @@ -980,18 +982,18 @@ class RefChecks extends MiniPhase { thisPhase => tree } catch { case ex: TypeError => - ctx.error(ex.getMessage, tree.pos) + ctx.error(ex.getMessage, tree.sourcePos) tree } override def transformIdent(tree: Ident)(implicit ctx: Context): Ident = { - checkUndesiredProperties(tree.symbol, tree.pos) - currentLevel.enterReference(tree.symbol, tree.pos) + checkUndesiredProperties(tree.symbol, tree.sourcePos) + currentLevel.enterReference(tree.symbol, tree.span) tree } override def transformSelect(tree: Select)(implicit ctx: Context): Select = { - checkUndesiredProperties(tree.symbol, tree.pos) + checkUndesiredProperties(tree.symbol, tree.sourcePos) tree } @@ -1002,7 +1004,8 @@ class RefChecks extends MiniPhase { thisPhase => if (level.maxIndex > 0) { // An implementation restriction to avoid VerifyErrors and lazyvals mishaps; see SI-4717 ctx.debuglog("refsym = " + level.refSym) - ctx.error("forward reference not allowed from self constructor invocation", level.refPos) + ctx.error("forward reference not allowed from self constructor invocation", + ctx.source.atSpan(level.refSpan)) } } tree @@ -1011,10 +1014,10 @@ class RefChecks extends MiniPhase { thisPhase => override def transformNew(tree: New)(implicit ctx: Context): New = { val tpe = tree.tpe val sym = tpe.typeSymbol - checkUndesiredProperties(sym, tree.pos) - currentLevel.enterReference(sym, tree.pos) + checkUndesiredProperties(sym, tree.sourcePos) + currentLevel.enterReference(sym, tree.span) tpe.dealias.foreachPart { - case TermRef(_, s: Symbol) => currentLevel.enterReference(s, tree.pos) + case TermRef(_, s: Symbol) => currentLevel.enterReference(s, tree.span) case _ => } tree diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 317d3f762696..d66fe8eeb16d 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -6,7 +6,8 @@ import core._ import ast._ import Contexts._, Constants._, Types._, Symbols._, Names._, Flags._, Decorators._ import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._ -import util.Positions._ +import util.Spans._ +import util.SourcePosition import config.Printers.typr import ast.Trees._ import NameOps._ @@ -32,7 +33,7 @@ trait TypeAssigner { case _ => ctx.error( if (qual.isEmpty) tree.show + " can be used only in a class, object, or template" - else qual.show + " is not an enclosing class", tree.pos) + else qual.show + " is not an enclosing class", tree.sourcePos) NoSymbol } } @@ -149,7 +150,7 @@ trait TypeAssigner { def avoidingType(expr: Tree, bindings: List[Tree])(implicit ctx: Context): Type = avoid(expr.tpe, localSyms(bindings).filter(_.isTerm)) - def avoidPrivateLeaks(sym: Symbol, pos: Position)(implicit ctx: Context): Type = + def avoidPrivateLeaks(sym: Symbol, pos: SourcePosition)(implicit ctx: Context): Type = if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) checkNoPrivateLeaks(sym, pos) else sym.info @@ -184,7 +185,7 @@ trait TypeAssigner { * (2) if the owner of the denotation is a package object, it is assured * that the package object shows up as the prefix. */ - def ensureAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = { + def ensureAccessible(tpe: Type, superAccess: Boolean, pos: SourcePosition)(implicit ctx: Context): Type = { def test(tpe: Type, firstTry: Boolean): Type = tpe match { case tpe: NamedType => val pre = tpe.prefix @@ -235,7 +236,7 @@ trait TypeAssigner { /** The type of a selection with `name` of a tree with type `site`. */ - def selectionType(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = { + def selectionType(site: Type, name: Name, pos: SourcePosition)(implicit ctx: Context): Type = { val mbr = site.member(name) if (reallyExists(mbr)) site.select(name, mbr) @@ -261,11 +262,12 @@ trait TypeAssigner { var qualType = qual1.tpe.widenIfUnstable if (!qualType.hasSimpleKind && tree.name != nme.CONSTRUCTOR) // constructors are selected on typeconstructor, type arguments are passed afterwards - qualType = errorType(em"$qualType takes type parameters", qual1.pos) - else if (!qualType.isInstanceOf[TermType]) qualType = errorType(em"$qualType is illegal as a selection prefix", qual1.pos) - val ownType = selectionType(qualType, tree.name, tree.pos) + qualType = errorType(em"$qualType takes type parameters", qual1.sourcePos) + else if (!qualType.isInstanceOf[TermType]) + qualType = errorType(em"$qualType is illegal as a selection prefix", qual1.sourcePos) + val ownType = selectionType(qualType, tree.name, tree.sourcePos) if (tree.getAttachment(desugar.SuppressAccessCheck).isDefined) ownType - else ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.pos) + else ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.sourcePos) } /** Type assignment method. Each method takes as parameters @@ -316,7 +318,7 @@ trait TypeAssigner { val cls = qualifyingClass(tree, tree.qual.name, packageOK = false) tree.withType( if (cls.isClass) cls.thisType - else errorType("not a legal qualifying class for this", tree.pos)) + else errorType("not a legal qualifying class for this", tree.sourcePos)) } def assignType(tree: untpd.Super, qual: Tree, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context): Super = { @@ -329,9 +331,9 @@ trait TypeAssigner { case p :: Nil => p.typeConstructor case Nil => - errorType(SuperQualMustBeParent(mix, cls), tree.pos) + errorType(SuperQualMustBeParent(mix, cls), tree.sourcePos) case p :: q :: _ => - errorType("ambiguous parent class qualifier", tree.pos) + errorType("ambiguous parent class qualifier", tree.sourcePos) } val owntype = if (mixinClass.exists) mixinClass.appliedRef @@ -373,15 +375,15 @@ trait TypeAssigner { if (fntpe.isResultDependent) safeSubstParams(fntpe.resultType, fntpe.paramRefs, args.tpes) else fntpe.resultType else - errorType(i"wrong number of arguments at ${ctx.phase.prev} for $fntpe: ${fn.tpe}, expected: ${fntpe.paramInfos.length}, found: ${args.length}", tree.pos) + errorType(i"wrong number of arguments at ${ctx.phase.prev} for $fntpe: ${fn.tpe}, expected: ${fntpe.paramInfos.length}, found: ${args.length}", tree.sourcePos) case t => - errorType(err.takesNoParamsStr(fn, ""), tree.pos) + errorType(err.takesNoParamsStr(fn, ""), tree.sourcePos) } ConstFold(tree.withType(ownType)) } def assignType(tree: untpd.TypeApply, fn: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = { - def fail = tree.withType(errorType(err.takesNoParamsStr(fn, "type "), tree.pos)) + def fail = tree.withType(errorType(err.takesNoParamsStr(fn, "type "), tree.sourcePos)) fn.tpe.widen match { case pt: TypeLambda => tree.withType { @@ -393,9 +395,9 @@ trait TypeAssigner { val namedArgMap = new mutable.HashMap[Name, Type] for (NamedArg(name, arg) <- args) if (namedArgMap.contains(name)) - ctx.error(DuplicateNamedTypeParameter(name), arg.pos) + ctx.error(DuplicateNamedTypeParameter(name), arg.sourcePos) else if (!paramNames.contains(name)) - ctx.error(UndefinedNamedTypeParameter(name, paramNames), arg.pos) + ctx.error(UndefinedNamedTypeParameter(name, paramNames), arg.sourcePos) else namedArgMap(name) = arg.tpe @@ -432,7 +434,7 @@ trait TypeAssigner { else { val argTypes = args.tpes if (sameLength(argTypes, paramNames)) pt.instantiate(argTypes) - else wrongNumberOfTypeArgs(fn.tpe, pt.typeParams, args, tree.pos) + else wrongNumberOfTypeArgs(fn.tpe, pt.typeParams, args, tree.sourcePos) } } case err: ErrorType => @@ -544,7 +546,7 @@ trait TypeAssigner { val tparams = tycon.tpe.typeParams val ownType = if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes) - else wrongNumberOfTypeArgs(tycon.tpe, tparams, args, tree.pos) + else wrongNumberOfTypeArgs(tycon.tpe, tparams, args, tree.sourcePos) tree.withType(ownType) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 667c30cd0d90..0b726256c0b3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -24,7 +24,7 @@ import ErrorReporting._ import Checking._ import Inferencing._ import EtaExpansion.etaExpand -import util.Positions._ +import util.Spans._ import util.common._ import util.Property import Applications.{ExtMethodApply, wrapDefs, productSelectorTypes} @@ -58,7 +58,7 @@ object Typer { /** Assert tree has a position, unless it is empty or a typed splice */ def assertPositioned(tree: untpd.Tree)(implicit ctx: Context): Unit = if (!tree.isEmpty && !tree.isInstanceOf[untpd.TypedSplice] && ctx.typerState.isGlobalCommittable) - assert(tree.pos.exists, s"position not set for $tree # ${tree.uniqueId}") + assert(tree.span.exists, i"position not set for $tree # ${tree.uniqueId} of ${tree.getClass} in ${tree.source}") /** A context property that indicates the owner of any expressions to be typed in the context * if that owner is different from the context's owner. Typically, a context with a class @@ -112,9 +112,9 @@ class Typer extends Namer * @param name the name of the identifier * @param pt the expected type * @param required flags the result's symbol must have - * @param pos position to use for error reporting + * @param posd indicates position to use for error reporting */ - def findRef(name: Name, pt: Type, required: FlagConjunction, pos: Position)(implicit ctx: Context): Type = { + def findRef(name: Name, pt: Type, required: FlagConjunction, posd: Positioned)(implicit ctx: Context): Type = { val refctx = ctx val noImports = ctx.mode.is(Mode.InPackageClauseName) @@ -164,14 +164,14 @@ class Typer extends Namer } else { if (!scala2pkg && !previous.isError && !found.isError) { - refctx.error(AmbiguousImport(name, newPrec, prevPrec, prevCtx), pos) + refctx.error(AmbiguousImport(name, newPrec, prevPrec, prevCtx), posd.sourcePos) } previous } def selection(imp: ImportInfo, name: Name) = if (imp.sym.isCompleting) { - ctx.warning(i"cyclic ${imp.sym}, ignored", pos) + ctx.warning(i"cyclic ${imp.sym}, ignored", posd.sourcePos) NoType } else if (unimported.nonEmpty && unimported.contains(imp.site.termSymbol)) NoType @@ -193,7 +193,7 @@ class Typer extends Namer def checkUnambiguous(found: Type) = { val other = recur(selectors.tail) if (other.exists && found.exists && (found != other)) - refctx.error(em"reference to `$name` is ambiguous; it is imported twice", pos) + refctx.error(em"reference to `$name` is ambiguous; it is imported twice", posd.sourcePos) found } @@ -228,7 +228,7 @@ class Typer extends Namer */ def isDefinedInCurrentUnit(denot: Denotation)(implicit ctx: Context): Boolean = denot match { case MultiDenotation(d1, d2) => isDefinedInCurrentUnit(d1) || isDefinedInCurrentUnit(d2) - case denot: SingleDenotation => denot.symbol.sourceFile == ctx.source.file + case denot: SingleDenotation => denot.symbol.source == ctx.compilationUnit.source } /** Is `denot` the denotation of a self symbol? */ @@ -362,12 +362,12 @@ class Typer extends Namer unimported = Set.empty foundUnderScala2 = NoType try { - var found = findRef(name, pt, EmptyFlagConjunction, tree.pos) + var found = findRef(name, pt, EmptyFlagConjunction, tree.posd) if (foundUnderScala2.exists && !(foundUnderScala2 =:= found)) { ctx.migrationWarning( ex"""Name resolution will change. | currently selected : $foundUnderScala2 - | in the future, without -language:Scala2: $found""", tree.pos) + | in the future, without -language:Scala2: $found""", tree.sourcePos) found = foundUnderScala2 } found @@ -380,7 +380,7 @@ class Typer extends Namer val ownType = if (rawType.exists) - ensureAccessible(rawType, superAccess = false, tree.pos) + ensureAccessible(rawType, superAccess = false, tree.sourcePos) else if (name == nme._scope) { // gross hack to support current xml literals. // awaiting a better implicits based solution for library-supported xml @@ -392,13 +392,13 @@ class Typer extends Namer ctx.owner.owner.unforcedDecls.lookup(tree.name).exists) { // When InSuperCall mode and in a constructor we are in the arguments // of a this(...) constructor call - errorType(ex"$tree is not accessible from constructor arguments", tree.pos) + errorType(ex"$tree is not accessible from constructor arguments", tree.sourcePos) } else - errorType(new MissingIdent(tree, kind, name.show), tree.pos) + errorType(new MissingIdent(tree, kind, name.show), tree.sourcePos) val tree1 = ownType match { case ownType: NamedType if !prefixIsElidable(ownType) => - ref(ownType).withPos(tree.pos) + ref(ownType).withSpan(tree.span) case _ => tree.withType(ownType) } @@ -415,7 +415,7 @@ class Typer extends Namer !pt.isInstanceOf[ApplyingProto] && !tree.tpe.isStable && !isWildcardArg(tree)) - ctx.error(StableIdentPattern(tree, pt), tree.pos) + ctx.error(StableIdentPattern(tree, pt), tree.sourcePos) tree } @@ -433,7 +433,7 @@ class Typer extends Namer case _ => app } case qual1 => - if (tree.name.isTypeName) checkStable(qual1.tpe, qual1.pos) + if (tree.name.isTypeName) checkStable(qual1.tpe, qual1.posd) val select = typedSelect(tree, pt, qual1) if (select.tpe ne TryDynamicCallType) ConstFold(checkStableIdentPattern(select, pt)) else if (pt.isInstanceOf[FunOrPolyProto] || pt == AssignProto) select @@ -476,7 +476,7 @@ class Typer extends Namer } val enclosingInlineable = ctx.owner.ownersIterator.findSymbol(_.isInlineMethod) if (enclosingInlineable.exists && !PrepareInlineable.isLocal(qual1.symbol, enclosingInlineable)) - ctx.error(SuperCallsNotAllowedInlineable(enclosingInlineable), tree.pos) + ctx.error(SuperCallsNotAllowedInlineable(enclosingInlineable), tree.sourcePos) pt match { case pt: SelectionProto if pt.name.isTypeName => qual1 // don't do super references for types; they are meaningless anyway @@ -511,18 +511,18 @@ class Typer extends Namer typed(cpy.Block(tree)(clsDef :: Nil, New(Ident(x), Nil)), pt) case _ => var tpt1 = typedType(tree.tpt) - tpt1 = tpt1.withType(ensureAccessible(tpt1.tpe, superAccess = false, tpt1.pos)) + tpt1 = tpt1.withType(ensureAccessible(tpt1.tpe, superAccess = false, tpt1.sourcePos)) tpt1.tpe.dealias match { case TypeApplications.EtaExpansion(tycon) => tpt1 = tpt1.withType(tycon) case _ => } - if (checkClassType(tpt1.tpe, tpt1.pos, traitReq = false, stablePrefixReq = true) eq defn.ObjectType) - tpt1 = TypeTree(defn.ObjectType).withPos(tpt1.pos) + if (checkClassType(tpt1.tpe, tpt1.posd, traitReq = false, stablePrefixReq = true) eq defn.ObjectType) + tpt1 = TypeTree(defn.ObjectType).withSpan(tpt1.span) tpt1 match { case AppliedTypeTree(_, targs) => for (targ @ TypeBoundsTree(_, _) <- targs) - ctx.error(WildcardOnTypeArgumentNotAllowedOnNew(), targ.pos) + ctx.error(WildcardOnTypeArgumentNotAllowedOnNew(), targ.sourcePos) case _ => } @@ -543,7 +543,7 @@ class Typer extends Namer if (id.name == nme.WILDCARD || id.name == nme.WILDCARD_STAR) ifPat else { import untpd._ - typed(Bind(id.name, Typed(Ident(wildName), tree.tpt)).withPos(tree.pos), pt) + typed(Bind(id.name, Typed(Ident(wildName), tree.tpt)).withSpan(tree.span), pt) } case _ => ifExpr } @@ -603,7 +603,7 @@ class Typer extends Namer case tref: TypeRef if !tref.symbol.isClass && !ctx.isAfterTyper => require(ctx.mode.is(Mode.Pattern)) inferImplicit(defn.ClassTagType.appliedTo(tref), - EmptyTree, tree.tpt.pos)(ctx.retractMode(Mode.Pattern)) match { + EmptyTree, tree.tpt.span)(ctx.retractMode(Mode.Pattern)) match { case SearchSuccess(clsTag, _, _) => typed(untpd.Apply(untpd.TypedSplice(clsTag), untpd.TypedSplice(tree.expr)), pt) case _ => @@ -661,7 +661,7 @@ class Typer extends Namer lhsCore match { case lhsCore: RefTree if setter.exists => val setterTypeRaw = pre.select(setterName, setter) - val setterType = ensureAccessible(setterTypeRaw, isSuperSelection(lhsCore), tree.pos) + val setterType = ensureAccessible(setterTypeRaw, isSuperSelection(lhsCore), tree.sourcePos) val lhs2 = untpd.rename(lhsCore, setterName).withType(setterType) typedUnadapted(untpd.Apply(untpd.TypedSplice(lhs2), tree.rhs :: Nil), WildcardType, locked) case _ => @@ -712,7 +712,7 @@ class Typer extends Namer def noLeaks(t: Tree): Boolean = escapingRefs(t, localSyms).isEmpty if (noLeaks(tree)) tree else { - fullyDefinedType(tree.tpe, "block", tree.pos) + fullyDefinedType(tree.tpe, "block", tree.span) var avoidingType = avoid(tree.tpe, localSyms) val ptDefined = isFullyDefined(pt, ForceDegree.none) if (ptDefined && !(avoidingType <:< pt)) avoidingType = pt @@ -725,11 +725,11 @@ class Typer extends Namer } def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context): Tree = track("typedIf") { - if (tree.isInline) checkInInlineContext("inline if", tree.pos) + if (tree.isInline) checkInInlineContext("inline if", tree.posd) val cond1 = typed(tree.cond, defn.BooleanType) val thenp2 :: elsep2 :: Nil = harmonic(harmonize, pt) { val thenp1 = typed(tree.thenp, pt.notApplied) - val elsep1 = typed(tree.elsep orElse (untpd.unitLiteral withPos tree.pos), pt.notApplied) + val elsep1 = typed(tree.elsep.orElse(untpd.unitLiteral.withSpan(tree.span)), pt.notApplied) thenp1 :: elsep1 :: Nil } assignType(cpy.If(tree)(cond1, thenp2, elsep2), thenp2, elsep2) @@ -780,7 +780,7 @@ class Typer extends Namer val isImplicit = tree.mods.is(Implicit) var isErased = tree.mods.is(Erased) if (isErased && args.isEmpty) { - ctx.error("An empty function cannot not be erased", tree.pos) + ctx.error("An empty function cannot not be erased", tree.sourcePos) isErased = false } (isImplicit, isErased) @@ -797,22 +797,22 @@ class Typer extends Namer val companion = MethodType.maker(isImplicit = isImplicit, isErased = isErased) val mt = companion.fromSymbols(params1.map(_.symbol), resultTpt.tpe) if (mt.isParamDependent) - ctx.error(i"$mt is an illegal function type because it has inter-parameter dependencies", tree.pos) - val resTpt = TypeTree(mt.nonDependentResultApprox).withPos(body.pos) + ctx.error(i"$mt is an illegal function type because it has inter-parameter dependencies", tree.sourcePos) + val resTpt = TypeTree(mt.nonDependentResultApprox).withSpan(body.span) val typeArgs = params1.map(_.tpt) :+ resTpt val tycon = TypeTree(funCls.typeRef) val core = assignType(cpy.AppliedTypeTree(tree)(tycon, typeArgs), tycon, typeArgs) - val appMeth = ctx.newSymbol(ctx.owner, nme.apply, Synthetic | Method | Deferred, mt, coord = body.pos) + val appMeth = ctx.newSymbol(ctx.owner, nme.apply, Synthetic | Method | Deferred, mt, coord = body.span) val appDef = assignType( untpd.DefDef(appMeth.name, Nil, List(params1), resultTpt, EmptyTree), - appMeth).withPos(body.pos) + appMeth).withSpan(body.span) RefinedTypeTree(core, List(appDef), ctx.owner.asClass) } args match { case ValDef(_, _, _) :: _ => typedDependent(args.asInstanceOf[List[ValDef]])( - ctx.fresh.setOwner(ctx.newRefinedClassSymbol(tree.pos)).setNewScope) + ctx.fresh.setOwner(ctx.newRefinedClassSymbol(tree.span)).setNewScope) case _ => typed(cpy.AppliedTypeTree(tree)(untpd.TypeTree(funCls.typeRef), args :+ body), pt) } @@ -916,18 +916,18 @@ class Typer extends Namer } case _ => } - errorType(AnonymousFunctionMissingParamType(param, params, tree, pt), param.pos) + errorType(AnonymousFunctionMissingParamType(param, params, tree, pt), param.sourcePos) } def protoFormal(i: Int): Type = if (protoFormals.length == params.length) protoFormals(i) - else errorType(WrongNumberOfParameters(protoFormals.length), tree.pos) + else errorType(WrongNumberOfParameters(protoFormals.length), tree.sourcePos) /** Is `formal` a product type which is elementwise compatible with `params`? */ def ptIsCorrectProduct(formal: Type) = { isFullyDefined(formal, ForceDegree.noBottom) && (defn.isProductSubType(formal) || formal.derivesFrom(defn.PairClass)) && - productSelectorTypes(formal).corresponds(params) { + productSelectorTypes(formal, tree.sourcePos).corresponds(params) { (argType, param) => param.tpt.isEmpty || argType <:< typedAheadType(param.tpt).tpe } @@ -961,14 +961,14 @@ class Typer extends Namer case SAMType(sam) if !defn.isFunctionType(pt) && mt <:< sam => if (!isFullyDefined(pt, ForceDegree.all)) - ctx.error(ex"result type of closure is an underspecified SAM type $pt", tree.pos) + ctx.error(ex"result type of closure is an underspecified SAM type $pt", tree.sourcePos) TypeTree(pt) case _ => if (mt.isParamDependent) { throw new java.lang.Error( i"""internal error: cannot turn method type $mt into closure |because it has internal parameter dependencies, - |position = ${tree.pos}, raw type = ${mt.toString}""") // !!! DEBUG. Eventually, convert to an error? + |position = ${tree.span}, raw type = ${mt.toString}""") // !!! DEBUG. Eventually, convert to an error? } else if ((tree.tpt `eq` untpd.ImplicitEmptyTree) && mt.paramNames.isEmpty) // Note implicitness of function in target type since there are no method parameters that indicate it. @@ -977,7 +977,7 @@ class Typer extends Namer EmptyTree } case tp => - throw new java.lang.Error(i"internal error: closing over non-method $tp, pos = ${tree.pos}") + throw new java.lang.Error(i"internal error: closing over non-method $tp, pos = ${tree.span}") } else typed(tree.tpt) //println(i"typing closure $tree : ${meth1.tpe.widen}") @@ -988,7 +988,7 @@ class Typer extends Namer tree.selector match { case EmptyTree => if (tree.isInline) { - checkInInlineContext("implicit match", tree.pos) + checkInInlineContext("implicit match", tree.posd) val cases1 = tree.cases.mapconserve { case cdef @ CaseDef(pat @ Typed(Ident(nme.WILDCARD), _), _, _) => // case _ : T --> case evidence$n : T @@ -1000,12 +1000,12 @@ class Typer extends Namer else { val (protoFormals, _) = decomposeProtoFunction(pt, 1) val unchecked = pt.isRef(defn.PartialFunctionClass) - typed(desugar.makeCaseLambda(tree.cases, protoFormals.length, unchecked) withPos tree.pos, pt) + typed(desugar.makeCaseLambda(tree.cases, protoFormals.length, unchecked).withSpan(tree.span), pt) } case _ => - if (tree.isInline) checkInInlineContext("inline match", tree.pos) + if (tree.isInline) checkInInlineContext("inline match", tree.posd) val sel1 = typedExpr(tree.selector) - val selType = fullyDefinedType(sel1.tpe, "pattern selector", tree.pos).widen + val selType = fullyDefinedType(sel1.tpe, "pattern selector", tree.span).widen typedMatchFinish(tree, sel1, selType, tree.cases, pt) } } @@ -1064,7 +1064,7 @@ class Typer extends Namer val sym = b.symbol if (sym.name != tpnme.WILDCARD) if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(sym) - else ctx.error(new DuplicateBind(b, cdef), b.pos) + else ctx.error(new DuplicateBind(b, cdef), b.sourcePos) if (!ctx.isAfterTyper) { val bounds = ctx.gadt.bounds(sym) if (bounds != null) sym.info = bounds @@ -1127,14 +1127,14 @@ class Typer extends Namer def enclMethInfo(cx: Context): (Tree, Type) = { val owner = cx.owner if (owner.isType) { - ctx.error(ReturnOutsideMethodDefinition(owner), tree.pos) + ctx.error(ReturnOutsideMethodDefinition(owner), tree.sourcePos) (EmptyTree, WildcardType) } else if (owner != cx.outer.owner && owner.isRealMethod) { if (owner.isInlineMethod) - (EmptyTree, errorType(NoReturnFromInlineable(owner), tree.pos)) + (EmptyTree, errorType(NoReturnFromInlineable(owner), tree.sourcePos)) else if (!owner.isCompleted) - (EmptyTree, errorType(MissingReturnTypeWithReturnStatement(owner), tree.pos)) + (EmptyTree, errorType(MissingReturnTypeWithReturnStatement(owner), tree.sourcePos)) else { val from = Ident(TermRef(NoPrefix, owner.asTerm)) val proto = returnProto(owner, cx.scope) @@ -1154,7 +1154,7 @@ class Typer extends Namer // Hence no adaptation is possible, and we assume WildcardType as prototype. (from, proto) } - val expr1 = typedExpr(tree.expr orElse untpd.unitLiteral.withPos(tree.pos), proto) + val expr1 = typedExpr(tree.expr orElse untpd.unitLiteral.withSpan(tree.span), proto) assignType(cpy.Return(tree)(expr1, from)) } @@ -1179,7 +1179,7 @@ class Typer extends Namer def typedThrow(tree: untpd.Throw)(implicit ctx: Context): Tree = track("typedThrow") { val expr1 = typed(tree.expr, defn.ThrowableType) - Throw(expr1).withPos(tree.pos) + Throw(expr1).withSpan(tree.span) } def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(implicit ctx: Context): SeqLiteral = track("typedSeqLiteral") { @@ -1223,7 +1223,7 @@ class Typer extends Namer tree.ensureCompletions tree.getAttachment(untpd.OriginalSymbol) match { case Some(origSym) => - tree.derivedTree(origSym).withPos(tree.pos) + tree.derivedTree(origSym).withSpan(tree.span) // btw, no need to remove the attachment. The typed // tree is different from the untyped one, so the // untyped tree is no longer accessed after all @@ -1235,13 +1235,13 @@ class Typer extends Namer tree.withType( if (isFullyDefined(pt, ForceDegree.noBottom)) pt else if (ctx.reporter.errorsReported) UnspecifiedErrorType - else errorType(i"cannot infer type; expected type $pt is not fully defined", tree.pos)) + else errorType(i"cannot infer type; expected type $pt is not fully defined", tree.sourcePos)) } } def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(implicit ctx: Context): SingletonTypeTree = track("typedSingletonTypeTree") { val ref1 = typedExpr(tree.ref) - checkStable(ref1.tpe, tree.pos) + checkStable(ref1.tpe, tree.posd) assignType(cpy.SingletonTypeTree(tree)(ref1), ref1) } @@ -1260,7 +1260,7 @@ class Typer extends Namer def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(implicit ctx: Context): RefinedTypeTree = track("typedRefinedTypeTree") { val tpt1 = if (tree.tpt.isEmpty) TypeTree(defn.ObjectType) else typedAheadType(tree.tpt) - val refineClsDef = desugar.refinedTypeToClass(tpt1, tree.refinements).withPos(tree.pos) + val refineClsDef = desugar.refinedTypeToClass(tpt1, tree.refinements).withSpan(tree.span) val refineCls = createSymbol(refineClsDef).asClass val TypeDef(_, impl: Template) = typed(refineClsDef) val refinements1 = impl.body @@ -1271,11 +1271,11 @@ class Typer extends Namer checkRefinementNonCyclic(refinement, refineCls, seen) val rsym = refinement.symbol if (rsym.info.isInstanceOf[PolyType] && rsym.allOverriddenSymbols.isEmpty) - ctx.error(PolymorphicMethodMissingTypeInParent(rsym, tpt1.symbol), refinement.pos) + ctx.error(PolymorphicMethodMissingTypeInParent(rsym, tpt1.symbol), refinement.sourcePos) val member = refineCls.info.member(rsym.name) if (member.isOverloaded) { - ctx.error(OverloadInRefinement(rsym), refinement.pos) + ctx.error(OverloadInRefinement(rsym), refinement.sourcePos) } } assignType(cpy.RefinedTypeTree(tree)(tpt1, refinements1), tpt1, refinements1, refineCls) @@ -1285,14 +1285,14 @@ class Typer extends Namer val tpt1 = typed(tree.tpt, AnyTypeConstructorProto)(ctx.retractMode(Mode.Pattern)) val tparams = tpt1.tpe.typeParams if (tparams.isEmpty) { - ctx.error(TypeDoesNotTakeParameters(tpt1.tpe, tree.args), tree.pos) + ctx.error(TypeDoesNotTakeParameters(tpt1.tpe, tree.args), tree.sourcePos) tpt1 } else { var args = tree.args val args1 = { if (args.length != tparams.length) { - wrongNumberOfTypeArgs(tpt1.tpe, tparams, args, tree.pos) + wrongNumberOfTypeArgs(tpt1.tpe, tparams, args, tree.sourcePos) args = args.take(tparams.length) } def typedArg(arg: untpd.Tree, tparam: ParamInfo) = { @@ -1320,7 +1320,7 @@ class Typer extends Namer // type parameter in `C`. // The transform does not apply for patterns, where empty bounds translate to // wildcard identifiers `_` instead. - TypeTree(tparamBounds).withPos(arg.pos) + TypeTree(tparamBounds).withSpan(arg.span) case _ => typed(desugaredArg, argPt) } @@ -1384,7 +1384,7 @@ class Typer extends Namer //val ptt = if (lo.isEmpty && hi.isEmpty) pt else if (ctx.isAfterTyper) tree1 else { - val wildcardSym = ctx.newPatternBoundSymbol(tpnme.WILDCARD, tree1.tpe & pt, tree.pos) + val wildcardSym = ctx.newPatternBoundSymbol(tpnme.WILDCARD, tree1.tpe & pt, tree.span) untpd.Bind(tpnme.WILDCARD, tree1).withType(wildcardSym.typeRef) } } @@ -1392,7 +1392,7 @@ class Typer extends Namer } def typedBind(tree: untpd.Bind, pt: Type)(implicit ctx: Context): Tree = track("typedBind") { - val pt1 = fullyDefinedType(pt, "pattern variable", tree.pos) + val pt1 = fullyDefinedType(pt, "pattern variable", tree.span) val body1 = typed(tree.body, pt1) body1 match { case UnApply(fn, Nil, arg :: Nil) @@ -1401,7 +1401,7 @@ class Typer extends Namer // was rewritten to `x @ ctag(e)` by `tryWithClassTag`. // Rewrite further to `ctag(x @ e)` tpd.cpy.UnApply(body1)(fn, Nil, - typed(untpd.Bind(tree.name, untpd.TypedSplice(arg)).withPos(tree.pos), arg.tpe) :: Nil) + typed(untpd.Bind(tree.name, untpd.TypedSplice(arg)).withSpan(tree.span), arg.tpe) :: Nil) case _ => if (tree.name == nme.WILDCARD) body1 else { @@ -1410,10 +1410,10 @@ class Typer extends Namer val symTp = if (body1.tpe.isInstanceOf[TermRef]) pt1 else body1.tpe.underlyingIfRepeated(isJava = false) - val sym = ctx.newPatternBoundSymbol(tree.name, symTp, tree.pos) + val sym = ctx.newPatternBoundSymbol(tree.name, symTp, tree.span) if (pt == defn.ImplicitScrutineeTypeRef) sym.setFlag(Implicit) if (ctx.mode.is(Mode.InPatternAlternative)) - ctx.error(i"Illegal variable ${sym.name} in pattern alternative", tree.pos) + ctx.error(i"Illegal variable ${sym.name} in pattern alternative", tree.sourcePos) assignType(cpy.Bind(tree)(tree.name, body1), sym) } } @@ -1476,7 +1476,7 @@ class Typer extends Namer if (sym.is(Lazy, butNot = Deferred | Module | Synthetic) && !sym.isVolatile && ctx.scala2Mode && ctx.settings.rewrite.value.isDefined && !ctx.isAfterTyper) - patch(Position(toUntyped(vdef).pos.start), "@volatile ") + patch(Span(toUntyped(vdef).span.start), "@volatile ") } /** Adds inline to final vals with idempotent rhs @@ -1576,7 +1576,7 @@ class Typer extends Namer case cinfo: MethodType => if (!ctx.erasedTypes) { // after constructors arguments are passed in super call. typr.println(i"constr type: $cinfo") - ctx.error(ParameterizedTypeLacksArguments(psym), ref.pos) + ctx.error(ParameterizedTypeLacksArguments(psym), ref.sourcePos) } ref case _ => @@ -1589,7 +1589,7 @@ class Typer extends Namer var result = if (tree.isType) typedType(tree)(superCtx) else typedExpr(tree)(superCtx) val psym = result.tpe.dealias.typeSymbol if (seenParents.contains(psym) && !cls.isRefinementClass) { - if (!ctx.isAfterTyper) ctx.error(i"$psym is extended twice", tree.pos) + if (!ctx.isAfterTyper) ctx.error(i"$psym is extended twice", tree.sourcePos) } else seenParents += psym if (tree.isType) { @@ -1598,8 +1598,8 @@ class Typer extends Namer result = maybeCall(result, psym, psym.primaryConstructor.info) } else checkParentCall(result, cls) - checkTraitInheritance(psym, cls, tree.pos) - if (cls is Case) checkCaseInheritance(psym, cls, tree.pos) + checkTraitInheritance(psym, cls, tree.sourcePos) + if (cls is Case) checkCaseInheritance(psym, cls, tree.sourcePos) result } @@ -1614,7 +1614,7 @@ class Typer extends Namer val other = memberInSelfButNotThis(decl) if (other.exists) { val msg = CannotHaveSameNameAs(decl, other, CannotHaveSameNameAs.DefinedInSelf(self)) - ctx.error(msg, decl.pos) + ctx.error(msg, decl.sourcePos) } foundRedef || other.exists } @@ -1623,10 +1623,10 @@ class Typer extends Namer completeAnnotations(cdef, cls) val constr1 = typed(constr).asInstanceOf[DefDef] - val parentsWithClass = ensureFirstTreeIsClass(parents mapconserve typedParent, cdef.namePos) + val parentsWithClass = ensureFirstTreeIsClass(parents mapconserve typedParent, cdef.nameSpan) val parents1 = ensureConstrCall(cls, parentsWithClass)(superCtx) var self1 = typed(self)(ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible - if (cls.isOpaqueCompanion) { + if (cls.isOpaqueCompanion && !ctx.isAfterTyper) { // this is necessary to ensure selftype is correctly pickled self1 = tpd.cpy.ValDef(self1)(tpt = TypeTree(cls.classInfo.selfType)) } @@ -1642,7 +1642,7 @@ class Typer extends Namer val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1) .withType(dummy.termRef) if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) - checkRealizableBounds(cls, cdef.namePos) + checkRealizableBounds(cls, cdef.sourcePos.withSpan(cdef.nameSpan)) if (cls.is(Case) && cls.derivesFrom(defn.EnumClass)) { val firstParent = parents1.head.tpe.dealias.typeSymbol checkEnum(cdef, cls, firstParent) @@ -1658,10 +1658,10 @@ class Typer extends Namer if (reportDynamicInheritance) { val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass)) ctx.featureWarning(nme.dynamics.toString, "extension of type scala.Dynamic", isScala2Feature = true, - cls, isRequired, cdef.pos) + cls, isRequired, cdef.sourcePos) } - checkNonCyclicInherited(cls.thisType, cls.classParents, cls.info.decls, cdef.pos) + checkNonCyclicInherited(cls.thisType, cls.classParents, cls.info.decls, cdef.posd) // check value class constraints checkDerivedValueClass(cls, body1) @@ -1696,7 +1696,7 @@ class Typer extends Namer * - has C as its class symbol, and * - for all parents P_i: If P_i derives from C then P_i <:< CT. */ - def ensureFirstIsClass(parents: List[Type], pos: Position)(implicit ctx: Context): List[Type] = { + def ensureFirstIsClass(parents: List[Type], span: Span)(implicit ctx: Context): List[Type] = { def realClassParent(cls: Symbol): ClassSymbol = if (!cls.isClass) defn.ObjectClass else if (!(cls is Trait)) cls.asClass @@ -1714,14 +1714,14 @@ class Typer extends Namer val pcls = (defn.ObjectClass /: parents)(improve) typr.println(i"ensure first is class $parents%, % --> ${parents map (_ baseType pcls)}%, %") val first = ctx.typeComparer.glb(defn.ObjectType :: parents.map(_.baseType(pcls))) - checkFeasibleParent(first, pos, em" in inferred superclass $first") :: parents + checkFeasibleParent(first, ctx.source.atSpan(span), em" in inferred superclass $first") :: parents } } /** Ensure that first parent tree refers to a real class. */ - def ensureFirstTreeIsClass(parents: List[Tree], pos: Position)(implicit ctx: Context): List[Tree] = parents match { + def ensureFirstTreeIsClass(parents: List[Tree], span: Span)(implicit ctx: Context): List[Tree] = parents match { case p :: ps if p.tpe.classSymbol.isRealClass => parents - case _ => TypeTree(ensureFirstIsClass(parents.tpes, pos).head).withPos(pos.focus) :: parents + case _ => TypeTree(ensureFirstIsClass(parents.tpes, span).head).withSpan(span.focus) :: parents } /** If this is a real class, make sure its first parent is a @@ -1738,12 +1738,12 @@ class Typer extends Namer def checkVariance(tree: Tree)(implicit ctx: Context): Unit = VarianceChecker.check(tree) def localDummy(cls: ClassSymbol, impl: untpd.Template)(implicit ctx: Context): Symbol = - ctx.newLocalDummy(cls, impl.pos) + ctx.newLocalDummy(cls, impl.span) def typedImport(imp: untpd.Import, sym: Symbol)(implicit ctx: Context): Import = track("typedImport") { val expr1 = typedExpr(imp.expr, AnySelectionProto) - checkStable(expr1.tpe, imp.expr.pos) - if (!ctx.isAfterTyper) checkRealizable(expr1.tpe, imp.expr.pos) + checkStable(expr1.tpe, imp.expr.posd) + if (!ctx.isAfterTyper) checkRealizable(expr1.tpe, imp.expr.posd) assignType(cpy.Import(imp)(expr1, imp.selectors), sym) } @@ -1752,7 +1752,7 @@ class Typer extends Namer val pkg = pid1.symbol pid1 match { case pid1: RefTree if pkg.exists => - if (!pkg.is(Package)) ctx.error(PackageNameAlreadyDefined(pkg), tree.pos) + if (!pkg.is(Package)) ctx.error(PackageNameAlreadyDefined(pkg), tree.sourcePos) val packageCtx = ctx.packageContext(tree, pkg) val stats1 = typedStats(tree.stats, pkg.moduleClass)(packageCtx) cpy.PackageDef(tree)(pid1, stats1).withType(pkg.termRef) @@ -1803,11 +1803,11 @@ class Typer extends Namer case closure(_, _, _) => case _ => val recovered = typed(qual)(ctx.fresh.setExploreTyperState()) - ctx.errorOrMigrationWarning(OnlyFunctionsCanBeFollowedByUnderscore(recovered.tpe.widen), tree.pos) + ctx.errorOrMigrationWarning(OnlyFunctionsCanBeFollowedByUnderscore(recovered.tpe.widen), tree.sourcePos) if (ctx.scala2Mode) { // Under -rewrite, patch `x _` to `(() => x)` - patch(Position(tree.pos.start), "(() => ") - patch(Position(qual.pos.end, tree.pos.end), ")") + patch(Span(tree.span.start), "(() => ") + patch(Span(qual.span.end, tree.span.end), ")") return typed(untpd.Function(Nil, qual), pt) } } @@ -1824,10 +1824,10 @@ class Typer extends Namer if ((prefix ++ suffix).isEmpty) "simply leave out the trailing ` _`" else s"use `$prefix$suffix` instead" ctx.errorOrMigrationWarning(i"""The syntax ` _` is no longer supported; - |you can $remedy""", tree.pos) + |you can $remedy""", tree.sourcePos) if (ctx.scala2Mode) { - patch(Position(tree.pos.start), prefix) - patch(Position(qual.pos.end, tree.pos.end), suffix) + patch(Span(tree.span.start), prefix) + patch(Span(qual.span.end, tree.span.end), suffix) } } res @@ -1862,7 +1862,7 @@ class Typer extends Namer def typedTuple(tree: untpd.Tuple, pt: Type)(implicit ctx: Context): Tree = { val arity = tree.trees.length if (arity <= Definitions.MaxTupleArity) - typed(desugar.smallTuple(tree).withPos(tree.pos), pt) + typed(desugar.smallTuple(tree).withSpan(tree.span), pt) else { val pts = if (arity == pt.tupleArity) pt.tupleElementTypes @@ -1871,11 +1871,11 @@ class Typer extends Namer if (ctx.mode.is(Mode.Type)) (elems :\ (TypeTree(defn.UnitType): Tree))((elemTpt, elemTpts) => AppliedTypeTree(TypeTree(defn.PairType), List(elemTpt, elemTpts))) - .withPos(tree.pos) + .withSpan(tree.span) else { val tupleXXLobj = untpd.ref(defn.TupleXXLModule.termRef) val app = untpd.cpy.Apply(tree)(tupleXXLobj, elems.map(untpd.TypedSplice(_))) - .withPos(tree.pos) + .withSpan(tree.span) val app1 = typed(app, defn.TupleXXLType) if (ctx.mode.is(Mode.Pattern)) app1 else { @@ -1976,7 +1976,7 @@ class Typer extends Namer case tree: untpd.TypedSplice => typedTypedSplice(tree) case tree: untpd.UnApply => typedUnApply(tree, pt) case tree: untpd.Tuple => typedTuple(tree, pt) - case tree: untpd.DependentTypeTree => typed(untpd.TypeTree().withPos(tree.pos), pt) + case tree: untpd.DependentTypeTree => typed(untpd.TypeTree().withSpan(tree.span), pt) case tree: untpd.InfixOp if ctx.mode.isExpr => typedInfixOp(tree, pt) case tree @ untpd.PostfixOp(qual, Ident(nme.WILDCARD)) => typedAsFunction(tree, pt) case untpd.EmptyTree => tpd.EmptyTree @@ -2024,15 +2024,18 @@ class Typer extends Namer record(s"typed $getClass") record("typed total") assertPositioned(tree) - try adapt(typedUnadapted(tree, pt, locked), pt, locked) - catch { - case ex: TypeError => - errorTree(tree, ex.toMessage, tree.pos.focus) - // This uses tree.pos.focus instead of the default tree.pos, because: - // - since tree can be a top-level definition, tree.pos can point to the whole definition - // - that would in turn hide all other type errors inside tree. - // TODO: might be even better to store positions inside TypeErrors. - } + if (tree.source != ctx.source && tree.source.exists) + typed(tree, pt, locked)(ctx.withSource(tree.source)) + else + try adapt(typedUnadapted(tree, pt, locked), pt, locked) + catch { + case ex: TypeError => + errorTree(tree, ex.toMessage, tree.sourcePos.focus) + // This uses tree.span.focus instead of the default tree.span, because: + // - since tree can be a top-level definition, tree.span can point to the whole definition + // - that would in turn hide all other type errors inside tree. + // TODO: might be even better to store positions inside TypeErrors. + } } def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = @@ -2271,8 +2274,8 @@ class Typer extends Namer def missingArgs(mt: MethodType) = { val meth = methPart(tree).symbol - if (mt.paramNames.length == 0) ctx.error(MissingEmptyArgumentList(meth), tree.pos) - else ctx.error(em"missing arguments for $meth", tree.pos) + if (mt.paramNames.length == 0) ctx.error(MissingEmptyArgumentList(meth), tree.sourcePos) + else ctx.error(em"missing arguments for $meth", tree.sourcePos) tree.withType(mt.resultType) } @@ -2366,7 +2369,7 @@ class Typer extends Namer def implicitArgs(formals: List[Type], argIndex: Int): List[Tree] = formals match { case Nil => Nil case formal :: formals1 => - val arg = inferImplicitArg(formal, tree.pos.endPos) + val arg = inferImplicitArg(formal, tree.span.endPos) arg.tpe match { case failed: SearchFailureType if !failed.isInstanceOf[AmbiguousImplicits] && !tree.symbol.hasDefaultParams => @@ -2410,7 +2413,7 @@ class Typer extends Namer case failure: SearchFailureType => ctx.error( missingArgMsg(arg, formal, implicitParamString(paramName, methodStr, tree)), - tree.pos.endPos) + tree.sourcePos.endPos) case _ => } } @@ -2479,8 +2482,8 @@ class Typer extends Namer def isAutoApplied(sym: Symbol): Boolean = { sym.isConstructor || sym.matchNullaryLoosely || - ctx.testScala2Mode(MissingEmptyArgumentList(sym), tree.pos, - patch(tree.pos.endPos, "()")) + ctx.testScala2Mode(MissingEmptyArgumentList(sym), tree.sourcePos, + patch(tree.span.endPos, "()")) } // Reasons NOT to eta expand: @@ -2496,7 +2499,7 @@ class Typer extends Namer if (!defn.isFunctionType(pt)) pt match { case SAMType(_) if !pt.classSymbol.hasAnnotation(defn.FunctionalInterfaceAnnot) => - ctx.warning(ex"${tree.symbol} is eta-expanded even though $pt does not have the @FunctionalInterface annotation.", tree.pos) + ctx.warning(ex"${tree.symbol} is eta-expanded even though $pt does not have the @FunctionalInterface annotation.", tree.sourcePos) case _ => } simplify(typed(etaExpand(tree, wtp, arity), pt), pt, locked) @@ -2603,7 +2606,7 @@ class Typer extends Namer /** Adapt an expression of constant type to a different constant type `tpe`. */ def adaptConstant(tree: Tree, tpe: ConstantType): Tree = { - def lit = Literal(tpe.value).withPos(tree.pos) + def lit = Literal(tpe.value).withSpan(tree.span) tree match { case Literal(c) => lit case tree @ Block(stats, expr) => tpd.cpy.Block(tree)(stats, adaptConstant(expr, tpe)) @@ -2651,14 +2654,14 @@ class Typer extends Namer case SelectionProto(name, mbrType, _, _) => def tryExtension(implicit ctx: Context): Tree = try { - findRef(name, WildcardType, ExtensionMethod, tree.pos) match { + findRef(name, WildcardType, ExtensionMethod, tree.posd) match { case ref: TermRef => - extMethodApply(untpd.ref(ref).withPos(tree.pos), tree, mbrType) + extMethodApply(untpd.ref(ref).withSpan(tree.span), tree, mbrType) case _ => EmptyTree } } catch { - case ex: TypeError => errorTree(tree, ex.toMessage, tree.pos) + case ex: TypeError => errorTree(tree, ex.toMessage, tree.sourcePos) } val nestedCtx = ctx.fresh.setNewTyperState() val app = tryExtension(nestedCtx) @@ -2681,7 +2684,7 @@ class Typer extends Namer case SearchSuccess(inferred: ExtMethodApply, _, _) => inferred // nothing to check or adapt for extension method applications case SearchSuccess(inferred, _, _) => - checkImplicitConversionUseOK(inferred.symbol, tree.pos) + checkImplicitConversionUseOK(inferred.symbol, tree.posd) readapt(inferred)(ctx.retractMode(Mode.ImplicitsEnabled)) case failure: SearchFailure => if (pt.isInstanceOf[ProtoType] && !failure.isAmbiguous) @@ -2721,7 +2724,7 @@ class Typer extends Namer * tree that went unreported. A scenario where this happens is i1802.scala. */ def ensureReported(tp: Type) = tp match { - case err: ErrorType if !ctx.reporter.errorsReported => ctx.error(err.msg, tree.pos) + case err: ErrorType if !ctx.reporter.errorsReported => ctx.error(err.msg, tree.sourcePos) case _ => } @@ -2792,6 +2795,6 @@ class Typer extends Namer private def checkStatementPurity(tree: tpd.Tree)(original: untpd.Tree, exprOwner: Symbol)(implicit ctx: Context): Unit = { if (!ctx.isAfterTyper && isPureExpr(tree) && !tree.tpe.isRef(defn.UnitClass) && !isSelfOrSuperConstrCall(tree)) - ctx.warning(PureExpressionInStatementPosition(original, exprOwner), original.pos) + ctx.warning(PureExpressionInStatementPosition(original, exprOwner), original.sourcePos) } } diff --git a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala index fe59723ed3c0..76be55f9cc9d 100644 --- a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala +++ b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala @@ -8,7 +8,8 @@ import Decorators._ import Variances._ import NameKinds._ import TypeApplications.varianceConforms -import util.Positions._ +import util.Spans._ +import util.SourcePosition import config.Printers.variances import reporting.trace @@ -38,8 +39,8 @@ object VarianceChecker { } val pos = tree.tparams .find(_.name.toTermName == paramName) - .map(_.pos) - .getOrElse(tree.pos) + .map(_.sourcePos) + .getOrElse(tree.sourcePos) ctx.error(em"${paramVarianceStr}variant type parameter $paramName occurs in ${occursStr}variant position in ${tl.resType}", pos) } def apply(x: Boolean, t: Type) = x && { @@ -151,13 +152,15 @@ class VarianceChecker()(implicit ctx: Context) { } private object Traverser extends TreeTraverser { - def checkVariance(sym: Symbol, pos: Position) = Validator.validateDefinition(sym) match { + def checkVariance(sym: Symbol, pos: SourcePosition) = Validator.validateDefinition(sym) match { case Some(VarianceError(tvar, required)) => def msg = i"${varianceString(tvar.flags)} $tvar occurs in ${varianceString(required)} position in type ${sym.info} of $sym" if (ctx.scala2Mode && (sym.owner.isConstructor || sym.ownersIterator.exists(_.is(ProtectedLocal)))) { - ctx.migrationWarning(s"According to new variance rules, this is no longer accepted; need to annotate with @uncheckedVariance:\n$msg", pos) - // patch(Position(pos.end), " @scala.annotation.unchecked.uncheckedVariance") + ctx.migrationWarning( + s"According to new variance rules, this is no longer accepted; need to annotate with @uncheckedVariance:\n$msg", + pos) + // patch(Span(pos.end), " @scala.annotation.unchecked.uncheckedVariance") // Patch is disabled until two TODOs are solved: // TODO use an import or shorten if possible // TODO need to use a `:' if annotation is on term @@ -178,15 +181,15 @@ 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.pos) + checkVariance(sym, tree.sourcePos) tree.rhs match { case rhs: Template => traverseChildren(rhs) case _ => } case tree: ValDef => - checkVariance(sym, tree.pos) + checkVariance(sym, tree.sourcePos) case DefDef(_, tparams, vparamss, _, _) => - checkVariance(sym, tree.pos) + checkVariance(sym, tree.sourcePos) tparams foreach traverse vparamss foreach (_ foreach traverse) case _ => diff --git a/compiler/src/dotty/tools/dotc/util/Positions.scala b/compiler/src/dotty/tools/dotc/util/Positions.scala deleted file mode 100644 index 1e6814d7caf4..000000000000 --- a/compiler/src/dotty/tools/dotc/util/Positions.scala +++ /dev/null @@ -1,176 +0,0 @@ -package dotty.tools.dotc -package util -import language.implicitConversions - -/** Position format in little endian: - * Start: unsigned 26 Bits (works for source files up to 64M) - * End: unsigned 26 Bits - * Point: unsigned 12 Bits relative to start - * NoPosition encoded as -1L (this is a normally invalid position - * because point would lie beyond end. - */ -object Positions { - - private final val StartEndBits = 26 - private final val StartEndMask = (1L << StartEndBits) - 1 - private final val SyntheticPointDelta = (1 << (64 - StartEndBits * 2)) - 1 - - /** The maximal representable offset in a position */ - private final val MaxOffset = StartEndMask - - /** Convert offset `x` to an integer by sign extending the original - * field of `StartEndBits` width. - */ - def offsetToInt(x: Int): Int = - x << (32 - StartEndBits) >> (32 - StartEndBits) - - /** A position indicates a range between a start offset and an end offset. - * Positions can be synthetic or source-derived. A source-derived position - * has in addition a point lies somewhere between start and end. The point - * is roughly where the ^ would go if an error was diagnosed at that position. - * All quantities are encoded opaquely in a Long. - */ - class Position(val coords: Long) extends AnyVal { - - /** Is this position different from NoPosition? */ - def exists: Boolean = this != NoPosition - - /** The start of this position. */ - def start: Int = { - assert(exists) - (coords & StartEndMask).toInt - } - - /** The end of this position */ - def end: Int = { - assert(exists) - ((coords >>> StartEndBits) & StartEndMask).toInt - } - - /** The point of this position, returns start for synthetic positions */ - def point: Int = { - assert(exists) - val poff = pointDelta - if (poff == SyntheticPointDelta) start else start + poff - } - - /** The difference between point and start in this position */ - def pointDelta: Int = - (coords >>> (StartEndBits * 2)).toInt - - def orElse(that: Position): Position = - if (this.exists) this else that - - /** The union of two positions. This is the least range that encloses - * both positions. It is always a synthetic position. - */ - def union(that: Position): Position = - if (!this.exists) that - else if (!that.exists) this - else Position(this.start min that.start, this.end max that.end, this.point) - - /** Does the range of this position contain the one of that position? */ - def contains(that: Position): Boolean = - !that.exists || exists && (start <= that.start && end >= that.end) - - /** Is this position synthetic? */ - def isSynthetic: Boolean = pointDelta == SyntheticPointDelta - - /** Is this position source-derived? */ - def isSourceDerived: Boolean = !isSynthetic - - /** Is this a zero-extent position? */ - def isZeroExtent: Boolean = start == end - - /** A position where all components are shifted by a given `offset` - * relative to this position. - */ - def shift(offset: Int): Position = - if (exists) fromOffsets(start + offset, end + offset, pointDelta) - else this - - /** The zero-extent position with start and end at the point of this position */ - def focus: Position = if (exists) Position(point) else NoPosition - - /** The zero-extent position with start and end at the start of this position */ - def startPos: Position = if (exists) Position(start) else NoPosition - - /** The zero-extent position with start and end at the end of this position */ - def endPos: Position = if (exists) Position(end) else NoPosition - - /** A copy of this position with a different start */ - def withStart(start: Int): Position = - if (exists) fromOffsets(start, this.end, if (isSynthetic) SyntheticPointDelta else this.point - start) - else this - - /** A copy of this position with a different end */ - def withEnd(end: Int): Position = - if (exists) fromOffsets(this.start, end, pointDelta) - else this - - /** A copy of this position with a different point */ - def withPoint(point: Int): Position = - if (exists) fromOffsets(this.start, this.end, point - this.start) - else this - - /** A synthetic copy of this position */ - def toSynthetic: Position = if (isSynthetic) this else Position(start, end) - - override def toString: String = { - val (left, right) = if (isSynthetic) ("<", ">") else ("[", "]") - if (exists) - s"$left$start..${if (point == start) "" else s"$point.."}$end$right" - else - s"${left}no position${right}" - } - } - - private def fromOffsets(start: Int, end: Int, pointDelta: Int) = { - //assert(start <= end || start == 1 && end == 0, s"$start..$end") - new Position( - (start & StartEndMask).toLong | - ((end & StartEndMask).toLong << StartEndBits) | - (pointDelta.toLong << (StartEndBits * 2))) - } - - /** A synthetic position with given start and end */ - def Position(start: Int, end: Int): Position = - fromOffsets(start, end, SyntheticPointDelta) - - /** A source-derived position with given start, end, and point delta */ - def Position(start: Int, end: Int, point: Int): Position = { - val pointDelta = (point - start) max 0 - fromOffsets(start, end, if (pointDelta >= SyntheticPointDelta) 0 else pointDelta) - } - - /** A synthetic zero-extent position that starts and ends at given `start`. */ - def Position(start: Int): Position = Position(start, start) - - /** A sentinel for a non-existing position */ - val NoPosition: Position = Position(1, 0) - - /** The coordinate of a symbol. This is either an index or - * a zero-range position. - */ - class Coord(val encoding: Int) extends AnyVal { - def isIndex: Boolean = encoding > 0 - def isPosition: Boolean = encoding <= 0 - def toIndex: Int = { - assert(isIndex) - encoding - 1 - } - def toPosition: Position = { - assert(isPosition) - if (this == NoCoord) NoPosition else Position(-1 - encoding) - } - } - - /** An index coordinate */ - implicit def indexCoord(n: Int): Coord = new Coord(n + 1) - implicit def positionCoord(pos: Position): Coord = - if (pos.exists) new Coord(-(pos.point + 1)) - else NoCoord - - /** A sentinel for a missing coordinate */ - val NoCoord: Coord = new Coord(0) -} diff --git a/compiler/src/dotty/tools/dotc/util/Signatures.scala b/compiler/src/dotty/tools/dotc/util/Signatures.scala index 4c44d337cbf3..14dcddcb77dd 100644 --- a/compiler/src/dotty/tools/dotc/util/Signatures.scala +++ b/compiler/src/dotty/tools/dotc/util/Signatures.scala @@ -7,7 +7,7 @@ import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.Denotations.SingleDenotation import dotty.tools.dotc.core.Flags.Implicit import dotty.tools.dotc.core.Names.TermName -import dotty.tools.dotc.util.Positions.Position +import dotty.tools.dotc.util.Spans.Span import dotty.tools.dotc.core.Types.{ErrorType, MethodType, PolyType} import dotty.tools.dotc.reporting.diagnostic.messages @@ -44,15 +44,15 @@ object Signatures { * Extract (current parameter index, function index, functions) out of a method call. * * @param path The path to the function application - * @param pos The position of the cursor + * @param span The position of the cursor * @return A triple containing the index of the parameter being edited, the index of the function * being called, the list of overloads of this function). */ - def callInfo(path: List[tpd.Tree], pos: Position)(implicit ctx: Context): (Int, Int, List[SingleDenotation]) = { + def callInfo(path: List[tpd.Tree], span: Span)(implicit ctx: Context): (Int, Int, List[SingleDenotation]) = { path match { case Apply(fun, params) :: _ => val alreadyAppliedCount = Signatures.countParams(fun) - val paramIndex = params.indexWhere(_.pos.contains(pos)) match { + val paramIndex = params.indexWhere(_.span.contains(span)) match { case -1 => (params.length - 1 max 0) + alreadyAppliedCount case n => n + alreadyAppliedCount } @@ -170,7 +170,7 @@ object Signatures { // `null` parameter: `foo(bar, null)`. This may influence what's the "best" // alternative, so we discard it. val userParams = params match { - case xs :+ (nul @ Literal(Constant(null))) if nul.pos.isZeroExtent => xs + case xs :+ (nul @ Literal(Constant(null))) if nul.span.isZeroExtent => xs case _ => params } val userParamsTypes = userParams.map(_.tpe) diff --git a/compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala b/compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala index d609b889497f..ad0ec87067c5 100644 --- a/compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala +++ b/compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala @@ -160,8 +160,8 @@ object SimpleIdentityMap { m } else { val bindings1 = new Array[AnyRef](bindings.length - 2) - Array.copy(bindings, 0, bindings1, 0, i) - Array.copy(bindings, i + 2, bindings1, i, bindings1.length - i) + System.arraycopy(bindings, 0, bindings1, 0, i) + System.arraycopy(bindings, i + 2, bindings1, i, bindings1.length - i) new MapMore(bindings1) } } @@ -185,7 +185,7 @@ object SimpleIdentityMap { i += 2 } val bindings2 = new Array[AnyRef](bindings.length + 2) - Array.copy(bindings, 0, bindings2, 0, bindings.length) + System.arraycopy(bindings, 0, bindings2, 0, bindings.length) bindings2(bindings.length) = k bindings2(bindings.length + 1) = v new MapMore(bindings2) diff --git a/compiler/src/dotty/tools/dotc/util/SimpleIdentitySet.scala b/compiler/src/dotty/tools/dotc/util/SimpleIdentitySet.scala index 1d4b4d0a3b1b..42dd3a7bf42d 100644 --- a/compiler/src/dotty/tools/dotc/util/SimpleIdentitySet.scala +++ b/compiler/src/dotty/tools/dotc/util/SimpleIdentitySet.scala @@ -83,7 +83,7 @@ object SimpleIdentitySet { def size = xs.length def + [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[E] = { val xs1 = new Array[AnyRef](size + 1) - Array.copy(xs, 0, xs1, 0, size) + System.arraycopy(xs, 0, xs1, 0, size) xs1(size) = x new SetN[E](xs1) } @@ -98,8 +98,8 @@ object SimpleIdentitySet { else new Set3(xs(0), xs(1), xs(2)) else { val xs1 = new Array[AnyRef](size - 1) - Array.copy(xs, 0, xs1, 0, i) - Array.copy(xs, i + 1, xs1, i, size - (i + 1)) + System.arraycopy(xs, 0, xs1, 0, i) + System.arraycopy(xs, i + 1, xs1, i, size - (i + 1)) new SetN(xs1) } } diff --git a/compiler/src/dotty/tools/dotc/util/SourceFile.scala b/compiler/src/dotty/tools/dotc/util/SourceFile.scala index d200fae54df3..07d3e886142c 100644 --- a/compiler/src/dotty/tools/dotc/util/SourceFile.scala +++ b/compiler/src/dotty/tools/dotc/util/SourceFile.scala @@ -7,9 +7,14 @@ import dotty.tools.io._ import java.util.regex.Pattern import java.io.IOException import scala.tasty.util.Chars._ -import Positions._ +import Spans._ import scala.io.Codec +import core.Names.TermName +import core.Contexts.Context import scala.annotation.internal.sharable +import core.Decorators.PreNamedString +import java.util.concurrent.atomic.AtomicInteger +import scala.collection.mutable import java.util.Optional @@ -34,10 +39,17 @@ object ScriptSourceFile { } } -case class SourceFile(file: AbstractFile, content: Array[Char]) extends interfaces.SourceFile { +class SourceFile(val file: AbstractFile, computeContent: => Array[Char]) extends interfaces.SourceFile { + import SourceFile._ + + private var myContent: Array[Char] = null + + def content(): Array[Char] = { + if (myContent == null) myContent = computeContent + myContent + } def this(file: AbstractFile, codec: Codec) = this(file, new String(file.toByteArray, codec.charSet).toCharArray) - def this(name: String, content: String) = this(new VirtualFile(name), content.toCharArray) /** Tab increment; can be overridden */ def tabInc: Int = 8 @@ -46,15 +58,21 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) extends interfac override def path: String = file.path override def jfile: Optional[JFile] = Optional.ofNullable(file.file) - override def equals(that : Any): Boolean = that match { - case that : SourceFile => file.path == that.file.path && start == that.start - case _ => false - } - override def hashCode: Int = file.path.## + start.## + def pathName: PathName = file.absolutePath.toTermName + + override def equals(that: Any): Boolean = + (this `eq` that.asInstanceOf[AnyRef]) || { + that match { + case that : SourceFile => file == that.file && start == that.start + case _ => false + } + } - def apply(idx: Int): Char = content.apply(idx) + override def hashCode: Int = file.hashCode * 41 + start.hashCode - val length: Int = content.length + def apply(idx: Int): Char = content().apply(idx) + + def length: Int = content().length /** true for all source files except `NoSource` */ def exists: Boolean = true @@ -65,8 +83,8 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) extends interfac /** The start of this file in the underlying source file */ def start: Int = 0 - def atPos(pos: Position): SourcePosition = - if (pos.exists) SourcePosition(underlying, pos) + def atSpan(span: Span): SourcePosition = + if (span.exists) SourcePosition(underlying, span) else NoSourcePosition def isSelfContained: Boolean = underlying eq this @@ -75,13 +93,13 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) extends interfac * For regular source files, simply return the argument. */ def positionInUltimateSource(position: SourcePosition): SourcePosition = - SourcePosition(underlying, position.pos shift start) + SourcePosition(underlying, position.span shift start) private def isLineBreak(idx: Int) = if (idx >= length) false else { - val ch = content(idx) + val ch = content()(idx) // don't identify the CR in CR LF as a line break, since LF will do. - if (ch == CR) (idx + 1 == length) || (content(idx + 1) != LF) + if (ch == CR) (idx + 1 == length) || (content()(idx + 1) != LF) else isLineBreakChar(ch) } @@ -92,7 +110,7 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) extends interfac buf += cs.length // sentinel, so that findLine below works smoother buf.toArray } - private lazy val lineIndices: Array[Int] = calculateLineIndices(content) + private lazy val lineIndices: Array[Int] = calculateLineIndices(content()) /** Map line to offset of first character in line */ def lineToOffset(index: Int): Int = lineIndices(index) @@ -128,7 +146,7 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) extends interfac var idx = startOfLine(offset) var col = 0 while (idx != offset) { - col += (if (idx < length && content(idx) == '\t') (tabInc - col) % tabInc else 1) + col += (if (idx < length && content()(idx) == '\t') (tabInc - col) % tabInc else 1) idx += 1 } col @@ -139,17 +157,59 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) extends interfac var idx = startOfLine(offset) val pad = new StringBuilder while (idx != offset) { - pad.append(if (idx < length && content(idx) == '\t') '\t' else ' ') + pad.append(if (idx < length && content()(idx) == '\t') '\t' else ' ') idx += 1 } pad.result() } override def toString: String = file.toString + + // Positioned ids + + private[this] val ctr = new AtomicInteger + + def nextId: Int = { + val id = ctr.get + if (id % ChunkSize == 0) newChunk + else if (ctr.compareAndSet(id, id + 1)) id + else nextId + } + + private def newChunk: Int = sourceOfChunk.synchronized { + val id = chunks << ChunkSizeLog + if (chunks == sourceOfChunk.length) { + val a = new Array[SourceFile](chunks * 2) + System.arraycopy(sourceOfChunk, 0, a, 0, chunks) + sourceOfChunk = a + } + sourceOfChunk(chunks) = this + chunks += 1 + ctr.set(id + 1) + id + } +} +object SourceFile { + implicit def eqSource: Eq[SourceFile, SourceFile] = Eq + + implicit def fromContext(implicit ctx: Context): SourceFile = ctx.source + + type PathName = TermName + + def fromId(id: Int): SourceFile = sourceOfChunk(id >> ChunkSizeLog) + + def virtual(name: String, content: String) = new SourceFile(new VirtualFile(name, content.getBytes), scala.io.Codec.UTF8) + + private final val ChunkSizeLog = 10 + private final val ChunkSize = 1 << ChunkSizeLog + + // These two vars are sharable because they're only used in the synchronized block in newChunk + @sharable private var chunks: Int = 0 + @sharable private var sourceOfChunk: Array[SourceFile] = new Array[SourceFile](2000) } -@sharable object NoSource extends SourceFile("", "") { +@sharable object NoSource extends SourceFile(NoAbstractFile, Array[Char]()) { override def exists: Boolean = false - override def atPos(pos: Position): SourcePosition = NoSourcePosition + override def atSpan(span: Span): SourcePosition = NoSourcePosition } diff --git a/compiler/src/dotty/tools/dotc/util/SourcePosition.scala b/compiler/src/dotty/tools/dotc/util/SourcePosition.scala index 2731551c501a..257d3ca42553 100644 --- a/compiler/src/dotty/tools/dotc/util/SourcePosition.scala +++ b/compiler/src/dotty/tools/dotc/util/SourcePosition.scala @@ -4,23 +4,23 @@ package util import printing.{Showable, Printer} import printing.Texts._ -import Positions.{Position, NoPosition} - +import Spans.{Span, NoSpan} import scala.annotation.internal.sharable -/** A source position is comprised of a position in a source file */ -case class SourcePosition(source: SourceFile, pos: Position, outer: SourcePosition = NoSourcePosition) +/** A source position is comprised of a span and a source file */ +case class SourcePosition(source: SourceFile, span: Span, outer: SourcePosition = NoSourcePosition) extends interfaces.SourcePosition with Showable { + /** Is `that` a source position contained in this source position ? * `outer` is not taken into account. */ def contains(that: SourcePosition): Boolean = - this.source == that.source && this.pos.contains(that.pos) + this.source == that.source && this.span.contains(that.span) - def exists: Boolean = pos.exists + def exists: Boolean = span.exists def lineContent: String = source.lineContent(point) - def point: Int = pos.point + def point: Int = span.point /** The line of the position, starting at 0 */ def line: Int = source.offsetToLine(point) @@ -46,25 +46,31 @@ extends interfaces.SourcePosition with Showable { /** The column of the position, starting at 0 */ def column: Int = source.column(point) - def start: Int = pos.start + def start: Int = span.start def startLine: Int = source.offsetToLine(start) def startColumn: Int = source.column(start) def startColumnPadding: String = source.startColumnPadding(start) - def end: Int = pos.end + def end: Int = span.end def endLine: Int = source.offsetToLine(end) def endColumn: Int = source.column(end) - def withOuter(outer: SourcePosition): SourcePosition = new SourcePosition(source, pos, outer) + def withOuter(outer: SourcePosition): SourcePosition = SourcePosition(source, span, outer) + def withSpan(range: Span) = SourcePosition(source, range, outer) + + def startPos: SourcePosition = withSpan(span.startPos) + def endPos : SourcePosition = withSpan(span.endPos) + def focus : SourcePosition = withSpan(span.focus) + def toSynthetic: SourcePosition = withSpan(span.toSynthetic) override def toString: String = - s"${if (source.exists) source.file.toString else "(no source)"}:$pos" + s"${if (source.exists) source.file.toString else "(no source)"}:$span" def toText(printer: Printer): Text = printer.toText(this) } /** A sentinel for a non-existing source position */ -@sharable object NoSourcePosition extends SourcePosition(NoSource, NoPosition) { +@sharable object NoSourcePosition extends SourcePosition(NoSource, NoSpan) { override def toString: String = "?" override def withOuter(outer: SourcePosition): SourcePosition = outer } diff --git a/compiler/src/dotty/tools/dotc/util/Spans.scala b/compiler/src/dotty/tools/dotc/util/Spans.scala new file mode 100644 index 000000000000..1672d3468fa1 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/util/Spans.scala @@ -0,0 +1,180 @@ +package dotty.tools.dotc +package util +import language.implicitConversions + +/** The offsets part of a full position, consisting of 2 or 3 entries: + * - start: the start offset of the span, in characters from start of file + * - end : the end offset of the span + * - point: if given, the offset where a sing;le `^` would be logically placed + * + & Spans are encoded according to the following format in little endian: + * Start: unsigned 26 Bits (works for source files up to 64M) + * End: unsigned 26 Bits + * Point: unsigned 12 Bits relative to start + * NoSpan encoded as -1L (this is a normally invalid span because point would lie beyond end). + */ +object Spans { + + private final val StartEndBits = 26 + private final val StartEndMask = (1L << StartEndBits) - 1 + private final val SyntheticPointDelta = (1 << (64 - StartEndBits * 2)) - 1 + + /** The maximal representable offset in a span */ + final val MaxOffset = StartEndMask.toInt + + /** Convert offset `x` to an integer by sign extending the original + * field of `StartEndBits` width. + */ + def offsetToInt(x: Int): Int = + x << (32 - StartEndBits) >> (32 - StartEndBits) + + /** A span indicates a range between a start offset and an end offset. + * Spans can be synthetic or source-derived. A source-derived span + * has in addition a point lies somewhere between start and end. The point + * is roughly where the ^ would go if an error was diagnosed at that position. + * All quantities are encoded opaquely in a Long. + */ + class Span(val coords: Long) extends AnyVal { + + /** Is this span different from NoSpan? */ + def exists: Boolean = this != NoSpan + + /** The start of this span. */ + def start: Int = { + assert(exists) + (coords & StartEndMask).toInt + } + + /** The end of this span */ + def end: Int = { + assert(exists) + ((coords >>> StartEndBits) & StartEndMask).toInt + } + + /** The point of this span, returns start for synthetic spans */ + def point: Int = { + assert(exists) + val poff = pointDelta + if (poff == SyntheticPointDelta) start else start + poff + } + + /** The difference between point and start in this span */ + def pointDelta: Int = + (coords >>> (StartEndBits * 2)).toInt + + def orElse(that: Span): Span = + if (this.exists) this else that + + /** The union of two spans. This is the least range that encloses + * both spans. It is always a synthetic span. + */ + def union(that: Span): Span = + if (!this.exists) that + else if (!that.exists) this + else Span(this.start min that.start, this.end max that.end, this.point) + + /** Does the range of this span contain the one of that span? */ + def contains(that: Span): Boolean = + !that.exists || exists && (start <= that.start && end >= that.end) + + /** Is this span synthetic? */ + def isSynthetic: Boolean = pointDelta == SyntheticPointDelta + + /** Is this span source-derived? */ + def isSourceDerived: Boolean = !isSynthetic + + /** Is this a zero-extent span? */ + def isZeroExtent: Boolean = start == end + + /** A span where all components are shifted by a given `offset` + * relative to this span. + */ + def shift(offset: Int): Span = + if (exists) fromOffsets(start + offset, end + offset, pointDelta) + else this + + /** The zero-extent span with start and end at the point of this span */ + def focus: Span = if (exists) Span(point) else NoSpan + + /** The zero-extent span with start and end at the start of this span */ + def startPos: Span = if (exists) Span(start) else NoSpan + + /** The zero-extent span with start and end at the end of this span */ + def endPos: Span = if (exists) Span(end) else NoSpan + + /** A copy of this span with a different start */ + def withStart(start: Int): Span = + if (exists) fromOffsets(start, this.end, if (isSynthetic) SyntheticPointDelta else this.point - start) + else this + + /** A copy of this span with a different end */ + def withEnd(end: Int): Span = + if (exists) fromOffsets(this.start, end, pointDelta) + else this + + /** A copy of this span with a different point */ + def withPoint(point: Int): Span = + if (exists) fromOffsets(this.start, this.end, point - this.start) + else this + + /** A synthetic copy of this span */ + def toSynthetic: Span = if (isSynthetic) this else Span(start, end) + + override def toString: String = { + val (left, right) = if (isSynthetic) ("<", ">") else ("[", "]") + if (exists) + s"$left$start..${if (point == start) "" else s"$point.."}$end$right" + else + s"${left}no position${right}" + } + } + + private def fromOffsets(start: Int, end: Int, pointDelta: Int) = { + //assert(start <= end || start == 1 && end == 0, s"$start..$end") + new Span( + (start & StartEndMask).toLong | + ((end & StartEndMask).toLong << StartEndBits) | + (pointDelta.toLong << (StartEndBits * 2))) + } + + /** A synthetic span with given start and end */ + def Span(start: Int, end: Int): Span = + fromOffsets(start, end, SyntheticPointDelta) + + /** A source-derived span with given start, end, and point delta */ + def Span(start: Int, end: Int, point: Int): Span = { + val pointDelta = (point - start) max 0 + fromOffsets(start, end, if (pointDelta >= SyntheticPointDelta) 0 else pointDelta) + } + + /** A synthetic zero-extent span that starts and ends at given `start`. */ + def Span(start: Int): Span = Span(start, start) + + /** A sentinel for a non-existing span */ + val NoSpan: Span = Span(1, 0) + + /** The coordinate of a symbol. This is either an index or + * a zero-range span. + */ + class Coord(val encoding: Int) extends AnyVal { + def isIndex: Boolean = encoding > 0 + def isSpan: Boolean = encoding <= 0 + def toIndex: Int = { + assert(isIndex) + encoding - 1 + } + def toSpan: Span = { + assert(isSpan) + if (this == NoCoord) NoSpan else Span(-1 - encoding) + } + } + + /** An index coordinate */ + implicit def indexCoord(n: Int): Coord = new Coord(n + 1) + implicit def spanCoord(span: Span): Coord = + if (span.exists) new Coord(-(span.point + 1)) + else NoCoord + + /** A sentinel for a missing coordinate */ + val NoCoord: Coord = new Coord(0) +} diff --git a/compiler/src/dotty/tools/dotc/util/Util.scala b/compiler/src/dotty/tools/dotc/util/Util.scala index ffb40caf5292..bf34ff0157ed 100644 --- a/compiler/src/dotty/tools/dotc/util/Util.scala +++ b/compiler/src/dotty/tools/dotc/util/Util.scala @@ -26,7 +26,7 @@ object Util { /** An array twice the size of given array, with existing elements copied over */ def dble[T: ClassTag](arr: Array[T]): Array[T] = { val arr1 = new Array[T](arr.length * 2) - Array.copy(arr, 0, arr1, 0, arr.length) + System.arraycopy(arr, 0, arr1, 0, arr.length) arr1 } } diff --git a/compiler/src/dotty/tools/io/AbstractFile.scala b/compiler/src/dotty/tools/io/AbstractFile.scala index 6d893a275bbc..67bd964ecc3d 100644 --- a/compiler/src/dotty/tools/io/AbstractFile.scala +++ b/compiler/src/dotty/tools/io/AbstractFile.scala @@ -89,6 +89,9 @@ abstract class AbstractFile extends Iterable[AbstractFile] { /** Returns the path of this abstract file. */ def path: String + /** Returns the absolute path of this abstract file. */ + def absolutePath: String = path + /** Returns the path of this abstract file in a canonical form. */ def canonicalPath: String = if (jpath == null) path else jpath.normalize.toString diff --git a/compiler/src/dotty/tools/io/PlainFile.scala b/compiler/src/dotty/tools/io/PlainFile.scala index f5bde26722fc..7ee263729e5b 100644 --- a/compiler/src/dotty/tools/io/PlainFile.scala +++ b/compiler/src/dotty/tools/io/PlainFile.scala @@ -22,10 +22,11 @@ class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) { class PlainFile(val givenPath: Path) extends AbstractFile { assert(path ne null) + dotc.util.Stats.record("new PlainFile") + def jpath: JPath = givenPath.jpath override def underlyingSource: Some[PlainFile] = Some(this) - private val fpath = givenPath.toAbsolute /** Returns the name of this abstract file. */ def name: String = givenPath.name @@ -33,6 +34,9 @@ class PlainFile(val givenPath: Path) extends AbstractFile { /** Returns the path of this abstract file. */ def path: String = givenPath.path + /** Returns the absolute path of this abstract file as an interned string. */ + override val absolutePath: String = givenPath.toAbsolute.toString.intern + /** The absolute file. */ def absolute: PlainFile = new PlainFile(givenPath.toAbsolute) @@ -41,9 +45,9 @@ class PlainFile(val givenPath: Path) extends AbstractFile { override def output: OutputStream = givenPath.toFile.outputStream() override def sizeOption: Option[Int] = Some(givenPath.length.toInt) - override def hashCode(): Int = fpath.hashCode() + override def hashCode(): Int = System.identityHashCode(absolutePath) override def equals(that: Any): Boolean = that match { - case x: PlainFile => fpath == x.fpath + case x: PlainFile => absolutePath `eq` x.absolutePath case _ => false } diff --git a/compiler/src/dotty/tools/io/VirtualFile.scala b/compiler/src/dotty/tools/io/VirtualFile.scala index 8206e50baaf2..5cd1bde187fb 100644 --- a/compiler/src/dotty/tools/io/VirtualFile.scala +++ b/compiler/src/dotty/tools/io/VirtualFile.scala @@ -15,6 +15,7 @@ import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, InputStream, Outpu * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class VirtualFile(val name: String, override val path: String) extends AbstractFile { + /** * Initializes this instance with the specified name and an * identical path. @@ -24,10 +25,17 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF */ def this(name: String) = this(name, name) - override def hashCode: Int = path.hashCode - override def equals(that: Any): Boolean = that match { - case x: VirtualFile => x.path == path - case _ => false + /** + * Initializes this instance with the specified name and an + * identical path. + * + * @param name the name of the virtual file to be created + * @param content the initial contents of the virtual file + * @return the created virtual file + */ + def this(name: String, content: Array[Byte]) = { + this(name) + this.content = content } private[this] var content = Array.emptyByteArray diff --git a/compiler/src/dotty/tools/repl/JLineTerminal.scala b/compiler/src/dotty/tools/repl/JLineTerminal.scala index 7868eacf4831..3376714e5bee 100644 --- a/compiler/src/dotty/tools/repl/JLineTerminal.scala +++ b/compiler/src/dotty/tools/repl/JLineTerminal.scala @@ -110,7 +110,7 @@ final class JLineTerminal extends java.io.Closeable { case class TokenData(token: Token, start: Int, end: Int) def currentToken: TokenData /* | Null */ = { - val source = new SourceFile("", input) + val source = SourceFile.virtual("", input) val scanner = new Scanner(source)(ctx.fresh.setReporter(Reporter.NoReporter)) while (scanner.token != EOF) { val start = scanner.offset diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index 9d5c89980f53..8bfb3864dff7 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -7,7 +7,7 @@ import dotc.parsing.Parsers.Parser import dotc.parsing.Tokens import dotc.util.SourceFile import dotc.ast.untpd - +import dotty.tools.dotc.core.StdNames.str import scala.annotation.internal.sharable @@ -15,7 +15,7 @@ import scala.annotation.internal.sharable sealed trait ParseResult /** An error free parsing resulting in a list of untyped trees */ -case class Parsed(sourceCode: String, trees: List[untpd.Tree]) extends ParseResult +case class Parsed(source: SourceFile, trees: List[untpd.Tree]) extends ParseResult /** A parsing result containing syntax `errors` */ case class SyntaxErrors(sourceCode: String, @@ -109,15 +109,14 @@ object ParseResult { @sharable private[this] val CommandExtract = """(:[\S]+)\s*(.*)""".r private def parseStats(sourceCode: String)(implicit ctx: Context): List[untpd.Tree] = { - val source = new SourceFile("", sourceCode) - val parser = new Parser(source) + val parser = new Parser(ctx.source) val stats = parser.blockStatSeq() parser.accept(Tokens.EOF) stats } /** Extract a `ParseResult` from the string `sourceCode` */ - def apply(sourceCode: String)(implicit ctx: Context): ParseResult = + def apply(sourceCode: String)(implicit state: State): ParseResult = sourceCode match { case "" => Newline case CommandExtract(cmd, arg) => cmd match { @@ -131,8 +130,12 @@ object ParseResult { case _ => UnknownCommand(cmd) } case _ => + implicit val ctx: Context = state.context + + val source = SourceFile.virtual(str.REPL_SESSION_LINE + (state.objectIndex + 1), sourceCode) + val reporter = newStoreReporter - val stats = parseStats(sourceCode)(ctx.fresh.setReporter(reporter)) + val stats = parseStats(sourceCode)(state.context.fresh.setReporter(reporter).withSource(source)) if (reporter.hasErrors) SyntaxErrors( @@ -140,7 +143,7 @@ object ParseResult { reporter.removeBufferedMessages, stats) else - Parsed(sourceCode, stats) + Parsed(source, stats) } /** Check if the input is incomplete diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index 819043fb458b..6093f91d277e 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -14,7 +14,7 @@ import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.reporting.diagnostic.messages import dotty.tools.dotc.transform.PostTyper import dotty.tools.dotc.typer.ImportInfo -import dotty.tools.dotc.util.Positions._ +import dotty.tools.dotc.util.Spans._ import dotty.tools.dotc.util.{ParsedComment, SourceFile} import dotty.tools.dotc.{CompilationUnit, Compiler, Run} import dotty.tools.repl.results._ @@ -64,9 +64,6 @@ class ReplCompiler extends Compiler { } private[this] val objectNames = mutable.Map.empty[Int, TermName] - private def objectName(state: State) = - objectNames.getOrElseUpdate(state.objectIndex, - (str.REPL_SESSION_LINE + state.objectIndex).toTermName) private case class Definitions(stats: List[untpd.Tree], state: State) @@ -92,12 +89,12 @@ class ReplCompiler extends Compiler { // special case simple reassignment (e.g. x = 3) // in order to print the new value in the REPL val assignName = (id.name ++ str.REPL_ASSIGN_SUFFIX).toTermName - val assign = ValDef(assignName, TypeTree(), id).withPos(expr.pos) + val assign = ValDef(assignName, TypeTree(), id).withSpan(expr.span) defs += expr += assign case expr if expr.isTerm => val resName = (str.REPL_RES_PREFIX + valIdx).toTermName valIdx += 1 - val vd = ValDef(resName, TypeTree(), expr).withPos(expr.pos) + val vd = ValDef(resName, TypeTree(), expr).withSpan(expr.span) defs += vd case other => defs += other @@ -126,7 +123,7 @@ class ReplCompiler extends Compiler { * } * ``` */ - private def wrapped(defs: Definitions): untpd.PackageDef = { + private def wrapped(defs: Definitions, objectTermName: TermName): untpd.PackageDef = { import untpd._ assert(defs.stats.nonEmpty) @@ -134,15 +131,21 @@ class ReplCompiler extends Compiler { implicit val ctx: Context = defs.state.context val tmpl = Template(emptyConstructor, Nil, EmptyValDef, defs.stats) - val module = ModuleDef(objectName(defs.state), tmpl) - .withPos(Position(0, defs.stats.last.pos.end)) + val module = ModuleDef(objectTermName, tmpl) + .withSpan(Span(0, defs.stats.last.span.end)) PackageDef(Ident(nme.EMPTY_PACKAGE), List(module)) } - private def createUnit(defs: Definitions, sourceCode: String): CompilationUnit = { - val unit = new CompilationUnit(new SourceFile(objectName(defs.state).toString, sourceCode)) - unit.untpdTree = wrapped(defs) + private def createUnit(defs: Definitions)(implicit ctx: Context): CompilationUnit = { + val objectName = ctx.source.file.toString + assert(objectName.startsWith(str.REPL_SESSION_LINE)) + assert(objectName.endsWith(defs.state.objectIndex.toString)) + val objectTermName = ctx.source.file.toString.toTermName + objectNames.update(defs.state.objectIndex, objectTermName) + + val unit = CompilationUnit(ctx.source) + unit.untpdTree = wrapped(defs, objectTermName) unit } @@ -156,7 +159,7 @@ class ReplCompiler extends Compiler { final def compile(parsed: Parsed)(implicit state: State): Result[(CompilationUnit, State)] = { val defs = definitions(parsed.trees, state) - val unit = createUnit(defs, parsed.sourceCode) + val unit = createUnit(defs)(state.context) runCompilationUnit(unit, defs.state) } @@ -226,16 +229,15 @@ class ReplCompiler extends Compiler { def wrapped(expr: String, sourceFile: SourceFile, state: State)(implicit ctx: Context): Result[untpd.PackageDef] = { def wrap(trees: List[untpd.Tree]): untpd.PackageDef = { import untpd._ - - val valdef = ValDef("expr".toTermName, TypeTree(), Block(trees, unitLiteral)) + val valdef = ValDef("expr".toTermName, TypeTree(), Block(trees, unitLiteral).withSpan(Span(0, expr.length))) val tmpl = Template(emptyConstructor, Nil, EmptyValDef, List(valdef)) val wrapper = TypeDef("$wrapper".toTypeName, tmpl) .withMods(Modifiers(Final)) - .withPos(Position(0, expr.length)) + .withSpan(Span(0, expr.length)) PackageDef(Ident(nme.EMPTY_PACKAGE), List(wrapper)) } - ParseResult(expr) match { + ParseResult(expr)(state) match { case Parsed(_, trees) => wrap(trees).result case SyntaxErrors(_, reported, trees) => @@ -244,7 +246,7 @@ class ReplCompiler extends Compiler { case _ => List( new messages.Error( s"Couldn't parse '$expr' to valid scala", - sourceFile.atPos(Position(0, expr.length)) + sourceFile.atSpan(Span(0, expr.length)) ) ).errors } @@ -253,7 +255,7 @@ class ReplCompiler extends Compiler { def unwrapped(tree: tpd.Tree, sourceFile: SourceFile)(implicit ctx: Context): Result[tpd.ValDef] = { def error: Result[tpd.ValDef] = List(new messages.Error(s"Invalid scala expression", - sourceFile.atPos(Position(0, sourceFile.content.length)))).errors + sourceFile.atSpan(Span(0, sourceFile.content.length)))).errors import tpd._ tree match { @@ -267,13 +269,13 @@ class ReplCompiler extends Compiler { } - val src = new SourceFile("", expr) + val src = SourceFile.virtual("", expr) implicit val ctx: Context = state.context.fresh .setReporter(newStoreReporter) .setSetting(state.context.settings.YstopAfter, List("frontend")) wrapped(expr, src, state).flatMap { pkg => - val unit = new CompilationUnit(src) + val unit = CompilationUnit(src) unit.untpdTree = pkg ctx.run.compileUnits(unit :: Nil, ctx) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 38bbaffff0e4..d29c3ae90582 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -17,7 +17,7 @@ import dotty.tools.dotc.interactive.Completion import dotty.tools.dotc.printing.SyntaxHighlighting import dotty.tools.dotc.reporting.MessageRendering import dotty.tools.dotc.reporting.diagnostic.{Message, MessageContainer} -import dotty.tools.dotc.util.Positions.Position +import dotty.tools.dotc.util.Spans.Span import dotty.tools.dotc.util.{SourceFile, SourcePosition} import dotty.tools.dotc.{CompilationUnit, Driver} import dotty.tools.io._ @@ -113,7 +113,7 @@ class ReplDriver(settings: Array[String], implicit val ctx = state.context try { val line = terminal.readLine(completer) - ParseResult(line) + ParseResult(line)(state) } catch { case _: EndOfFileException | _: UserInterruptException => // Ctrl+D or Ctrl+C @@ -132,7 +132,7 @@ class ReplDriver(settings: Array[String], } final def run(input: String)(implicit state: State): State = withRedirectedOutput { - val parsed = ParseResult(input)(state.context) + val parsed = ParseResult(input)(state) interpret(parsed) } @@ -149,7 +149,7 @@ class ReplDriver(settings: Array[String], /** Extract possible completions at the index of `cursor` in `expr` */ protected[this] final def completions(cursor: Int, expr: String, state0: State): List[Candidate] = { - def makeCandidate(completion: Completion)(implicit ctx: Context) = { + def makeCandidate(completion: Completion) = { val displ = completion.label new Candidate( /* value = */ displ, @@ -165,11 +165,11 @@ class ReplDriver(settings: Array[String], compiler .typeCheck(expr, errorsAllowed = true) .map { tree => - val file = new SourceFile("", expr) - val unit = new CompilationUnit(file) + val file = SourceFile.virtual("", expr) + val unit = CompilationUnit(file)(state.context) unit.tpdTree = tree implicit val ctx = state.context.fresh.setCompilationUnit(unit) - val srcPos = SourcePosition(file, Position(cursor)) + val srcPos = SourcePosition(file, Span(cursor)) val (_, completions) = Completion.completions(srcPos) completions.map(makeCandidate) } @@ -208,7 +208,10 @@ class ReplDriver(settings: Array[String], def extractTopLevelImports(ctx: Context): List[tpd.Import] = ctx.phases.collectFirst { case phase: CollectTopLevelImports => phase.imports }.get - implicit val state = newRun(istate) + implicit val state = { + val state0 = newRun(istate) + state0.copy(context = state0.context.withSource(parsed.source)) + } compiler .compile(parsed) .fold( diff --git a/compiler/test-resources/repl/notFound b/compiler/test-resources/repl/notFound new file mode 100644 index 000000000000..99379a89660d --- /dev/null +++ b/compiler/test-resources/repl/notFound @@ -0,0 +1,8 @@ +scala> Foo +1 | Foo + | ^^^ + | Not found: Foo +scala> Bar +1 | Bar + | ^^^ + | Not found: Bar diff --git a/compiler/test/dotty/tools/dotc/ast/UntypedTreeMapTest.scala b/compiler/test/dotty/tools/dotc/ast/UntypedTreeMapTest.scala index 251bc3ab07a8..1633cfaa9b57 100644 --- a/compiler/test/dotty/tools/dotc/ast/UntypedTreeMapTest.scala +++ b/compiler/test/dotty/tools/dotc/ast/UntypedTreeMapTest.scala @@ -14,7 +14,7 @@ class UntpdTreeMapTest extends DottyTest { import untpd._ def parse(code: String): Tree = { - val (_, stats) = new Parser(new SourceFile("", code)).templateStatSeq() + val (_, stats) = new Parser(SourceFile.virtual("", code)).templateStatSeq() stats match { case List(stat) => stat; case stats => untpd.Thicket(stats) } } diff --git a/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala index 862159505465..97bd20e8d5a4 100644 --- a/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala @@ -17,7 +17,7 @@ object ModifiersParsingTest { implicit val ctx: Context = (new ContextBase).initialCtx def parse(code: String): Tree = { - val (_, stats) = new Parser(new SourceFile("", code)).templateStatSeq() + val (_, stats) = new Parser(SourceFile.virtual("", code)).templateStatSeq() stats match { case List(stat) => stat; case stats => Thicket(stats) } } @@ -137,7 +137,7 @@ class ModifiersParsingTest { source = parse("def f(implicit a: Int, b: Int) = ???") assert(source.defParam(0).modifiers == List(Mod.Implicit())) - assert(source.defParam(1).modifiers == List(Mod.Implicit())) + assert(source.defParam(1).modifiers == List()) source = parse("def f(x: Int, y: Int)(implicit a: Int, b: Int) = ???") assert(source.defParam(0, 0).modifiers == List()) diff --git a/compiler/test/dotty/tools/repl/TabcompleteTests.scala b/compiler/test/dotty/tools/repl/TabcompleteTests.scala index 7dc82fbb9988..d67deedad917 100644 --- a/compiler/test/dotty/tools/repl/TabcompleteTests.scala +++ b/compiler/test/dotty/tools/repl/TabcompleteTests.scala @@ -91,6 +91,12 @@ class TabcompleteTests extends ReplTest { assertEquals(expected, tabComplete("val foo: Rena")) } + @Test def tabClosureComplete = fromInitialState { implicit s => + assertEquals(List("map", "mapConserve"), tabComplete("Nil.map")) + assertEquals(List("map", "mapConserve"), tabComplete("(x: Int => Int) => Nil.map")) + assertEquals(List("apply"), tabComplete("(x: Int => Int) => x.ap")) + } + @Test def importScala = fromInitialState { implicit s => val comp = tabComplete("import scala.") // check that there are no special symbols leaked: , , ... diff --git a/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala b/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala index b51e93ab49d6..8c2fade43898 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala @@ -129,7 +129,7 @@ class DocASTPhase extends Phase { ValImpl(v.symbol, annotations(v.symbol), v.name.decode.toString, flags(v), path(v.symbol), returnType(v.tpt.tpe), kind) :: Nil case x => { - ctx.docbase.debug(s"Found unwanted entity: $x (${x.pos},\n${x.show}") + ctx.docbase.debug(s"Found unwanted entity: $x (${x.span},\n${x.show}") Nil } } diff --git a/doc-tool/src/dotty/tools/dottydoc/core/DocstringPhase.scala b/doc-tool/src/dotty/tools/dottydoc/core/DocstringPhase.scala index fa6c06cd4759..025c56cfa91c 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/DocstringPhase.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/DocstringPhase.scala @@ -32,11 +32,11 @@ class DocstringPhase extends DocMiniPhase with CommentParser with CommentCleaner comment <- getComment(ent.symbol) text <- comment.expandedBody } yield { - val parsed = parse(ent, ctx.docbase.packages, clean(text), text, comment.pos) + val parsed = parse(ent, ctx.docbase.packages, clean(text), text, comment.span) if (ctx.settings.wikiSyntax.value) - WikiComment(ent, parsed, comment.pos).comment + WikiComment(ent, parsed, comment.span).comment else - MarkdownComment(ent, parsed, comment.pos).comment + MarkdownComment(ent, parsed, comment.span).comment } } diff --git a/doc-tool/src/dotty/tools/dottydoc/model/comment/Comment.scala b/doc-tool/src/dotty/tools/dottydoc/model/comment/Comment.scala index dbc76d2fd618..e6a0219e5ede 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/Comment.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/Comment.scala @@ -5,7 +5,7 @@ package comment import dotty.tools.dottydoc.util.syntax._ import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.util.Positions._ +import dotty.tools.dotc.util.Spans._ import com.vladsch.flexmark.ast.{ Node => MarkdownNode } import HtmlParsers._ import util.MemberLookup @@ -59,7 +59,7 @@ private[comment] case class ParsedComment ( trait MarkupConversion[T] extends MemberLookup { def ent: Entity - def pos: Position + def span: Span def parsed: ParsedComment protected def linkedExceptions(m: Map[String, String])(implicit ctx: Context): Map[String, String] @@ -74,7 +74,7 @@ trait MarkupConversion[T] extends MemberLookup { case x :: xs => if (xs.nonEmpty) ctx.docbase.warn( s"Only allowed to have a single annotation for $annot", - ent.symbol.sourcePosition(pos) + ent.symbol.sourcePosition(span) ) Some(x) case _ => None @@ -104,7 +104,7 @@ trait MarkupConversion[T] extends MemberLookup { ) } -case class MarkdownComment(ent: Entity, parsed: ParsedComment, pos: Position) +case class MarkdownComment(ent: Entity, parsed: ParsedComment, span: Span) extends MarkupConversion[MarkdownNode] { def stringToMarkup(str: String)(implicit ctx: Context) = @@ -135,21 +135,21 @@ extends MarkupConversion[MarkdownNode] { .mapValues(stringToMarkup) } -case class WikiComment(ent: Entity, parsed: ParsedComment, pos: Position) +case class WikiComment(ent: Entity, parsed: ParsedComment, span: Span) extends MarkupConversion[Body] { def filterEmpty(xs: Map[String,String])(implicit ctx: Context) = - xs.mapValues(_.toWiki(ent, ctx.docbase.packages, pos)) + xs.mapValues(_.toWiki(ent, ctx.docbase.packages, span)) .filterNot { case (_, v) => v.blocks.isEmpty } def filterEmpty(xs: List[String])(implicit ctx: Context) = - xs.map(_.toWiki(ent, ctx.docbase.packages, pos)) + xs.map(_.toWiki(ent, ctx.docbase.packages, span)) def markupToHtml(t: Body)(implicit ctx: Context) = t.show(ent) def stringToMarkup(str: String)(implicit ctx: Context) = - str.toWiki(ent, ctx.docbase.packages, pos) + str.toWiki(ent, ctx.docbase.packages, span) def stringToShortHtml(str: String)(implicit ctx: Context) = { val parsed = stringToMarkup(str) @@ -157,7 +157,7 @@ extends MarkupConversion[Body] { } def linkedExceptions(m: Map[String, String])(implicit ctx: Context) = { - m.mapValues(_.toWiki(ent, ctx.docbase.packages, pos)).map { case (targetStr, body) => + m.mapValues(_.toWiki(ent, ctx.docbase.packages, span)).map { case (targetStr, body) => val link = lookup(Some(ent), ctx.docbase.packages, targetStr) val newBody = body match { case Body(List(Paragraph(Chain(content)))) => diff --git a/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentParser.scala b/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentParser.scala index f5b1b35cc8ee..72c86d5d8b1a 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentParser.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/CommentParser.scala @@ -3,7 +3,7 @@ package model package comment import dotty.tools.dottydoc.util.syntax._ -import dotty.tools.dotc.util.Positions._ +import dotty.tools.dotc.util.Spans._ import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.Decorators._ @@ -21,14 +21,14 @@ trait CommentParser extends util.MemberLookup { * @param packages all packages parsed by Scaladoc tool, used for lookup * @param cleanComment a cleaned comment to be parsed * @param src the raw comment source string. - * @param pos the position of the comment in source. + * @param span the position of the comment in source. */ def parse( entity: Entity, packages: Map[String, Package], comment: List[String], src: String, - pos: Position, + span: Span, site: Symbol = NoSymbol )(implicit ctx: Context): ParsedComment = { @@ -159,7 +159,7 @@ trait CommentParser extends util.MemberLookup { bodyTags.keys.toSeq flatMap { case stk: SymbolTagKey if (stk.name == key.name) => Some(stk) case stk: SimpleTagKey if (stk.name == key.name) => - dottydoc.println(s"$pos: tag '@${stk.name}' must be followed by a symbol name") + dottydoc.println(s"$span: tag '@${stk.name}' must be followed by a symbol name") None case _ => None } @@ -167,7 +167,7 @@ trait CommentParser extends util.MemberLookup { for (key <- keys) yield { val bs = (bodyTags remove key).get if (bs.length > 1) - dottydoc.println(s"$pos: only one '@${key.name}' tag for symbol ${key.symbol} is allowed") + dottydoc.println(s"$span: only one '@${key.name}' tag for symbol ${key.symbol} is allowed") (key.symbol, bs.head) } Map.empty[String, String] ++ pairs @@ -202,7 +202,7 @@ trait CommentParser extends util.MemberLookup { // with the point being at the very end. This ensures that the entire // comment will be visible in error reporting. A more fine-grained // reporting would be amazing here. - entity.symbol.sourcePosition(Position(pos.start, pos.end, pos.end)) + entity.symbol.sourcePosition(Span(span.start, span.end, span.end)) ) cmt @@ -236,7 +236,7 @@ trait CommentParser extends util.MemberLookup { entity: Entity, packages: Map[String, Package], string: String, - pos: Position, + span: Span, site: Symbol - )(implicit ctx: Context): Body = new WikiParser(entity, packages, string, pos, site).document() + )(implicit ctx: Context): Body = new WikiParser(entity, packages, string, span, site).document() } diff --git a/doc-tool/src/dotty/tools/dottydoc/model/comment/HtmlParsers.scala b/doc-tool/src/dotty/tools/dottydoc/model/comment/HtmlParsers.scala index 1faa25f326c5..c27ac22f36b2 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/HtmlParsers.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/HtmlParsers.scala @@ -4,7 +4,7 @@ package model package comment import dotc.core.Contexts.Context -import dotc.util.Positions._ +import dotc.util.Spans._ import dotty.tools.dottydoc.util.syntax._ import util.MemberLookup @@ -70,8 +70,8 @@ object HtmlParsers { } implicit class StringToWiki(val text: String) extends AnyVal { - def toWiki(origin: Entity, packages: Map[String, Package], pos: Position): Body = - new WikiParser(origin, packages, text, pos, origin.symbol).document() + def toWiki(origin: Entity, packages: Map[String, Package], span: Span): Body = + new WikiParser(origin, packages, text, span, origin.symbol).document() } implicit class BodyToHtml(val body: Body) extends AnyVal { diff --git a/doc-tool/src/dotty/tools/dottydoc/model/comment/WikiParser.scala b/doc-tool/src/dotty/tools/dottydoc/model/comment/WikiParser.scala index 70f85a53e29c..1d3aae5499ae 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/comment/WikiParser.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/comment/WikiParser.scala @@ -3,7 +3,7 @@ package model package comment import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.util.Positions._ +import dotty.tools.dotc.util.Spans._ import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.config.Printers.dottydoc import util.MemberLookup @@ -21,7 +21,7 @@ private[comment] final class WikiParser( entity: Entity, packages: Map[String, Package], val buffer: String, - pos: Position, + span: Span, site: Symbol ) extends CharReader(buffer) with MemberLookup { wiki => var summaryParsed = false @@ -110,7 +110,7 @@ private[comment] final class WikiParser( jump("{{{") val str = readUntil("}}}") if (char == endOfText) - reportError(pos, "unclosed code block") + reportError(span, "unclosed code block") else jump("}}}") blockEnded("code block") @@ -124,7 +124,7 @@ private[comment] final class WikiParser( val text = getInline(check("=" * inLevel)) val outLevel = repeatJump('=', inLevel) if (inLevel != outLevel) - reportError(pos, "unbalanced or unclosed heading") + reportError(span, "unbalanced or unclosed heading") blockEnded("heading") Title(text, inLevel) } @@ -344,7 +344,7 @@ private[comment] final class WikiParser( /** {{{ eol ::= { whitespace } '\n' }}} */ def blockEnded(blockType: String): Unit = { if (char != endOfLine && char != endOfText) { - reportError(pos, "no additional content on same line after " + blockType) + reportError(span, "no additional content on same line after " + blockType) jumpUntil(endOfLine) } while (char == endOfLine) @@ -402,8 +402,8 @@ private[comment] final class WikiParser( } } - def reportError(pos: Position, message: String) = - dottydoc.println(s"$pos: $message") + def reportError(span: Span, message: String) = + dottydoc.println(s"$span: $message") } sealed class CharReader(buffer: String) { reader => diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Page.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Page.scala index 7de72693aaea..76e401188dfd 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Page.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Page.scala @@ -89,7 +89,6 @@ trait Page { new SourceFile(virtualFile, Codec.UTF8) } - protected[this] var _yaml: Map[String, AnyRef /* String | JList[String] */] = _ protected[this] var _html: Option[String] = _ protected[this] def initFields(implicit ctx: Context) = { diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala index 1e656ee4f37d..89c6ca0f7e96 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala @@ -415,7 +415,7 @@ case class Site( } private def toSourceFile(f: JFile): SourceFile = - SourceFile(AbstractFile.getFile(new File(f.toPath)), Source.fromFile(f, "UTF-8").toArray) + new SourceFile(AbstractFile.getFile(new File(f.toPath)), Source.fromFile(f, "UTF-8").toArray) private def collectFiles(dir: JFile, includes: String => Boolean): Array[JFile] = dir diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Template.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Template.scala index efa011e0a8a8..ef1f68b6e1c4 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Template.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Template.scala @@ -6,7 +6,7 @@ import scala.util.control.NonFatal import dotc.util.SourceFile import dotc.core.Contexts.Context -import dotc.util.Positions.{ Position, NoPosition } +import dotc.util.Spans.Span import util.syntax._ trait Template { @@ -68,7 +68,7 @@ case class LiquidTemplate(path: String, content: SourceFile) extends Template wi s"unexpected end of file, expected: '$expected'" else s"unexpected token '$unexpected', expected: '$expected'", - content atPos Position(mm.index) + content atSpan Span(mm.index) ) None diff --git a/doc-tool/src/dotty/tools/dottydoc/util/syntax.scala b/doc-tool/src/dotty/tools/dottydoc/util/syntax.scala index 4edb71b387dd..2c99783d7182 100644 --- a/doc-tool/src/dotty/tools/dottydoc/util/syntax.scala +++ b/doc-tool/src/dotty/tools/dottydoc/util/syntax.scala @@ -9,7 +9,7 @@ import core.ContextDottydoc import dotc.core.Symbols._ import dotc.util.{ SourcePosition, SourceFile } -import dotc.util.Positions.Position +import dotc.util.Spans.Span import scala.io.Codec object syntax { @@ -20,7 +20,7 @@ object syntax { } implicit class SymbolExtensions(val sym: Symbol) extends AnyVal { - def sourcePosition(pos: Position)(implicit ctx: Context): SourcePosition = - ctx.getSource(sym.sourceFile).atPos(pos) + def sourcePosition(span: Span)(implicit ctx: Context): SourcePosition = + sym.source.atSpan(span) } } diff --git a/doc-tool/test/dotty/tools/dottydoc/ConstructorTest.scala b/doc-tool/test/dotty/tools/dottydoc/ConstructorTest.scala index 086abd99c9fd..ce90fd020212 100644 --- a/doc-tool/test/dotty/tools/dottydoc/ConstructorTest.scala +++ b/doc-tool/test/dotty/tools/dottydoc/ConstructorTest.scala @@ -14,8 +14,7 @@ class ConstructorsFromTastyTest extends ConstructorsBase with CheckFromTasty abstract class ConstructorsBase extends DottyDocTest { @Test def singleClassConstructor = { - val source = new SourceFile ( - "Class.scala", + val source = SourceUtil.makeTemp( """ |package scala | @@ -38,8 +37,7 @@ abstract class ConstructorsBase extends DottyDocTest { } @Test def constructorPlusImplicitArgList = { - val source = new SourceFile ( - "Class.scala", + val source = SourceUtil.makeTemp( """ |package scala | @@ -65,8 +63,7 @@ abstract class ConstructorsBase extends DottyDocTest { } @Test def multipleArgumentListsForConstructor = { - val source = new SourceFile ( - "Class.scala", + val source = SourceUtil.makeTemp( """ |package scala | @@ -93,8 +90,7 @@ abstract class ConstructorsBase extends DottyDocTest { } @Test def multipleConstructors = { - val source = new SourceFile ( - "Class.scala", + val source = SourceUtil.makeTemp( """ |package scala | @@ -133,8 +129,7 @@ abstract class ConstructorsBase extends DottyDocTest { } @Test def multipleConstructorsCC = { - val source = new SourceFile ( - "Class.scala", + val source = SourceUtil.makeTemp( """ |package scala | @@ -174,8 +169,7 @@ abstract class ConstructorsBase extends DottyDocTest { } @Test def traitParameters = { - val source = new SourceFile ( - "Trait.scala", + val source = SourceUtil.makeTemp( """ |package scala | diff --git a/doc-tool/test/dotty/tools/dottydoc/PackageStructure.scala b/doc-tool/test/dotty/tools/dottydoc/PackageStructure.scala index 2ef1352f2d07..5d235a0a6821 100644 --- a/doc-tool/test/dotty/tools/dottydoc/PackageStructure.scala +++ b/doc-tool/test/dotty/tools/dottydoc/PackageStructure.scala @@ -13,8 +13,7 @@ class PackageStructureFromTastyTest extends PackageStructureBase with CheckFromT abstract class PackageStructureBase extends DottyDocTest { @Test def sourceFileAnnotIsStripped = { - val source = new SourceFile( - "A.scala", + val source = SourceUtil.makeTemp( """package scala | |/** Some doc */ @@ -33,8 +32,7 @@ abstract class PackageStructureBase extends DottyDocTest { } @Test def multipleCompilationUnits = { - val source1 = new SourceFile( - "TraitA.scala", + val source1 = SourceUtil.makeTemp( """ |package scala | @@ -42,8 +40,7 @@ abstract class PackageStructureBase extends DottyDocTest { """.stripMargin ) - val source2 = new SourceFile( - "TraitB.scala", + val source2 = SourceUtil.makeTemp( """ |package scala | @@ -67,8 +64,7 @@ abstract class PackageStructureBase extends DottyDocTest { @Test def multiplePackages = { - val source1 = new SourceFile( - "TraitA.scala", + val source1 = SourceUtil.makeTemp( """ |package scala |package collection @@ -76,8 +72,7 @@ abstract class PackageStructureBase extends DottyDocTest { |trait A """.stripMargin) - val source2 = new SourceFile( - "TraitB.scala", + val source2 = SourceUtil.makeTemp( """ |package scala |package collection diff --git a/doc-tool/test/dotty/tools/dottydoc/SimpleComments.scala b/doc-tool/test/dotty/tools/dottydoc/SimpleComments.scala index f9d8ae043ba9..cbfd57fb568e 100644 --- a/doc-tool/test/dotty/tools/dottydoc/SimpleComments.scala +++ b/doc-tool/test/dotty/tools/dottydoc/SimpleComments.scala @@ -3,6 +3,7 @@ package dottydoc import model.internal._ import dotc.util.SourceFile +import dotty.tools.io._ import org.junit.Test import org.junit.Assert._ @@ -35,8 +36,7 @@ abstract class SimpleCommentsBase extends DottyDocTest { } @Test def simpleComment = { - val source = new SourceFile( - "HelloWorld.scala", + val source = SourceUtil.makeTemp( """ |package scala | @@ -45,6 +45,7 @@ abstract class SimpleCommentsBase extends DottyDocTest { """.stripMargin ) + val className = "scala.HelloWorld" check(className :: Nil, source :: Nil) { (ctx, packages) => diff --git a/doc-tool/test/dotty/tools/dottydoc/SourceUtil.scala b/doc-tool/test/dotty/tools/dottydoc/SourceUtil.scala new file mode 100644 index 000000000000..eef86f5da9d2 --- /dev/null +++ b/doc-tool/test/dotty/tools/dottydoc/SourceUtil.scala @@ -0,0 +1,18 @@ +package dotty.tools.dottydoc + +import dotty.tools.dotc.util.SourceFile +import dotty.tools.io.{Path, PlainFile} + +object SourceUtil { + + /** Create a temporary `.scala` source file with the given content */ + def makeTemp(content: String): SourceFile = { + val tempFile = java.io.File.createTempFile("dottydoc-test-", ".scala") + tempFile.deleteOnExit() + val file = new PlainFile(Path(tempFile.toPath)) + val out = file.output + out.write(content.getBytes) + new SourceFile(file, scala.io.Codec.UTF8) + } + +} diff --git a/doc-tool/test/dotty/tools/dottydoc/TypeRendering.scala b/doc-tool/test/dotty/tools/dottydoc/TypeRendering.scala index 630c0d09aead..5e4d50274ac3 100644 --- a/doc-tool/test/dotty/tools/dottydoc/TypeRendering.scala +++ b/doc-tool/test/dotty/tools/dottydoc/TypeRendering.scala @@ -13,7 +13,7 @@ class TypeRenderingTestFromTasty extends TypeRenderingTest with CheckFromTasty class TypeRenderingTestFromSource extends TypeRenderingTest with CheckFromSource abstract class TypeRenderingTest extends DottyDocTest { @Test def renderImplicitFunctionType = { - val source = new SourceFile( + val source = SourceFile.virtual( "ImplicitFunctionType.scala", """ |package scala diff --git a/doc-tool/test/dotty/tools/dottydoc/UsecaseTest.scala b/doc-tool/test/dotty/tools/dottydoc/UsecaseTest.scala index f3772a882782..79f2c4c1d4e8 100644 --- a/doc-tool/test/dotty/tools/dottydoc/UsecaseTest.scala +++ b/doc-tool/test/dotty/tools/dottydoc/UsecaseTest.scala @@ -15,8 +15,7 @@ class UsecaseFromTastyTest extends UsecaseBase with CheckFromTasty abstract class UsecaseBase extends DottyDocTest { @Test def simpleUsecase = { - val source = new SourceFile( - "DefWithUseCase.scala", + val source = SourceUtil.makeTemp( """ |package scala | @@ -61,8 +60,7 @@ abstract class UsecaseBase extends DottyDocTest { } @Test def simpleUsecaseAddedArg = { - val source = new SourceFile( - "DefWithUseCase.scala", + val source = SourceUtil.makeTemp( """ |package scala | @@ -108,8 +106,7 @@ abstract class UsecaseBase extends DottyDocTest { } @Test def simpleTparamUsecase = { - val source = new SourceFile( - "DefWithUseCase.scala", + val source = SourceUtil.makeTemp( """ |package scala | @@ -154,8 +151,7 @@ abstract class UsecaseBase extends DottyDocTest { } @Test def expandColl = { - val source = new SourceFile( - "ExpandColl.scala", + val source = SourceUtil.makeTemp( """ |package scala | @@ -199,8 +195,7 @@ abstract class UsecaseBase extends DottyDocTest { } @Test def checkStripping = { - val source = new SourceFile( - "CheckStripping.scala", + val source = SourceUtil.makeTemp( """ |package scala | @@ -236,8 +231,7 @@ abstract class UsecaseBase extends DottyDocTest { } @Test def multipleUseCases: Unit = { - val source = new SourceFile( - name = "MultipleUseCases.scala", + val source = SourceUtil.makeTemp( """ |package scala | diff --git a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala index 9703bb022f18..76ae83ffc374 100644 --- a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala +++ b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala @@ -18,7 +18,7 @@ import scala.io.Codec import dotc._ import ast.{Trees, tpd} -import core._, core.Decorators.{sourcePos => _, _} +import core._, core.Decorators._ import Annotations.AnnotInfo import Comments._, Constants._, Contexts._, Flags._, Names._, NameOps._, Symbols._, SymDenotations._, Trees._, Types._ import classpath.ClassPathEntries @@ -388,7 +388,7 @@ class DottyLanguageServer extends LanguageServer val refs = path match { // Selected a renaming in an import node - case Thicket(_ :: (rename: Ident) :: Nil) :: (_: Import) :: rest if rename.pos.contains(pos.pos) => + case Thicket(_ :: (rename: Ident) :: Nil) :: (_: Import) :: rest if rename.span.contains(pos.span) => findRenamedReferences(uriTrees, syms, rename.name) // Selected a reference that has been renamed @@ -545,7 +545,7 @@ class DottyLanguageServer extends LanguageServer val trees = driver.openedTrees(uri) val path = Interactive.pathTo(trees, pos).dropWhile(!_.isInstanceOf[Apply]) - val (paramN, callableN, alternatives) = Signatures.callInfo(path, pos.pos) + val (paramN, callableN, alternatives) = Signatures.callInfo(path, pos.span) val signatureInfos = alternatives.flatMap(Signatures.toSignature) new SignatureHelp(signatureInfos.map(signatureToSignatureInformation).asJava, callableN, paramN) @@ -646,7 +646,7 @@ object DottyLanguageServer { else pos val source = driver.openedFiles(uri) if (source.exists) { - val p = Positions.Position(source.lineToOffset(actualPosition.getLine) + actualPosition.getCharacter) + val p = Spans.Span(source.lineToOffset(actualPosition.getLine) + actualPosition.getCharacter) new SourcePosition(source, p) } else NoSourcePosition @@ -754,7 +754,7 @@ object DottyLanguageServer { * @return The position in the actual source file (before wrapping). */ private def toUnwrappedPosition(position: SourcePosition): SourcePosition = { - new SourcePosition(position.source, position.pos, position.outer) { + new SourcePosition(position.source, position.span, position.outer) { override def startLine: Int = position.startLine - 1 override def endLine: Int = position.endLine - 1 } diff --git a/language-server/src/dotty/tools/languageserver/worksheet/Worksheet.scala b/language-server/src/dotty/tools/languageserver/worksheet/Worksheet.scala index 88cd82368044..f51149ae0dea 100644 --- a/language-server/src/dotty/tools/languageserver/worksheet/Worksheet.scala +++ b/language-server/src/dotty/tools/languageserver/worksheet/Worksheet.scala @@ -3,7 +3,7 @@ package dotty.tools.languageserver.worksheet import dotty.tools.dotc.ast.tpd.{DefTree, Template, Tree, TypeDef} import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.interactive.SourceTree -import dotty.tools.dotc.util.Positions.Position +import dotty.tools.dotc.util.Spans.Span import dotty.tools.dotc.util.SourceFile import dotty.tools.dotc.core.Flags.Synthetic @@ -40,7 +40,7 @@ object Worksheet { template.body.flatMap { case statement: DefTree if statement.symbol.is(Synthetic) => None - case statement if seen.add(bounds(statement.pos)) => + case statement if seen.add(bounds(statement.span)) => Some(query(statement, tree.source)) case _ => None @@ -66,12 +66,12 @@ object Worksheet { * @param sourcefile The sourcefile of the worksheet. */ private def query(tree: Tree, sourcefile: SourceFile): (Int, String) = { - val line = sourcefile.offsetToLine(tree.pos.end) - val source = sourcefile.content.slice(tree.pos.start, tree.pos.end).mkString + val line = sourcefile.offsetToLine(tree.span.end) + val source = sourcefile.content.slice(tree.span.start, tree.span.end).mkString (line, source) } - private def bounds(pos: Position): (Int, Int) = (pos.start, pos.end) + private def bounds(span: Span): (Int, Int) = (span.start, span.end) } diff --git a/library/src-bootstrapped/scala/Tuple.scala b/library/src-bootstrapped/scala/Tuple.scala index 3f19b82d4a43..ed5e3d43ff25 100644 --- a/library/src-bootstrapped/scala/Tuple.scala +++ b/library/src-bootstrapped/scala/Tuple.scala @@ -183,7 +183,7 @@ object Tuple { def $consArray[H](x: H, elems: Array[Object]): Array[Object] = { val elems1 = new Array[Object](elems.length + 1) elems1(0) = x.asInstanceOf[Object] - Array.copy(elems, 0, elems1, 1, elems.length) + System.arraycopy(elems, 0, elems1, 1, elems.length) elems1 } diff --git a/library/src/scala/annotation/constructorOnly.scala b/library/src/scala/annotation/constructorOnly.scala new file mode 100644 index 000000000000..580354e468a3 --- /dev/null +++ b/library/src/scala/annotation/constructorOnly.scala @@ -0,0 +1,20 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.annotation + +import scala.annotation.meta._ + +/** An annotation that goes on parameters of classes or traits. It asserts + * that the parameter is used only for initialization and is not kept in + * the class as a field. Violations of this assertion are flagged as + * compile errors. The annotation is particularly useful for implicit + * parameters since for these a textual scan is not sufficient to know + * where they are used. + */ +@param class constructorOnly extends scala.annotation.StaticAnnotation diff --git a/library/src/scala/tasty/reflect/TreeOps.scala b/library/src/scala/tasty/reflect/TreeOps.scala index be45b19e8f02..5d0a40747907 100644 --- a/library/src/scala/tasty/reflect/TreeOps.scala +++ b/library/src/scala/tasty/reflect/TreeOps.scala @@ -320,7 +320,7 @@ trait TreeOps extends Core { /** Create a `this[` */ def apply(cls: ClassSymbol)(implicit ctx: Context): This - def copy(original: Tree)(qual: Option[Id]): This + def copy(original: Tree)(qual: Option[Id])(implicit ctx: Context): This /** Matches `this[` */ def unapply(tree: Tree)(implicit ctx: Context): Option[Option[Id]] @@ -444,7 +444,7 @@ trait TreeOps extends Core { /** Creates a `.super[` */ def apply(qual: Term, mix: Option[Id])(implicit ctx: Context): Super - def copy(original: Tree)(qual: Term, mix: Option[Id]): Super + def copy(original: Tree)(qual: Term, mix: Option[Id])(implicit ctx: Context): Super /** Matches a `.super[` */ def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, Option[Id])] diff --git a/tests/neg/constructor-only.scala b/tests/neg/constructor-only.scala new file mode 100644 index 000000000000..8a7ad716dd3b --- /dev/null +++ b/tests/neg/constructor-only.scala @@ -0,0 +1,14 @@ +import annotation.constructorOnly +class Context + +class Test1()(implicit @constructorOnly ctx: Context) { // error + def test1 = implicitly[Context] +} + +class Test2()(@constructorOnly ctx: Context) { // error + def test1 = ctx +} + +class Test3()(implicit @constructorOnly ctx: Context) { // OK + val foo = implicitly[Context] +} diff --git a/tests/neg/quote-0.scala b/tests/neg/quote-0.scala index 6ee4c560c1a4..3e4231281300 100644 --- a/tests/neg/quote-0.scala +++ b/tests/neg/quote-0.scala @@ -14,8 +14,8 @@ class Test { '((y: Expr[Int]) => ~y ) // error: wrong staging level - def f[T](t: Type[T], x: Expr[T]) = '{ - val z2 = ~x // error: wrong staging level + def f[T](t: Type[T], x: Expr[T]) = '{ // error: wrong staging level + val z2 = ~x } def g[T](implicit t: Type[T], x: Expr[T]) = '{ diff --git a/tests/neg/ski.scala b/tests/neg/ski.scala index 90a43039aa73..2c68f336e98c 100644 --- a/tests/neg/ski.scala +++ b/tests/neg/ski.scala @@ -18,7 +18,7 @@ trait S2[x <: Term, y <: Term] extends Term { } trait S3[x <: Term, y <: Term, z <: Term] extends Term { type ap[v <: Term] = eval#ap[v] // error: not a legal path - type eval = x#ap[z]#ap[y#ap[z]]#eval // error: not a legal path // error: not a legal path + type eval = x#ap[z]#ap[y#ap[z]]#eval // error: not a legal path } // The K combinator diff --git a/tests/plugins/neg/divideZero-research/plugin_1.scala b/tests/plugins/neg/divideZero-research/plugin_1.scala index 4b255faa1266..45ef30a41150 100644 --- a/tests/plugins/neg/divideZero-research/plugin_1.scala +++ b/tests/plugins/neg/divideZero-research/plugin_1.scala @@ -30,7 +30,7 @@ class DivideZero extends MiniPhase with ResearchPlugin { override def transformApply(tree: tpd.Apply)(implicit ctx: Context): tpd.Tree = tree match { case tpd.Apply(fun, tpd.Literal(Constants.Constant(v)) :: Nil) if isNumericDivide(fun.symbol) && v == 0 => - ctx.error("divide by zero", tree.pos) + ctx.error("divide by zero", tree.sourcePos) tree case _ => tree diff --git a/tests/plugins/neg/divideZero/plugin_1.scala b/tests/plugins/neg/divideZero/plugin_1.scala index 97b3dfa22ee2..fb27821f59e7 100644 --- a/tests/plugins/neg/divideZero/plugin_1.scala +++ b/tests/plugins/neg/divideZero/plugin_1.scala @@ -31,7 +31,7 @@ class DivideZero extends PluginPhase with StandardPlugin { override def transformApply(tree: tpd.Apply)(implicit ctx: Context): tpd.Tree = tree match { case tpd.Apply(fun, tpd.Literal(Constants.Constant(v)) :: Nil) if isNumericDivide(fun.symbol) && v == 0 => - ctx.error("divide by zero", tree.pos) + ctx.error("divide by zero", tree.sourcePos) tree case _ => tree diff --git a/tests/pos-with-compiler/tasty/definitions.scala b/tests/pos-with-compiler/tasty/definitions.scala index d54edfbba574..40363f4e8eeb 100644 --- a/tests/pos-with-compiler/tasty/definitions.scala +++ b/tests/pos-with-compiler/tasty/definitions.scala @@ -348,7 +348,7 @@ object ReflectionImpl extends Tasty { import dotty.tools.dotc._ import ast.tpd import core.{Types, Symbols, Contexts} - import util.{Positions} + import util.Spans type Type = Types.Type implicit class TypeDeco(x: Type) extends TypeAPI {} @@ -361,7 +361,7 @@ object ReflectionImpl extends Tasty { val owner = c.owner } - type Position = Positions.Position + type Position = Spans.Span implicit class PositionDeco(p: Position) extends PositionAPI { val start = p.start val end = p.end @@ -369,19 +369,19 @@ object ReflectionImpl extends Tasty { type Pattern = tpd.Tree implicit class PatternDeco(p: Pattern) extends TypedPositioned { - val pos = p.pos + val pos = p.span val tpe = p.tpe } type Term = tpd.Tree implicit class TermDeco(t: Term) extends TypedPositioned { - val pos = t.pos + val pos = t.span val tpe = t.tpe } type CaseDef = tpd.CaseDef implicit class CaseDefDeco(c: CaseDef) extends TypedPositioned { - val pos = c.pos + val pos = c.span val tpe = c.tpe } diff --git a/tests/run/i3396.check b/tests/run/i3396.check new file mode 100644 index 000000000000..d00491fd7e5b --- /dev/null +++ b/tests/run/i3396.check @@ -0,0 +1 @@ +1 diff --git a/tests/run/tuple-cons-2.check b/tests/run/tuple-cons-2.check new file mode 100644 index 000000000000..2f42f3bc5bd3 --- /dev/null +++ b/tests/run/tuple-cons-2.check @@ -0,0 +1 @@ +(1,2,3,4,5,6)