diff --git a/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala b/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala index a2d178e70c49..a7ce85c4976e 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.Position import Decorators._ import StdNames.nme @@ -48,9 +48,9 @@ object CollectEntryPoints{ (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) + 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.pos // 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 diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 781885faec65..236e9a795195 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.Position = + ctx.source.atSpan(pos) def emitAsmp: Option[String] = None @@ -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/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 48c363ee65e0..d602439781cb 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,7 +1601,7 @@ 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 @@ -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) { @@ -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..cdd92078d1db 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -34,9 +34,9 @@ class CompilationUnit(val source: SourceFile) { object CompilationUnit { - /** Make a compilation unit for top class `clsd` with the contends of the `unpickled` */ + /** Make a compilation unit for top class `clsd` with the contents of the `unpickled` tree */ def mkCompilationUnit(clsd: ClassDenotation, unpickled: Tree, forceTrees: Boolean)(implicit ctx: Context): CompilationUnit = - mkCompilationUnit(SourceFile(clsd.symbol.associatedFile, Array.empty), unpickled, forceTrees) + mkCompilationUnit(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 = { diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index 9067693e1168..f5d1522749bc 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) => @@ -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 = new 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..bacb62e6a366 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.transientParam import scala.annotation.internal.sharable @@ -42,15 +43,15 @@ object desugar { // ----- DerivedTypeTrees ----------------------------------- - class SetterParamTree extends DerivedTypeTree { + class SetterParamTree(implicit @transientParam 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 @transientParam src: SourceFile) extends DerivedTypeTree { def derivedTree(sym: Symbol)(implicit ctx: Context): tpd.TypeTree = tpd.TypeTree(sym.typeRef) } - class TermRefTree extends DerivedTypeTree { + class TermRefTree(implicit @transientParam 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 @transientParam 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).withPosOf(tdef.rhs).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("").withPosOf(vdef.tpt).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.pos.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.pos.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 @@ -563,7 +564,7 @@ object desugar { ModuleDef( className.toTermName, Template(emptyConstructor, parentTpt :: Nil, EmptyValDef, defs)) .withMods(companionMods | Synthetic)) - .withPos(cdef.pos).toList + .withPosOf(cdef).toList val companionMembers = defaultGetters ::: eqInstances ::: enumCases @@ -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 + .withPosOf(cdef) :: 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) 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).withPosOf(mdef)) } } @@ -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)).withPosOf(tree) } 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)).withPosOf(param) } 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.withPosOf(tree) } /** Create a class definition with the same info as the refined type given by `parent` @@ -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 @transientParam 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..46c4765a0544 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 @@ -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..962b4da1a246 100644 --- a/compiler/src/dotty/tools/dotc/ast/Positioned.scala +++ b/compiler/src/dotty/tools/dotc/ast/Positioned.scala @@ -1,84 +1,117 @@ -package dotty.tools.dotc +package dotty.tools +package dotc package ast -import util.Positions._ +import util.Spans._ +import util.{SourceFile, NoSource, Position} import core.Contexts.Context import core.Decorators._ import core.Flags.{JavaDefined, Extension} import core.StdNames.nme +import annotation.transientParam +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 @transientParam src: SourceFile) extends Product with Cloneable { - private[this] var curPos: Position = _ + /** A unique identifier. Among other things, used for determining the source file + * component of the position. + */ + private var myUniqueId: Int = -1 + private[this] var mySpan: Span = NoSpan - setPos(initialPos) + /** The span part of the item's position */ + def span: Span = mySpan - /** The item's position. - */ - def pos: Position = curPos + /** item's id */ + def uniqueId: Int = myUniqueId + + def source: SourceFile = SourceFile.fromId(uniqueId) + def pos(implicit ctx: Context): Position = source.atSpan(span) + + //setId(initialSource(src).nextId) + setPos(initialSpan(src), source) + + protected def setId(id: Int): Unit = { + myUniqueId = id + //assert(id != 2067, getClass) + } - /** Destructively update `curPos` to given position. Also, set any missing - * positions in children. + /** Destructively update `mySpan` to given span and potentially update `id` so that + * it refers to `file`. Also, set any missing positions in children. */ - protected def setPos(pos: Position): Unit = { - setPosUnchecked(pos) - if (pos.exists) setChildPositions(pos.toSynthetic) + protected def setPos(span: Span, file: SourceFile): Unit = { + setOnePos(span, file) + if (span.exists) setChildPositions(span.toSynthetic, file) } - /** A positioned item like this one with the position set to `pos`. - * if the positioned item is source-derived, a clone is returned. + /** 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. */ - 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] + def withSpan(span: Span): this.type = { + val ownSpan = this.span + val newpd: this.type = + if (span == ownSpan || ownSpan.isSynthetic) this else cloneIn(source) + newpd.setPos(span, source) + newpd } - def withPos(posd: Positioned): this.type = - if (posd == null) this else withPos(posd.pos) + def withPosOf(posd: Positioned): this.type = { + val ownSpan = this.span + val newpd: this.type = + if ((posd.source `eq` source) && posd.span == ownSpan || ownSpan.isSynthetic) this + else cloneIn(posd.source) + newpd.setPos(posd.span, posd.source) + newpd + } - /** 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) + def withPos(pos: Position): this.type = { + val ownSpan = this.span + val newpd: this.type = + if ((pos.source `eq` source) && pos.span == ownSpan || ownSpan.isSynthetic) this + else cloneIn(pos.source) + newpd.setPos(pos.span, pos.source) + newpd + } - /** Set position of this tree only, without performing - * any checks of consistency with - or updates of - other positions. + /** Set span of this tree only, without updating children spans. * Called from Unpickler when entering positions. */ - private[dotc] def setPosUnchecked(pos: Position): Unit = curPos = pos + private[dotc] def setOnePos(span: Span, file: SourceFile = this.source): Unit = { + if (file `ne` this.source) setId(file.nextId) + mySpan = span + } - /** If any children of this node do not have positions, - * fit their positions between the positions of the known subtrees + /** If any children of this node do not have spans, + * fit their spans between the spans 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. + * is none and the other which propagates the span 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. */ - private def setChildPositions(pos: Position): Unit = { + private def setChildPositions(span: Span, file: SourceFile): 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 + var end = span.end // the last defined offset, fill in spans up to this offset + var outstanding: List[Positioned] = Nil // nodes that need their spans filled once a start offset // 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 + // If a tree has no span or a zero-extent span, 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)) + // zero-extent span for these trees here. + if (!p.span.exists || p.span.isZeroExtent) { + p.setPos(Span(start, start), file) fillIn(ps1, start, end) } else { - p.setPos(Position(start, end)) + p.setPos(Span(start, end), file) fillIn(ps1, end, end) } case nil => @@ -94,17 +127,20 @@ abstract class Positioned extends Product { nextChild = productElement(n) } else { - fillIn(outstanding, pos.start, end) + fillIn(outstanding, span.start, end) return } nextChild match { case p: Positioned => - if (p.pos.exists) { - fillIn(outstanding, p.pos.end, end) + if (p.span.exists) { + fillIn(outstanding, p.span.end, end) outstanding = Nil - end = p.pos.start + end = p.span.start } else outstanding = p :: outstanding + case m: untpd.Modifiers => + if (m.mods.nonEmpty || m.annotations.nonEmpty) + elems = elems ::: m.mods.reverse ::: m.annotations.reverse case xs: List[_] => elems = elems ::: xs.reverse case _ => @@ -112,40 +148,77 @@ abstract class Positioned extends Product { } } - /** The initial, synthetic position. This is usually the union of all positioned children's positions. + /** Clone this node but assign it a fresh id which marks it as a node in `file`. */ + protected def cloneIn(file: SourceFile): this.type = { + val newpd: this.type = clone.asInstanceOf[this.type] + newpd.setId(file.nextId) + newpd + } + + /** The initial, synthetic span. This is usually the union of all positioned children's spans. */ - def initialPos: Position = { - var n = productArity - var pos = NoPosition - while (n > 0) { - n -= 1 + def initialSpan(givenSource: SourceFile): Span = { + + def include(span1: Span, p2: Positioned): Span = { + val span2 = p2.span + if (span2.exists) { + var src = if (uniqueId == -1) NoSource else source + val src2 = p2.source + if (src `eq` src2) span1.union(span2) + else if (!src.exists) { + setId(src2.nextId) + if (span1.exists) initialSpan(givenSource) // we might have some mis-classified children; re-run everything + else span2 + } + else span1 // sources differ: ignore child span + } + else span1 + } + + def includeAll(span: Span, xs: List[_]): Span = xs match { + case Nil => span + case (p: Positioned) :: xs1 => includeAll(include(span, p), xs1) + case (xs0: List[_]) :: xs1 => includeAll(includeAll(span, xs0), xs1) + case _ :: xs1 => includeAll(span, xs1) + } + + val limit = relevantElemCount + var n = 0 + var span = NoSpan + while (n < limit) { productElement(n) match { - case p: Positioned => pos = pos union p.pos - case xs: List[_] => pos = unionPos(pos, xs) + case p: Positioned => + span = include(span, p) + case m: untpd.Modifiers => + span = includeAll(includeAll(span, m.mods), m.annotations) + case xs: ::[_] => + span = includeAll(span, xs) case _ => } + n += 1 } - pos.toSynthetic + if (uniqueId == -1) setId(givenSource.nextId) + span.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 - } + /** How many elements to consider when computing the span. + * Normally: all, overridden in Inlined. + */ + def relevantElemCount = productArity 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 +230,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, + s"""position error, parent span does not contain child span + |parent = $this, + |parent span = $span, + |child = $p, + |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 +259,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, + assert(!lastSpan.exists || !p.span.exists || lastSpan.end <= p.span.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) + |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 903c7aa9897b..6789bd55e96a 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -553,7 +553,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 } @@ -663,11 +663,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) @@ -716,7 +716,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..9f3cc17aaf54 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]).withPosOf(id) 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)).withPosOf(tree).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..eafaae4a10dc 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, Position} import config.Config import annotation.internal.sharable import annotation.unchecked.uncheckedVariance +import annotation.transientParam +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 @transientParam 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.withPosOf(from) 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam src: SourceFile) extends SeqLiteral(elems, elemtpt) { override def toString: String = s"JavaSeqLiteral($elems, $elemtpt)" } @@ -613,14 +599,14 @@ 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 @transientParam src: SourceFile) extends Tree[T] { type ThisTree[-T >: Untyped] = Inlined[T] - override def initialPos: Position = call.pos + override def relevantElemCount = 1 // only consider call when computing span } /** A type tree that represents an existing or inferred type */ - case class TypeTree[-T >: Untyped] () + case class TypeTree[-T >: Untyped]()(implicit @transientParam src: SourceFile) extends DenotingTree[T] with TypTree[T] { type ThisTree[-T >: Untyped] = TypeTree[T] override def isEmpty: Boolean = !hasType @@ -631,66 +617,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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 +684,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 @transientParam src: SourceFile) extends PatternTree[T] { type ThisTree[-T >: Untyped] = Alternative[T] } @@ -717,13 +703,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 @transientParam 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 @transientParam src: SourceFile) extends ValOrDefDef[T] { type ThisTree[-T >: Untyped] = ValDef[T] assert(isEmpty || tpt != genericEmptyTree) @@ -733,7 +719,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 @transientParam src: SourceFile) extends ValOrDefDef[T] { type ThisTree[-T >: Untyped] = DefDef[T] assert(tpt != genericEmptyTree) @@ -746,7 +732,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 @transientParam src: SourceFile) extends MemberDef[T] { type ThisTree[-T >: Untyped] = TypeDef[T] @@ -755,7 +741,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 @transientParam src: SourceFile) extends DefTree[T] with WithLazyField[List[Tree[T]]] { type ThisTree[-T >: Untyped] = Template[T] def unforcedBody: LazyTreeList = unforced @@ -768,20 +754,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 @transientParam 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 @transientParam 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 @transientParam src: SourceFile) extends ProxyTree[T] { type ThisTree[-T >: Untyped] = Annotated[T] def forwardTo: Tree[T] = arg @@ -789,8 +775,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 setPos(span: Span, src: SourceFile): Unit = {} } /** Temporary class that results from translation of ModuleDefs @@ -798,34 +784,47 @@ 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 @transientParam 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] + override def withPosOf(posd: Positioned): this.type = + mapElems(_.withPosOf(posd)).asInstanceOf[this.type] + override def withPos(pos: Position): this.type = + mapElems(_.withPos(pos)).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 +949,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 +978,192 @@ 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)) - - protected def finalize(tree: Tree, copied: untpd.MemberDef): copied.ThisTree[T] = - postProcess(tree, copied.withPos(tree.pos).withAttachmentsFrom(tree)) + postProcess(tree, copied.withPosOf(tree).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 +1176,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) } diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 3fce069dd475..ec39ca1fc2d7 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)).withPosOf(tree) } } @@ -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).withPosOf(id) 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).withPosOf(rename).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..796c01e6ae5a 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.transientParam +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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam src: SourceFile) extends Tree with TermTree - case class SymbolLit(str: String) extends TermTree + case class SymbolLit(str: String)(implicit @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam 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 @transientParam src: SourceFile) extends OpTree + case class PostfixOp(od: Tree, op: Ident)(implicit @transientParam src: SourceFile) extends OpTree + case class PrefixOp(op: Ident, od: Tree)(implicit @transientParam 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 @transientParam src: SourceFile) extends ProxyTree { def forwardTo: Tree = t } - case class Tuple(trees: List[Tree]) extends Tree { + case class Tuple(trees: List[Tree])(implicit @transientParam 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 @transientParam src: SourceFile) extends TermTree + case class Quote(expr: Tree)(implicit @transientParam src: SourceFile) extends TermTree + case class DoWhile(body: Tree, cond: Tree)(implicit @transientParam src: SourceFile) extends TermTree + case class ForYield(enums: List[Tree], expr: Tree)(implicit @transientParam src: SourceFile) extends TermTree + case class ForDo(enums: List[Tree], body: Tree)(implicit @transientParam src: SourceFile) extends TermTree + case class GenFrom(pat: Tree, expr: Tree)(implicit @transientParam src: SourceFile) extends Tree + case class GenAlias(pat: Tree, expr: Tree)(implicit @transientParam src: SourceFile) extends Tree + case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree])(implicit @transientParam src: SourceFile) extends TypTree + case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree)(implicit @transientParam src: SourceFile) extends DefTree + case class DependentTypeTree(tp: List[Symbol] => Type)(implicit @transientParam 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 @transientParam 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 @transientParam src: SourceFile) + extends Positioned object Mod { - case class Private() extends Mod(Flags.Private) + case class Private()(implicit @transientParam src: SourceFile) extends Mod(Flags.Private) - case class Protected() extends Mod(Flags.Protected) + case class Protected()(implicit @transientParam src: SourceFile) extends Mod(Flags.Protected) - case class Var() extends Mod(Flags.Mutable) + case class Var()(implicit @transientParam src: SourceFile) extends Mod(Flags.Mutable) - case class Implicit() extends Mod(Flags.ImplicitCommon) + case class Implicit()(implicit @transientParam src: SourceFile) extends Mod(Flags.ImplicitCommon) - case class Erased() extends Mod(Flags.Erased) + case class Erased()(implicit @transientParam src: SourceFile) extends Mod(Flags.Erased) - case class Final() extends Mod(Flags.Final) + case class Final()(implicit @transientParam src: SourceFile) extends Mod(Flags.Final) - case class Sealed() extends Mod(Flags.Sealed) + case class Sealed()(implicit @transientParam src: SourceFile) extends Mod(Flags.Sealed) - case class Opaque() extends Mod(Flags.Opaque) + case class Opaque()(implicit @transientParam src: SourceFile) extends Mod(Flags.Opaque) - case class Override() extends Mod(Flags.Override) + case class Override()(implicit @transientParam src: SourceFile) extends Mod(Flags.Override) - case class Abstract() extends Mod(Flags.Abstract) + case class Abstract()(implicit @transientParam src: SourceFile) extends Mod(Flags.Abstract) - case class Lazy() extends Mod(Flags.Lazy) + case class Lazy()(implicit @transientParam src: SourceFile) extends Mod(Flags.Lazy) - case class Inline() extends Mod(Flags.Inline) + case class Inline()(implicit @transientParam src: SourceFile) extends Mod(Flags.Inline) - case class Enum() extends Mod(Flags.Enum) + case class Enum()(implicit @transientParam 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 @transientParam 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).withPosOf(tpt) (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..1a8149edb40f 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,12 +112,12 @@ 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) tree match { @@ -125,7 +125,7 @@ object Comments { 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..48fd7ebeaceb 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,34 @@ 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)) + if (f.isDirectory) { + error(s"expected file, received directory '$path'") + NoSource + } + else if (f.exists) { + val src = getSource(f) + base.sourceNamed(path) = src + src + } + else { + error(s"not found: $path") + NoSource + } + } + + /** 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 +417,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 +435,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 +447,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 +500,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 +533,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 +609,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 +617,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 +677,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 +758,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..905a5d66bc5f 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.Position 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 a3f4191b7af1..1363b50b2965 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.transientParam") + 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/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 1f849ccd3e65..9e4ec7a66d01 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 @@ -159,7 +159,7 @@ object SymbolLoaders { Nil) } - val unit = new CompilationUnit(ctx.run.getSource(src.path)) + val unit = new 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..7d2e5f5c643f 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, Position} 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) 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,18 @@ 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 pos(implicit ctx: Context): Position = { + 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 +763,30 @@ 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..9bd18219ae2a 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.Position import NameKinds.DepParamName import Decorators._ import StdNames._ diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 80377807dedc..3111ce846444 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..6f9db78cef17 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) @@ -140,7 +140,7 @@ 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(_.withPosOf(tree)).getOrElse(tree) ).transform(ddef.rhs) case Block(stats, expr) => seq(stats, rec(expr)) 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..981aa5c3202a 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) @@ -24,33 +26,51 @@ class PositionPickler(pickler: TastyPickler, addrOfTree: untpd.Tree => Option[Ad (addrDelta << 3) | (toInt(hasStartDelta) << 2) | (toInt(hasEndDelta) << 1) | toInt(hasPoint) } + /** The result type of `matchDegree`, which encodes the kind of match between + * the position of a Positioned item and the inferred position computed by Positioned#setInitialPos. + */ + private type MatchDegree = Int + private final val Unknown = 0 // Nothing known yet + private final val StartMatch = 1 // We know that at least one element matches `start` + private final val EndMatch = 2 // We know that at least one element matches `end` + private final val SourceMatch = 4 // We know that the first element matches `source` + private final val SpanMismatch = 8 // We know that the span is different from initialSpan + private final val SourceMismatch = 16 // We know the source is different from the first element + private final val SpanMatch = StartMatch | EndMatch + private final val AllMatch = SpanMatch | SourceMatch + 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[_] @@ -59,31 +79,108 @@ class PositionPickler(pickler: TastyPickler, addrOfTree: untpd.Tree => Option[Ad case _ => false } - def traverse(x: Any): Unit = x match { + //val msgs = new mutable.ListBuffer[String] + + /** The degree to which the source position of `x` matches the initial position computed + * from its elements. + * @pre The span of `x` exists + */ + def matchDegree(x: Positioned): MatchDegree = { + val src = x.source + val start = x.span.start + val end = x.span.end + + def checkElem(acc: MatchDegree, elem: Any): MatchDegree = elem match { + case _: Trees.TypeTree[_] => + // TypeTrees contribute nothing since they are pickled as types + acc + case elem: Positioned => + val espan = elem.span + if (!espan.exists) acc // elements without position don't contribute + else { + val esrc = elem.source + if (!esrc.exists) acc // elements without source don't contribute + else if (esrc `ne` src) + if ((acc & SourceMatch) == 0) SourceMismatch // first element source is different -> no match + else acc // subsequent elements with different source don't contribute + else { + var matches = acc | SourceMatch + val estart = espan.start + val eend = espan.end + if (estart == start) matches |= StartMatch + if (eend == end) matches |= EndMatch + if (estart < start || eend > end) matches |= SpanMismatch + matches + } + } + case elem: List[_] => + checkElems(acc, elem) + case m: untpd.Modifiers => + checkElems(checkElems(acc, m.mods), m.annotations) + case _ => + acc + } + def checkElems(acc: MatchDegree, elems: List[Any]): MatchDegree = elems match { + case elem :: elems1 => checkElems(checkElem(acc, elem), elems1) + case nil => acc + } + + val limit = x.relevantElemCount + var n = 0 + var acc: MatchDegree = Unknown + while (n < limit) { + acc = checkElem(acc, x.productElement(n)) + n += 1 + } + acc + } + + 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))) { - addrOfTree(x) match { - case Some(addr) if !pickledIndices.contains(addr.index) => - //println(i"pickling $x with $pos at $addr") - pickleDeltas(addr.index, pos) - case _ => - //println(i"no address for $x") + var sourceFile = current + if (x.span.exists) { + val mdegree = matchDegree(x) + val sourceChange = + mdegree == SourceMismatch || // source different from initial source, or + (mdegree & SourceMatch) == 0 && // initial source unknown, and + (x.source `ne` current) // source different from context + val needPos = + (mdegree & SpanMismatch) != 0 || // initial span exceeds current in some direction, or + (mdegree & SpanMatch) != SpanMatch || // initial span smaller than current, or + sourceChange || // source needs to be specified, or + alwaysNeedsPos(x) // always needs position anyway + if (needPos) { + addrOfTree(x) match { + case Some(addr) if !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 (x.source != current) { + pickleSource(x.source) + sourceFile = x.source + } + case _ => + //println(i"no address for $x") + } } } - //else if (x.pos.exists) println(i"skipping $x") + //else if (x.span.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, sourceFile) case _ => } - traverse(x.productIterator) + traverse(x.productIterator, sourceFile) 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..7e956cc411d2 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 myPositions: mutable.HashMap[Addr, Span] = _ + private var mySourcePaths: mutable.HashMap[Addr, String] = _ + private var isDefined = false + + def ensureDefined(): Unit = + if (!isDefined) { + myPositions = 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() + myPositions(Addr(curIndex)) = + if (hasPoint) Span(curStart, curEnd, curStart + readInt()) + else Span(curStart, curEnd) + } + } + isDefined = true } - positions + + private[tasty] def positions: Map[Addr, Span] = { + ensureDefined() + myPositions + } + + private[tasty] def sourcePaths: Map[Addr, String] = { + ensureDefined() + mySourcePaths } - def posAt(addr: Addr): Position = positions.getOrElse(addr, NoPosition) + def posAt(addr: Addr): Span = positions.getOrElse(addr, NoSpan) + def sourcePathAt(addr: Addr): String = sourcePaths.getOrElse(addr, "") } 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..00a453c65a28 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -218,14 +218,19 @@ 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 + +All elements of a position section are serialized as Ints Standard Section: "Comments" Comment* @@ -272,7 +277,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..bc4cf6e4e405 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,7 +129,7 @@ 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 positions = new PositionUnpickler(reader, tastyName).positions sb.append(s" position bytes:\n") val sorted = positions.toSeq.sortBy(_._1.index) for ((addr, pos) <- sorted) { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 950863fa565f..2513e7c0efb8 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.transientParam 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 @transientParam 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( diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index bc8a8cc53595..548cdc8aad1b 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.transientParam 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,21 @@ class TreeUnpickler(reader: TastyReader, } } - class Completer(owner: Symbol, reader: TastyReader) extends LazyType { + class Completer(reader: TastyReader)(implicit @transientParam ctx: Context) extends LazyType { import reader._ + val owner = ctx.owner + val source = ctx.source def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { + val sourceToUse = if (source.exists) source else ctx.source + // TODO: remove. This is a hack to get pickling tests (notable tuple-cons-2.scala + // to pass. The problem is that without a bootstrapped library some unpicked + // files are lacking a source, and if these are completed from Definitions + // there's also no external source given in `context`. In that case we switch + // late and pick the calling context's source. We can drop this hack once + // all Tasty trees have a SOURCE entry, which will determine the context source treeAtAddr(currentAddr) = new TreeReader(reader).readIndexedDef()( - ctx.withPhaseNoLater(ctx.picklerPhase).withOwner(owner)) + ctx.withPhaseNoLater(ctx.picklerPhase).withOwner(owner).withSource(sourceToUse)) } } @@ -278,7 +282,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 +551,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 +575,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 +701,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 +748,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() @@ -866,6 +875,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) @@ -951,6 +961,7 @@ class TreeUnpickler(reader: TastyReader, def readImport()(implicit ctx: Context): Tree = { val start = currentAddr + assert(sourcePathAt(start).isEmpty) readByte() readEnd() val expr = readTerm() @@ -960,6 +971,7 @@ class TreeUnpickler(reader: TastyReader, 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())) nextByte match { @@ -994,9 +1006,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 +1031,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).withPosOf(qual), qual.tpe.asInstanceOf[TypeRef]) } def accessibleDenot(pre: Type, name: Name, sig: Signature) = { @@ -1235,6 +1249,8 @@ 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() @@ -1250,7 +1266,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 = { @@ -1273,21 +1289,44 @@ class TreeUnpickler(reader: TastyReader, // ------ Setting positions ------------------------------------------------ /** Pickled position for `addr`. */ - def posAt(addr: Addr)(implicit ctx: Context): Position = + def posAt(addr: Addr)(implicit ctx: Context): Span = if (ctx.mode.is(Mode.ReadPositions)) { posUnpicklerOpt match { case Some(posUnpickler) => posUnpickler.posAt(addr) case _ => - NoPosition + NoSpan + } + } else NoSpan + + /** 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 NoPosition + } 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 + } /** Coordinate for the symbol at `addr`. */ def coordAt(addr: Addr)(implicit ctx: Context): Coord = { val pos = posAt(addr) if (pos.exists) - positionCoord(pos) + spanCoord(pos) else indexCoord(addr.index) } @@ -1295,15 +1334,21 @@ class TreeUnpickler(reader: TastyReader, /** 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) + if (pos.exists) tree.setOnePos(pos, ctx.source) 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 +1430,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/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/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala index d740d4098e3e..169167f9b2a1 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala @@ -16,7 +16,7 @@ import dotty.tools.dotc.core.StdNames.{nme, tpnme} import dotty.tools.dotc.core.TypeError import dotty.tools.dotc.core.Types.{NameFilter, NamedType, Type, NoType} import dotty.tools.dotc.printing.Texts._ -import dotty.tools.dotc.util.{NoSourcePosition, SourcePosition} +import dotty.tools.dotc.util.{NoPosition, Position} import scala.collection.mutable @@ -39,8 +39,8 @@ 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) + def completions(pos: Position)(implicit ctx: Context): (Int, List[Completion]) = { + val path = Interactive.pathTo(ctx.compilationUnit.tpdTree, pos.span) computeCompletions(pos, path)(Interactive.contextOfPath(path)) } @@ -54,7 +54,7 @@ object Completion { * * Otherwise, provide no completion suggestion. */ - private def completionMode(path: List[Tree], pos: SourcePosition): Mode = { + private def completionMode(path: List[Tree], pos: Position): Mode = { path match { case (ref: RefTree) :: _ => if (ref.name.isTermName) Mode.Term @@ -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(_, _) :: _ => @@ -77,19 +77,19 @@ object Completion { * Inspect `path` to determine the completion prefix. Only symbols whose name start with the * returned prefix should be considered. */ - private def completionPrefix(path: List[Tree], pos: SourcePosition): String = { + private def completionPrefix(path: List[Tree], pos: Position): String = { path match { case Thicket(name :: _ :: Nil) :: (_: Import) :: _ => 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,19 +99,19 @@ 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 } } /** Create a new `CompletionBuffer` for completing at `pos`. */ - private def completionBuffer(path: List[Tree], pos: SourcePosition): CompletionBuffer = { + private def completionBuffer(path: List[Tree], pos: Position): CompletionBuffer = { val mode = completionMode(path, pos) val prefix = completionPrefix(path, pos) new CompletionBuffer(mode, prefix, pos) } - private def computeCompletions(pos: SourcePosition, path: List[Tree])(implicit ctx: Context): (Int, List[Completion]) = { + private def computeCompletions(pos: Position, path: List[Tree])(implicit ctx: Context): (Int, List[Completion]) = { val offset = completionOffset(path) val buffer = completionBuffer(path, pos) @@ -135,7 +135,7 @@ object Completion { (offset, completionList) } - private class CompletionBuffer(val mode: Mode, val prefix: String, pos: SourcePosition) { + private class CompletionBuffer(val mode: Mode, val prefix: String, pos: Position) { private[this] val completions = new RenameAwareScope @@ -309,7 +309,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..6abf97bcc010 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.Position import core.Denotations.SingleDenotation import NameKinds.SimpleNameKind import config.Printers.interactiv @@ -70,7 +70,7 @@ object Interactive { tree.isInstanceOf[DefTree with NameTree] /** The type of the closest enclosing tree with a type containing position `pos`. */ - def enclosingType(trees: List[SourceTree], pos: SourcePosition)(implicit ctx: Context): Type = { + def enclosingType(trees: List[SourceTree], pos: Position)(implicit ctx: Context): Type = { val path = pathTo(trees, pos) if (path.isEmpty) NoType else path.head.tpe @@ -78,7 +78,7 @@ object Interactive { /** The closest enclosing tree with a symbol containing position `pos`, or the `EmptyTree`. */ - def enclosingTree(trees: List[SourceTree], pos: SourcePosition)(implicit ctx: Context): Tree = + def enclosingTree(trees: List[SourceTree], pos: Position)(implicit ctx: Context): Tree = enclosingTree(pathTo(trees, pos)) /** The closes enclosing tree with a symbol, or the `EmptyTree`. @@ -97,7 +97,7 @@ object Interactive { * * @see sourceSymbol */ - def enclosingSourceSymbols(path: List[Tree], pos: SourcePosition)(implicit ctx: Context): List[Symbol] = { + def enclosingSourceSymbols(path: List[Tree], pos: Position)(implicit ctx: Context): List[Symbol] = { val syms = path match { // For a named arg, find the target `DefDef` and jump to the param case NamedArg(name, _) :: Apply(fn, _) :: _ => @@ -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) @@ -250,15 +250,15 @@ object Interactive { * or `Nil` if no such path exists. If a non-empty path is returned it starts with * the tree closest enclosing `pos` and ends with an element of `trees`. */ - def pathTo(trees: List[SourceTree], pos: SourcePosition)(implicit ctx: Context): List[Tree] = + def pathTo(trees: List[SourceTree], pos: Position)(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 @@ -332,7 +332,7 @@ object Interactive { * @param driver The driver responsible for `path`. * @return The definitions for the symbol at the end of `path`. */ - def findDefinitions(path: List[Tree], pos: SourcePosition, driver: InteractiveDriver): List[SourceTree] = { + def findDefinitions(path: List[Tree], pos: Position, driver: InteractiveDriver): List[SourceTree] = { implicit val ctx = driver.currentCtx val enclTree = enclosingTree(path) val includeOverridden = enclTree.isInstanceOf[MemberDef] diff --git a/compiler/src/dotty/tools/dotc/interactive/SourceTree.scala b/compiler/src/dotty/tools/dotc/interactive/SourceTree.scala index 3c8a51617723..f2017187b99c 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,15 +17,15 @@ 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): Position = source.atSpan(tree.span) /** The position of the name in `tree` */ - def namePos(implicit ctx: Context): SourcePosition = tree match { + def namePos(implicit ctx: Context): Position = tree match { case tree: tpd.NameTree => // FIXME: Merge with NameTree#namePos ? - val treePos = tree.pos - if (treePos.isZeroExtent || tree.name.toTermName == nme.ERROR) - NoSourcePosition + val treeSpan = tree.span + if (treeSpan.isZeroExtent || tree.name.toTermName == nme.ERROR) + NoPosition else { // Constructors are named `` in the trees, but `this` in the source. val nameLength = tree.name match { @@ -36,24 +36,24 @@ 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 + NoPosition } } 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..4980cb43b191 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.withPosOf(tree) case _ => tree match { case AppliedTypeTree(_, _) | Select(_, _) => tree case _ => - syntaxError(IdentifierExpected(tree.show), tree.pos) + syntaxError(IdentifierExpected(tree.show), tree.span) errorTypeTree } } @@ -248,14 +248,14 @@ object JavaParsers { var t: RefTree = atPos(in.offset) { Ident(ident()) } while (in.token == DOT) { in.nextToken() - t = atPos(t.pos.start, in.offset) { Select(t, ident()) } + t = atPos(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 = atPos(tpt.span.start, in.offset) { arrayOf(tpt) } in.nextToken() accept(RBRACKET) optArrayBrackets(tpt1) @@ -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(atPos(t.span.start, in.offset)(typeSelect(t, ident()))) } convertToTypeId(t) } else { @@ -323,7 +323,7 @@ object JavaParsers { val t1 = convertToTypeId(t) val args = repsep(() => typeArg(), COMMA) acceptClosingAngle() - atPos(t1.pos.start) { + atPos(t1.span.start) { AppliedTypeTree(t1, args) } } else t @@ -445,7 +445,7 @@ object JavaParsers { var t = typ() if (in.token == DOTDOTDOT) { in.nextToken() - t = atPos(t.pos.start) { + t = atPos(t.span.start) { PostfixOp(t, Ident(tpnme.raw.STAR)) } } @@ -596,14 +596,14 @@ object JavaParsers { } def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree = - atPos(cdef.pos) { - assert(cdef.pos.exists) + atPos(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,9 +660,9 @@ 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)) } @@ -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) @@ -895,7 +895,7 @@ 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) } } diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 541b50bf4079..cc6fd22aee78 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -5,7 +5,7 @@ package parsing import scala.annotation.internal.sharable import scala.collection.mutable.ListBuffer import scala.collection.immutable.BitSet -import util.{ SourceFile, SourcePosition } +import util.{ SourceFile, Position } import Tokens._ import Scanners._ import xml.MarkupParsers.MarkupParser @@ -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._ @@ -71,17 +71,17 @@ object Parsers { /** Positions tree. * If `t` does not have a position yet, set its position to the given one. */ - def atPos[T <: Positioned](pos: Position)(t: T): T = - if (t.pos.isSourceDerived) t else t.withPos(pos) + def atPos[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) + atPos(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 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 + * but wait for its position to be determined by `setChildSpans` when the * parent node is positioned. */ def atPos[T <: Positioned](start: Offset, point: Offset)(t: T): T = @@ -91,19 +91,19 @@ object Parsers { atPos(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) + def sourcePos(off: Int = in.offset): Position = + source.atSpan(Span(off)) /* ------------- ERROR HANDLING ------------------------------------------- */ /** The offset where the last syntax error was reported, or if a skip to a @@ -117,15 +117,15 @@ object Parsers { def syntaxError(msg: => Message, offset: Int = in.offset): Unit = if (offset > lastErrorOffset) { val length = if (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) + def syntaxError(msg: => Message, span: Span): Unit = + ctx.error(msg, source.atSpan(span)) } trait OutlineParserCommon extends ParserCommon { @@ -259,18 +259,18 @@ object Parsers { } } - def warning(msg: => Message, sourcePos: SourcePosition): Unit = + def warning(msg: => Message, sourcePos: Position): Unit = 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. @@ -349,7 +349,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) @@ -367,11 +367,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).withPosOf(tree) case Typed(Ident(name), tpt) => - makeParameter(name.asTermName, tpt, mods) withPos tree.pos + makeParameter(name.asTermName, tpt, mods).withPosOf(tree) case _ => - syntaxError(s"not a legal $expected", tree.pos) + syntaxError(s"not a legal $expected", tree.span) makeParameter(nme.ERROR, tree, mods) } @@ -383,7 +383,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 } @@ -401,7 +401,7 @@ object Parsers { try op finally { placeholderParams match { - case vd :: _ => syntaxError(UnboundPlaceholderParameter(), vd.pos) + case vd :: _ => syntaxError(UnboundPlaceholderParameter(), vd.span) case _ => } placeholderParams = savedPlaceholderParams @@ -480,7 +480,7 @@ object Parsers { if (prec < opPrec || leftAssoc && prec == opPrec) { opStack = opStack.tail recur { - atPos(opInfo.operator.pos union opInfo.operand.pos union top.pos) { + atPos(opInfo.operator.span union opInfo.operand.span union top.span) { val op = opInfo.operator val l = opInfo.operand val r = top @@ -602,7 +602,7 @@ object Parsers { def handleThis(qual: Ident) = { in.nextToken() val t = atPos(start) { This(qual) } - if (!thisOK && in.token != DOT) syntaxError(DanglingThisInPath(), t.pos) + if (!thisOK && in.token != DOT) syntaxError(DanglingThisInPath(), t.span) dotSelectors(t, finish) } def handleSuper(qual: Ident) = { @@ -663,8 +663,8 @@ object Parsers { 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) } } @@ -708,7 +708,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 } }) @@ -797,7 +797,7 @@ 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 @@ -832,8 +832,8 @@ 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) { @@ -903,7 +903,7 @@ object Parsers { 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)) } @@ -1011,7 +1011,7 @@ 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 atPos((t.span union cbs.head.span).start) { ContextBounds(t, cbs) } } def contextBounds(pname: TypeName): List[Tree] = in.token match { @@ -1030,7 +1030,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() @@ -1052,7 +1052,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 } @@ -1069,9 +1069,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 @@ -1184,9 +1184,9 @@ object Parsers { 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 { @@ -1194,7 +1194,7 @@ object Parsers { assert(handlerStart != -1) syntaxError( EmptyCatchBlock(body), - Position(handlerStart, endOffset(handler)) + Span(handlerStart, endOffset(handler)) ) case _ => } @@ -1204,7 +1204,7 @@ object Parsers { else { if (handler.isEmpty) warning( EmptyCatchAndFinallyBlock(body), - source atPos Position(tryOffset, endOffset(body)) + source.atSpan(Span(tryOffset, endOffset(body))) ) EmptyTree } @@ -1270,7 +1270,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) } @@ -1300,7 +1300,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 { @@ -1315,7 +1315,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 } @@ -1323,7 +1323,7 @@ object Parsers { /** `match' { TypeCaseClauses } */ def matchType(bound: Tree, t: Tree): MatchTypeTree = - atPos((if (bound.isEmpty) t else bound).pos.start, accept(MATCH)) { + atPos((if (bound.isEmpty) t else bound).span.start, accept(MATCH)) { inBraces(MatchTypeTree(bound, t, caseClauses(typeCaseClause))) } @@ -1347,8 +1347,8 @@ 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 } @@ -1425,7 +1425,7 @@ 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) } case LPAREN => @@ -1449,9 +1449,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() @@ -1738,8 +1738,8 @@ 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) + atPos(wildIndent.span) { Ident(tpnme.WILDCARD_STAR) } } else wildIndent case LPAREN => atPos(in.offset) { makeTupleOrParens(inParens(patternsOpt())) } @@ -1892,8 +1892,8 @@ object Parsers { 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 } @@ -1935,7 +1935,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 @@ -1946,7 +1946,6 @@ object Parsers { else EmptyFlags else EmptyFlags } - } atPos(start, nameStart) { val name = if (isConcreteOwner || in.token != USCORE) ident().toTypeName @@ -1984,35 +1983,33 @@ 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 = 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 } } else { if (isIdent(nme.inline) && in.isSoftModifierInParamModifierPosition) mods = addModifier(mods) - mods = atPos(start) { mods | Param } + mods |= Param } atPos(start, nameStart) { val name = ident() @@ -2023,9 +2020,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) } @@ -2037,7 +2033,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) @@ -2048,18 +2044,16 @@ object Parsers { if (in.token == RPAREN && !prefix) Nil else { def funArgMods(mods: Modifiers): Modifiers = - if (in.token == IMPLICIT) { - implicitOffset = in.offset + if (in.token == IMPLICIT) funArgMods(addMod(mods, atPos(accept(IMPLICIT)) { Mod.Implicit() })) - } else if (in.token == ERASED) funArgMods(addMod(mods, atPos(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 } @@ -2102,9 +2096,9 @@ object Parsers { case t :: rest => // The first import should start at the position 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 } } @@ -2165,9 +2159,8 @@ object Parsers { } def posMods(start: Int, mods: Modifiers): Modifiers = { - val mods1 = atPos(start)(mods) in.nextToken() - mods1 + mods } /** Def ::= val PatDef @@ -2236,7 +2229,7 @@ object Parsers { 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 } } @@ -2557,8 +2550,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) @@ -2595,11 +2590,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).withPosOf(first) 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).withPosOf(first) } in.nextToken() } else { @@ -2642,7 +2637,7 @@ object Parsers { } if (isLegal) tree :: Nil else { - syntaxError("illegal refinement", tree.pos) + syntaxError("illegal refinement", tree.span) Nil } } @@ -2718,7 +2713,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..0513967ccc3e 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) + ).withPosOf(tree) 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..4469d309a461 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. @@ -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 } + atPos(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 = + atPos(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 = atPos(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 = atPos(span)( Comment(const(text)) ) + def charData(span: Span, txt: String): Tree = atPos(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 = + atPos(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)) ) + atPos(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 = + atPos(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 = + atPos(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) = atPos(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))) + atPos(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..3af0fef42787 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -8,7 +8,7 @@ import StdNames.nme import ast.Trees._ import typer.Implicits._ import typer.ImportInfo -import util.SourcePosition +import util.Position import java.lang.Integer.toOctalString import config.Config.summarizeDepth import scala.util.control.NonFatal @@ -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) @@ -505,10 +506,11 @@ class PlainPrinter(_ctx: Context) extends Printer { nodeName ~ "(" ~ elems ~ tpSuffix ~ ")" ~ (Str(tree.pos.toString) provided ctx.settings.YprintPos.value) }.close // todo: override in refined printer - def toText(pos: SourcePosition): Text = + def toText(pos: Position): 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/Printer.scala b/compiler/src/dotty/tools/dotc/printing/Printer.scala index e0820d11119f..eb349bfdff4c 100644 --- a/compiler/src/dotty/tools/dotc/printing/Printer.scala +++ b/compiler/src/dotty/tools/dotc/printing/Printer.scala @@ -7,7 +7,7 @@ import Texts._, ast.Trees._ import Types.Type, Symbols.Symbol, Scopes.Scope, Constants.Constant, Names.Name, Denotations._, Annotations.Annotation import typer.Implicits.SearchResult -import util.SourcePosition +import util.Position import typer.ImportInfo import scala.annotation.internal.sharable @@ -136,7 +136,7 @@ abstract class Printer { def toText[T >: Untyped](tree: Tree[T]): Text /** Textual representation of source position */ - def toText(pos: SourcePosition): Text + def toText(pos: Position): Text /** Textual representation of implicit search result */ def toText(result: SearchResult): Text diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 72ad6850a1ce..29331440df1e 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -24,7 +24,7 @@ import scala.tasty.util.Chars.isOperatorPart import transform.TypeUtils._ import language.implicitConversions -import dotty.tools.dotc.util.SourcePosition +import dotty.tools.dotc.util.Position import dotty.tools.dotc.ast.untpd.{MemberDef, Modifiers, PackageDef, RefTree, Template, TypeDef, ValOrDefDef} class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { @@ -598,11 +598,14 @@ 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.pos) ~ ">" 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 ~ @@ -643,7 +646,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { val str: Text = nameString(tree.symbol) tree match { case tree: RefTree => withPos(str, tree.pos) - case tree: MemberDef => withPos(str, tree.namePos) + case tree: MemberDef => withPos(str, tree.pos.withSpan(tree.nameSpan)) case _ => str } } @@ -838,7 +841,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { override def plain: PlainPrinter = new PlainPrinter(_ctx) - private def withPos(txt: Text, pos: SourcePosition): Text = { + private def withPos(txt: Text, pos: Position): Text = { if (!printLines || !pos.exists) txt else txt match { case Str(s, _) => Str(s, LineRange(pos.line, pos.endLine)) diff --git a/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala b/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala index 989a3804e23a..9c3b75a06b10 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 @@ -39,13 +39,13 @@ object SyntaxHighlighting { 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..529c18023687 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} @@ -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/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index c36f248d8a3a..e2fd7b994b3a 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -10,7 +10,7 @@ import printing.Highlighting.{Blue, Red} import printing.SyntaxHighlighting import diagnostic.{ErrorMessageID, Message, MessageContainer} import diagnostic.messages._ -import util.SourcePosition +import util.Position import scala.tasty.util.Chars.{ LF, CR, FF, SU } import scala.annotation.switch @@ -31,7 +31,7 @@ trait MessageRendering { * * @return a list of strings with inline locations */ - def outer(pos: SourcePosition, prefix: String)(implicit ctx: Context): List[String] = + def outer(pos: Position, prefix: String)(implicit ctx: Context): List[String] = if (pos.outer.exists) { i"$prefix| This location is in code that was inlined at ${pos.outer}" :: outer(pos.outer, prefix) @@ -42,7 +42,7 @@ trait MessageRendering { * * @return (lines before error, lines after error, line numbers offset) */ - def sourceLines(pos: SourcePosition)(implicit ctx: Context): (List[String], List[String], Int) = { + def sourceLines(pos: Position)(implicit ctx: Context): (List[String], List[String], Int) = { var maxLen = Int.MinValue def render(offsetAndLine: (Int, String)): String = { val (offset, line) = offsetAndLine @@ -78,7 +78,7 @@ trait MessageRendering { } /** The column markers aligned under the error */ - def columnMarker(pos: SourcePosition, offset: Int)(implicit ctx: Context): String = { + def columnMarker(pos: Position, offset: Int)(implicit ctx: Context): String = { val prefix = " " * (offset - 1) val padding = pos.startColumnPadding val carets = Red { @@ -93,7 +93,7 @@ trait MessageRendering { * * @return aligned error message */ - def errorMsg(pos: SourcePosition, msg: String, offset: Int)(implicit ctx: Context): String = { + def errorMsg(pos: Position, msg: String, offset: Int)(implicit ctx: Context): String = { val padding = msg.linesIterator.foldLeft(pos.startColumnPadding) { (pad, line) => val lineLength = stripColor(line).length val maxPad = math.max(0, ctx.settings.pageWidth.value - offset - lineLength) - offset @@ -111,7 +111,7 @@ trait MessageRendering { * * @return separator containing error location and kind */ - def posStr(pos: SourcePosition, diagnosticLevel: String, message: Message)(implicit ctx: Context): String = + def posStr(pos: Position, diagnosticLevel: String, message: Message)(implicit ctx: Context): String = if (pos.exists) Blue({ val file = s"${pos.source.file.toString}:${pos.line + 1}:${pos.column}" val errId = @@ -141,7 +141,7 @@ trait MessageRendering { } /** The whole message rendered from `msg` */ - def messageAndPos(msg: Message, pos: SourcePosition, diagnosticLevel: String)(implicit ctx: Context): String = { + def messageAndPos(msg: Message, pos: Position, diagnosticLevel: String)(implicit ctx: Context): String = { val sb = mutable.StringBuilder.newBuilder val posString = posStr(pos, diagnosticLevel, msg) if (posString.nonEmpty) sb.append(posString).append(EOL) diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index ad4a073e46fb..d7da4e1a4816 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -5,7 +5,7 @@ package reporting import scala.annotation.internal.sharable import core.Contexts._ -import util.{SourcePosition, NoSourcePosition} +import util.{Position, NoPosition} import core.Decorators.PhaseListDecorator import collection.mutable import java.lang.System.currentTimeMillis @@ -37,10 +37,10 @@ object Reporter { trait Reporting { this: Context => /** For sending messages that are printed only if -verbose is set */ - def inform(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + def inform(msg: => String, pos: Position = NoPosition): Unit = if (this.settings.verbose.value) this.echo(msg, pos) - def echo(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + def echo(msg: => String, pos: Position = NoPosition): Unit = reporter.report(new Info(msg, pos)) def reportWarning(warning: Warning): Unit = @@ -49,20 +49,20 @@ trait Reporting { this: Context => else reporter.report(warning) } - def deprecationWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def deprecationWarning(msg: => Message, pos: Position = NoPosition): Unit = if (this.settings.deprecation.value) reportWarning(new DeprecationWarning(msg, pos)) - def migrationWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def migrationWarning(msg: => Message, pos: Position = NoPosition): Unit = reportWarning(new MigrationWarning(msg, pos)) - def uncheckedWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def uncheckedWarning(msg: => Message, pos: Position = NoPosition): Unit = reportWarning(new UncheckedWarning(msg, pos)) - def featureWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def featureWarning(msg: => Message, pos: Position = NoPosition): Unit = reportWarning(new FeatureWarning(msg, pos)) def featureWarning(feature: String, featureDescription: String, isScala2Feature: Boolean, - featureUseSite: Symbol, required: Boolean, pos: SourcePosition): Unit = { + featureUseSite: Symbol, required: Boolean, pos: Position): Unit = { val req = if (required) "needs to" else "should" val prefix = if (isScala2Feature) "scala." else "dotty." val fqname = prefix + "language." + feature @@ -84,32 +84,32 @@ trait Reporting { this: Context => else reportWarning(new FeatureWarning(msg, pos)) } - def warning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def warning(msg: => Message, pos: Position = NoPosition): Unit = reportWarning(new Warning(msg, pos)) - def strictWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def strictWarning(msg: => Message, pos: Position = NoPosition): Unit = if (this.settings.strict.value) error(msg, pos) else reportWarning(new ExtendMessage(() => msg)(_ + "\n(This would be an error under strict mode)").warning(pos)) - def error(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def error(msg: => Message, pos: Position = NoPosition): Unit = reporter.report(new Error(msg, pos)) - def errorOrMigrationWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def errorOrMigrationWarning(msg: => Message, pos: Position = NoPosition): Unit = if (ctx.scala2Mode) migrationWarning(msg, pos) else error(msg, pos) - def restrictionError(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def restrictionError(msg: => Message, pos: Position = NoPosition): Unit = reporter.report { new ExtendMessage(() => msg)(m => s"Implementation restriction: $m").error(pos) } - def incompleteInputError(msg: => Message, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit = + def incompleteInputError(msg: => Message, pos: Position = NoPosition)(implicit ctx: Context): Unit = reporter.incomplete(new Error(msg, pos))(ctx) /** Log msg if settings.log contains the current phase. * See [[config.CompilerCommand#explainAdvanced]] for the exact meaning of * "contains" here. */ - def log(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + def log(msg: => String, pos: Position = NoPosition): Unit = if (this.settings.Ylog.value.containsPhase(phase)) echo(s"[log ${ctx.phasesStack.reverse.mkString(" -> ")}] $msg", pos) @@ -129,7 +129,7 @@ trait Reporting { this: Context => value } - def debugwarn(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + def debugwarn(msg: => String, pos: Position = NoPosition): Unit = if (this.settings.Ydebug.value) warning(msg, pos) } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala index 48c5deaaa9a2..193b8d6cf519 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala @@ -3,7 +3,7 @@ package dotc package reporting package diagnostic -import util.SourcePosition +import util.Position import messages._ @@ -91,31 +91,31 @@ class ExtendMessage(_msg: () => Message)(f: String => String) { self => } /** Enclose this message in an `Error` container */ - def error(pos: SourcePosition): Error = + def error(pos: Position): Error = new Error(toMessage, pos) /** Enclose this message in an `Warning` container */ - def warning(pos: SourcePosition): Warning = + def warning(pos: Position): Warning = new Warning(toMessage, pos) /** Enclose this message in an `Info` container */ - def info(pos: SourcePosition): Info = + def info(pos: Position): Info = new Info(toMessage, pos) /** Enclose this message in an `FeatureWarning` container */ - def featureWarning(pos: SourcePosition): FeatureWarning = + def featureWarning(pos: Position): FeatureWarning = new FeatureWarning(toMessage, pos) /** Enclose this message in an `UncheckedWarning` container */ - def uncheckedWarning(pos: SourcePosition): UncheckedWarning = + def uncheckedWarning(pos: Position): UncheckedWarning = new UncheckedWarning(toMessage, pos) /** Enclose this message in an `DeprecationWarning` container */ - def deprecationWarning(pos: SourcePosition): DeprecationWarning = + def deprecationWarning(pos: Position): DeprecationWarning = new DeprecationWarning(toMessage, pos) /** Enclose this message in an `MigrationWarning` container */ - def migrationWarning(pos: SourcePosition): MigrationWarning = + def migrationWarning(pos: Position): MigrationWarning = new MigrationWarning(toMessage, pos) } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala index a72775c854f3..c24b9918a43b 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala @@ -3,7 +3,7 @@ package dotc package reporting package diagnostic -import util.SourcePosition +import util.Position import core.Contexts.Context import java.util.Optional @@ -25,7 +25,7 @@ object MessageContainer { class MessageContainer( msgFn: => Message, - val pos: SourcePosition, + val pos: Position, val level: Int ) extends Exception with interfaces.Diagnostic { import MessageContainer._ diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index d18d2c9a15ea..2144f2aa50c0 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -10,7 +10,7 @@ import Symbols._ import Names._ import NameOps._ import Types._ -import util.SourcePosition +import util.Position import config.Settings.Setting import interfaces.Diagnostic.{ERROR, INFO, WARNING} import dotc.parsing.Scanners.Token @@ -31,52 +31,52 @@ object messages { // `MessageContainer`s to be consumed by `Reporter` ---------------------- // class Error( msgFn: => Message, - pos: SourcePosition + pos: Position ) extends MessageContainer(msgFn, pos, ERROR) class Warning( msgFn: => Message, - pos: SourcePosition + pos: Position ) extends MessageContainer(msgFn, pos, WARNING) { def toError: Error = new Error(msgFn, pos) } class Info( msgFn: => Message, - pos: SourcePosition + pos: Position ) extends MessageContainer(msgFn, pos, INFO) abstract class ConditionalWarning( msgFn: => Message, - pos: SourcePosition + pos: Position ) extends Warning(msgFn, pos) { def enablingOption(implicit ctx: Context): Setting[Boolean] } class FeatureWarning( msgFn: => Message, - pos: SourcePosition + pos: Position ) extends ConditionalWarning(msgFn, pos) { def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.feature } class UncheckedWarning( msgFn: => Message, - pos: SourcePosition + pos: Position ) extends ConditionalWarning(msgFn, pos) { def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.unchecked } class DeprecationWarning( msgFn: => Message, - pos: SourcePosition + pos: Position ) extends ConditionalWarning(msgFn, pos) { def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.deprecation } class MigrationWarning( msgFn: => Message, - pos: SourcePosition + pos: Position ) extends ConditionalWarning(msgFn, pos) { def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.migration } @@ -2103,7 +2103,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.pos.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..d31168b7d06a 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,22 +12,22 @@ 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) @@ -38,10 +38,10 @@ object Rewrites { 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/tastyreflect/ContextOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/ContextOpsImpl.scala index ef65bb4d9671..7d68510093da 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, Position} 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: Position = Position(rootContext.source, Spans.NoSpan) } diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala index 0682c5c5bbfe..40b5ac98f84d 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala @@ -115,7 +115,7 @@ trait CoreImpl extends scala.tasty.reflect.Core { type Signature = core.Signature - type Position = util.SourcePosition + type Position = util.Position type Constant = Constants.Constant diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala index 49b221a22947..fbcf34e3baa5 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala @@ -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..19cb531cb949 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala @@ -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).withPosOf(x), tpd.TypeTree(tpe.hi).withPosOf(x))) 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..cb621a059cf2 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.transientParam +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 @transientParam 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..11bc0b4109fe 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) + }.withPosOf(reference) /** Given a reference to a getter accessor, the corresponding setter reference */ def useSetter(getterRef: Tree)(implicit ctx: Context): Tree = getterRef match { 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..4cc83a7be5e6 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.Position /** A helper class for generating bridge methods in class `root`. */ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Context) { @@ -41,7 +42,7 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont private val bridgeTarget = newMutableSymbolMap[Symbol] def bridgePosFor(member: Symbol): Position = - if (member.owner == root && member.pos.exists) member.pos else root.pos + (if (member.owner == root && member.span.exists) member else root).pos /** 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..01e52707c872 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)).withPosOf(arg) } } diff --git a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala index 9f03c39f92ac..75a730f55ccf 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).withPosOf(vdef.tpt)) } else vdef } diff --git a/compiler/src/dotty/tools/dotc/transform/ClassOf.scala b/compiler/src/dotty/tools/dotc/transform/ClassOf.scala index 4938d4a993d2..31f15cfedd1c 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).withPosOf(tree) } else tree } diff --git a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala index 8942d7ae6fcb..a8545cc394ea 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.Position import dotty.tools.dotc.config.JavaPlatform class CollectEntryPoints extends MiniPhase { @@ -39,9 +39,9 @@ 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) + 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.pos // 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 diff --git a/compiler/src/dotty/tools/dotc/transform/Constructors.scala b/compiler/src/dotty/tools/dotc/transform/Constructors.scala index 78c440061db7..6286e41ddb12 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).withPosOf(tree) 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)).withPosOf(stat) 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.pos) 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)).withPosOf(tree) :: 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/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index bafea790faba..5c908a61bb76 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)).withPosOf(tree) final def box(tree: Tree, target: => String = "")(implicit ctx: Context): Tree = trace(i"boxing ${tree.showSummary}: ${tree.tpe} into $target") { tree.tpe.widen match { @@ -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).withPosOf(vdef.tpt))), 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).withPosOf(ddef.tpt)), 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..d871a550d314 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) @@ -166,11 +166,11 @@ class ExpandSAMs extends MiniPhase { } } - 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.pos) + 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..39f4bc768015 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).withPosOf(impl) case _ => parent } } @@ -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).withPosOf(fun) :: 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..e3f205504cb5 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).withPosOf(tree) case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index 6717b3499f05..7ec6a6856c53 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).withPosOf(ddef) .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).withPosOf(tree) (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..1dbaf4485c6b 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) + }).withPosOf(originalDef.rhs) } } diff --git a/compiler/src/dotty/tools/dotc/transform/GetClass.scala b/compiler/src/dotty/tools/dotc/transform/GetClass.scala index 77ba6d1b618d..0c82431e5f70 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).withPosOf(tree) case _ => tree } } diff --git a/compiler/src/dotty/tools/dotc/transform/Getters.scala b/compiler/src/dotty/tools/dotc/transform/Getters.scala index 60658f9bc460..f8c484f57ec5 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).withPosOf(tree) 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).withPosOf(tree) 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..05648e69692c 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).withPosOf(tree)).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)).withPosOf(tree) else if (sym.owner.isClass) // sym was lifted out - ref(sym).withPos(tree.pos) + ref(sym).withPosOf(tree) 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)).withPosOf(tree) 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)).withPosOf(tree) case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index 9cd22a639b7a..1f65f21da5e1 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.withPosOf(x) 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..572c6c3e3d0e 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).withPosOf(app) 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/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..bfeea8014611 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 = ( @@ -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).withPosOf(p)), 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..39a4d36fd10d 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).withPosOf(tree) else tree } diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index 138fe95114af..264c987d4424 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)).withPosOf(stat) } 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..956f98229117 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) diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index 0abee9001ba9..a265e52153e6 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) @@ -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..1d16d97fd3f9 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).withPosOf(tree).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).withPosOf(tree) 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) @@ -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) diff --git a/compiler/src/dotty/tools/dotc/transform/Splicer.scala b/compiler/src/dotty/tools/dotc/transform/Splicer.scala index 5bd039fb2629..b89291b09028 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicer.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicer.scala @@ -20,7 +20,7 @@ import dotty.tools.dotc.core.Constants.Constant import dotty.tools.dotc.tastyreflect.ReflectionImpl import scala.util.control.NonFatal -import dotty.tools.dotc.util.SourcePosition +import dotty.tools.dotc.util.Position import dotty.tools.repl.AbstractFileClassLoader import scala.reflect.ClassTag @@ -35,7 +35,7 @@ object Splicer { * * See: `Staging` */ - def splice(tree: Tree, pos: SourcePosition, classLoader: ClassLoader)(implicit ctx: Context): Tree = tree match { + def splice(tree: Tree, pos: Position, classLoader: ClassLoader)(implicit ctx: Context): Tree = tree match { case Quoted(quotedTree) => quotedTree case _ => val interpreter = new Interpreter(pos, classLoader) @@ -71,7 +71,7 @@ object Splicer { } /** Tree interpreter that evaluates the tree */ - private class Interpreter(pos: SourcePosition, classLoader: ClassLoader)(implicit ctx: Context) extends AbstractInterpreter { + private class Interpreter(pos: Position, classLoader: ClassLoader)(implicit ctx: Context) extends AbstractInterpreter { type Result = Object @@ -108,7 +108,7 @@ object Splicer { protected def interpretTastyContext()(implicit env: Env): Object = { new ReflectionImpl(ctx) { - override def rootPosition: SourcePosition = pos + override def rootPosition: Position = pos } } @@ -266,7 +266,7 @@ object Splicer { } /** Exception that stops interpretation if some issue is found */ - private class StopInterpretation(val msg: String, val pos: SourcePosition) extends Exception + private class StopInterpretation(val msg: String, val pos: Position) extends Exception } diff --git a/compiler/src/dotty/tools/dotc/transform/Staging.scala b/compiler/src/dotty/tools/dotc/transform/Staging.scala index 6a04d9bc01fa..48a65d68c012 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.Position import tasty.TreePickler.Hole import SymUtils._ import NameKinds._ @@ -16,7 +17,7 @@ import scala.collection.mutable import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.core.quoted._ import dotty.tools.dotc.typer.Inliner -import dotty.tools.dotc.util.SourcePosition +import dotty.tools.dotc.util.Position /** Translates quoted terms and types to `unpickle` method calls. @@ -264,7 +265,7 @@ class Staging extends MacroTransformWithImplicits { 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""" @@ -314,11 +315,11 @@ class Staging extends MacroTransformWithImplicits { tp } case tp: NamedType => - check(tp.symbol, tp, pos) + check(tp.symbol, tp, tp.symbol.pos) if (!tp.symbol.is(Param)) foldOver(acc, tp) case tp: ThisType => - check(tp.cls, tp, pos) + check(tp.cls, tp, tp.cls.pos) foldOver(acc, tp) case _ => foldOver(acc, tp) @@ -386,7 +387,7 @@ class Staging extends MacroTransformWithImplicits { 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) + pickledQuote(body2, splices, body.tpe, isType).withPosOf(quote) } else { // In top-level splice in an inline def. Keep the tree as it is, it will be transformed at inline site. @@ -438,18 +439,18 @@ 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).withPosOf(splice) // 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 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: Position = spliceCtx.source.atSpan(enclosingInlineds.head.span) + val evaluatedSplice = Splicer.splice(splice.qualifier, pos, macroClassLoader)(spliceCtx).withPosOf(splice) if (ctx.reporter.hasErrors) splice else transform(evaluatedSplice) } else if (!ctx.owner.isInlineMethod) { // level 0 outside an inline method @@ -461,7 +462,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.pos) splice } } @@ -576,7 +579,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_~).withPosOf(tree)) case tree: Select if tree.symbol.isSplice => splice(tree) case tree: RefTree if tree.symbol.is(Inline) && tree.symbol.is(Param) => diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index d647127a68c3..3e6ae7f4c3ba 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.pos) + else accDefs(clazz) += DefDef(acc, EmptyTree).withSpan(accRange) acc } - This(clazz).select(superAcc).withPos(sel.pos) + This(clazz).select(superAcc).withPosOf(sel) } /** Check selection `super.f` for conforming to rules. If necessary, @@ -121,7 +123,6 @@ class SuperAccessors(thisPhase: DenotTransformer) { ctx.error( s"${sym.showLocated} cannot be directly accessed from ${clazz} because ${overriding.owner} redeclares it as abstract", sel.pos) - } 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..f9eca4c7d946 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -117,8 +117,8 @@ 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. @@ -285,7 +285,7 @@ class TailRec extends MiniPhase { ctx.error(s"Cannot rewrite recursive call: $reason", tree.pos) } 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)).withPosOf(tree)) }).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.withPosOf(tree), 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..9a4e89f5b6a6 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).withPosOf(arg) 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/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..ee503258e96e 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).withPosOf(expr), List(TypeTree(tp))) def effectiveClass(tp: Type): Symbol = if (tp.isRef(defn.PairClass)) effectiveClass(erasure(tp)) @@ -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).withPosOf(tree) case OrType(tp1, tp2) => evalOnce(expr) { e => transformTypeTest(e, tp1, flagUnrelated = false) @@ -273,7 +273,7 @@ object TypeTestsCasts { if (sym.isTypeTest) { val argType = tree.args.head.tpe - if (!checkable(expr.tpe, argType, tree.pos)) + if (!checkable(expr.tpe, argType, tree.span)) ctx.warning(i"the type test for $argType cannot be checked at runtime", tree.pos) transformTypeTest(expr, tree.args.head.tpe, flagUnrelated = true) } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 438249f89124..a53e25b4f596 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.{Position, NoPosition, 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.transientParam 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: Position)(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,8 +49,8 @@ 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: Position = NoPosition)(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 @@ -58,7 +60,7 @@ object Applications { 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: Position)(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: Position = NoPosition)(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: Position)(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: Position)(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,20 +169,20 @@ 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 @transientParam src: SourceFile) extends tpd.Tree { + override def span = app.span def canEqual(that: Any): Boolean = app.canEqual(that) def productArity: Int = app.productArity def productElement(n: Int): Any = app.productElement(n) } - + /** The unapply method of this extractor also recognizes ExtMethodApplys in closure blocks. * This is necessary to deal with closures as left arguments of extension method 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._ @@ -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.withPosOf(normalizedFun), normalizedFun)), formal) matchArgs(args1, formals1.mapconserve(substParam), n + 1) } @@ -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).withPosOf(tree) .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).withPosOf(tree) 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 @@ -1085,7 +1086,7 @@ 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()).withPosOf(tree) } else if (argTypes.lengthCompare(1) == 0 && args.lengthCompare(1) > 0 && ctx.canAutoTuple) untpd.Tuple(args) :: Nil @@ -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) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 8293e0a99ee0..063eda696125 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.Position import transform.SymUtils._ import Decorators._ import ErrorReporting.{err, errorType} @@ -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.pos) 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.pos) 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.pos) } 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.pos) } /** A type map which checks that the only cycles in a type are F-bounds @@ -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,7 +350,7 @@ object Checking { } catch { case ex: RecursionOverflow => - ctx.error(em"cyclic reference involving type $name", pos) + ctx.error(em"cyclic reference involving type $name", posd.pos) false } } @@ -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. */ @@ -578,8 +578,8 @@ trait Checking { } /** 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.pos) /** Check that all type members of `tp` have realizable bounds */ def checkRealizableBounds(cls: Symbol, pos: Position)(implicit ctx: Context): Unit = { @@ -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.pos) + 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.pos) defn.ObjectType } @@ -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.pos) } /** Issue a feature warning if feature is not enabled */ @@ -873,7 +873,7 @@ 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) @@ -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.pos) } /** Check that all case classes that extend `scala.Enum` are `enum` cases */ @@ -994,12 +994,12 @@ 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 checkImplicitConversionUseOK(sym: Symbol, posd: Positioned)(implicit ctx: Context): Unit = () override def checkFeasibleParent(tp: Type, pos: Position, 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 = () @@ -1011,6 +1011,6 @@ trait NoChecking extends ReChecking { override def checkCaseInheritance(parentSym: Symbol, caseCls: ClassSymbol, pos: Position)(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 checkInInlineContext(what: String, posd: Positioned)(implicit ctx: Context): Unit = () override def checkFeature(base: ClassSymbol, name: TermName, description: => String, featureUseSite: Symbol, pos: Position)(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..6abb764b4ffc 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)).withPosOf(fun), (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..32c34d8be708 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.Position import java.util.regex.Matcher.quoteReplacement import reporting.diagnostic.Message import reporting.diagnostic.messages._ @@ -16,7 +17,7 @@ object ErrorReporting { import tpd._ def errorTree(tree: untpd.Tree, msg: => Message, pos: Position)(implicit ctx: Context): tpd.Tree = - tree withType errorType(msg, pos) + tree.withType(errorType(msg, pos)) def errorTree(tree: untpd.Tree, msg: => Message)(implicit ctx: Context): tpd.Tree = errorTree(tree, msg, tree.pos) @@ -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..4220679d7dc3 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).withPosOf(expr) + 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..77bdc1a110cd 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).withPosOf(result.tree), 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..0d07b710f382 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.Position +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.withPosOf(call)) } } } @@ -121,7 +123,7 @@ object Inliner { if (enclosingInlineds.nonEmpty) inlined // Remove in the outer most inlined call else { val inlinedAtPos = inlined.call.pos - val callSourceFile = ctx.source.file + 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. @@ -134,10 +136,10 @@ object Inliner { case _ => val transformed = super.transform(tree) enclosingInlineds match { - case call :: _ if call.symbol.sourceFile != callSourceFile => + 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.withPos(inlinedAtPos) + transformed.withPosOf(inlined.call) case _ => transformed } } @@ -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 @@ -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).withPosOf(tree) 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).withPosOf(call) case _ => EmptyTree } @@ -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) 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) + case Some(t) if tree.isType => + TypeTree(t).withPosOf(tree) 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).withPosOf(call) def issueError() = callValueArgss match { case (msgArg :: rest) :: Nil => @@ -593,7 +598,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { case _ => binding } - binding1.withPos(call.pos) + binding1.withPosOf(call) } /** An extractor for references to inlineable arguments. These are : @@ -701,12 +706,12 @@ 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) @@ -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)) } } @@ -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..e47bc18c784d 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. @@ -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 } @@ -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 { @@ -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 = @@ -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)) { diff --git a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala index ef8e4b42c06d..015bd1664196 100644 --- a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala +++ b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala @@ -168,7 +168,7 @@ object PrepareInlineable { ref(accessor) .appliedToTypeTrees(localRefs.map(TypeTree(_)) ++ targs) .appliedToArgss((qual :: Nil) :: argss) - .withPos(tree.pos) + .withPosOf(tree) // 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).withPosOf(tree) // case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 9c3af1eef743..c031a22a9796 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().withPosOf(owningTree) 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..b4126902a5b8 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, Position} import scala.collection.{ mutable, immutable } import ast._ import Trees._ @@ -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.pos)) member.setFlag(Override) else if (member.isType && self.memberInfo(member) =:= self.memberInfo(other)) () // OK, don't complain about type aliases which are equal @@ -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 _ => } @@ -957,7 +958,8 @@ class RefChecks extends MiniPhase { thisPhase => 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 _ => } } @@ -986,7 +988,7 @@ class RefChecks extends MiniPhase { thisPhase => override def transformIdent(tree: Ident)(implicit ctx: Context): Ident = { checkUndesiredProperties(tree.symbol, tree.pos) - currentLevel.enterReference(tree.symbol, tree.pos) + currentLevel.enterReference(tree.symbol, tree.span) 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 @@ -1012,9 +1015,9 @@ class RefChecks extends MiniPhase { thisPhase => val tpe = tree.tpe val sym = tpe.typeSymbol checkUndesiredProperties(sym, tree.pos) - currentLevel.enterReference(sym, tree.pos) + 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..d2f30a0e9109 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.Position import config.Printers.typr import ast.Trees._ import NameOps._ @@ -262,7 +263,8 @@ trait TypeAssigner { 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) + 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) if (tree.getAttachment(desugar.SuppressAccessCheck).isDefined) ownType else ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.pos) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f426aa1562ad..3a21c17f7a5e 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, s"position not set for $tree # ${tree.uniqueId} 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.pos) } 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.pos) 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.pos) 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 `eq` ctx.compilationUnit.source } /** Is `denot` the denotation of a self symbol? */ @@ -362,7 +362,7 @@ 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. @@ -398,7 +398,7 @@ class Typer extends Namer val tree1 = ownType match { case ownType: NamedType if !prefixIsElidable(ownType) => - ref(ownType).withPos(tree.pos) + ref(ownType).withPosOf(tree) case _ => tree.withType(ownType) } @@ -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 @@ -516,8 +516,8 @@ class Typer extends Namer 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).withPosOf(tpt1) tpt1 match { case AppliedTypeTree(_, targs) => @@ -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)).withPosOf(tree), 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 _ => @@ -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.withPosOf(tree)), pt.notApplied) thenp1 :: elsep1 :: Nil } assignType(cpy.If(tree)(cond1, thenp2, elsep2), thenp2, elsep2) @@ -798,21 +798,21 @@ class Typer extends Namer 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) + val resTpt = TypeTree(mt.nonDependentResultApprox).withPosOf(body) 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).withPosOf(body) 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) } @@ -927,7 +927,7 @@ class Typer extends Namer def ptIsCorrectProduct(formal: Type) = { isFullyDefined(formal, ForceDegree.noBottom) && (defn.isProductSubType(formal) || formal.derivesFrom(defn.PairClass)) && - productSelectorTypes(formal).corresponds(params) { + productSelectorTypes(formal, tree.pos).corresponds(params) { (argType, param) => param.tpt.isEmpty || argType <:< typedAheadType(param.tpt).tpe } @@ -968,7 +968,7 @@ class Typer extends Namer 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).withPosOf(tree), 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) } } @@ -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.withPosOf(tree), 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).withPosOf(tree) } 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).withPosOf(tree) // 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 @@ -1241,7 +1241,7 @@ class Typer extends Namer 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).withPosOf(tree) val refineCls = createSymbol(refineClsDef).asClass val TypeDef(_, impl: Template) = typed(refineClsDef) val refinements1 = impl.body @@ -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).withPosOf(arg) 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)).withPosOf(tree), arg.tpe) :: Nil) case _ => if (tree.name == nme.WILDCARD) body1 else { @@ -1410,7 +1410,7 @@ 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) @@ -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 @@ -1622,7 +1622,7 @@ 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) { @@ -1641,7 +1641,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.pos.withSpan(cdef.nameSpan)) if (cls.is(Case) && cls.derivesFrom(defn.EnumClass)) { val firstParent = parents1.head.tpe.dealias.typeSymbol checkEnum(cdef, cls, firstParent) @@ -1660,7 +1660,7 @@ class Typer extends Namer cls, isRequired, cdef.pos) } - 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) @@ -1695,7 +1695,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 @@ -1713,14 +1713,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 @@ -1737,12 +1737,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) } @@ -1794,8 +1794,8 @@ class Typer extends Namer ctx.errorOrMigrationWarning(OnlyFunctionsCanBeFollowedByUnderscore(recovered.tpe.widen), tree.pos) 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) } } @@ -1814,8 +1814,8 @@ class Typer extends Namer ctx.errorOrMigrationWarning(i"""The syntax ` _` is no longer supported; |you can $remedy""", tree.pos) 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 @@ -1850,7 +1850,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).withPosOf(tree), pt) else { val pts = if (arity == pt.tupleArity) pt.tupleElementTypes @@ -1859,11 +1859,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) + .withPosOf(tree) else { val tupleXXLobj = untpd.ref(defn.TupleXXLModule.termRef) val app = untpd.cpy.Apply(tree)(tupleXXLobj, elems.map(untpd.TypedSplice(_))) - .withPos(tree.pos) + .withPosOf(tree) val app1 = typed(app, defn.TupleXXLType) if (ctx.mode.is(Mode.Pattern)) app1 else { @@ -1964,7 +1964,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().withPosOf(tree), 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 @@ -2016,8 +2016,8 @@ class Typer extends Namer 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 + // 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. } @@ -2356,7 +2356,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 => @@ -2470,7 +2470,7 @@ class Typer extends Namer sym.isConstructor || sym.matchNullaryLoosely || ctx.testScala2Mode(MissingEmptyArgumentList(sym), tree.pos, - patch(tree.pos.endPos, "()")) + patch(tree.span.endPos, "()")) } // Reasons NOT to eta expand: @@ -2587,7 +2587,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).withPosOf(tree) tree match { case Literal(c) => lit case tree @ Block(stats, expr) => tpd.cpy.Block(tree)(stats, adaptConstant(expr, tpe)) @@ -2632,9 +2632,9 @@ 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).withPosOf(tree), tree, mbrType) case _ => EmptyTree } } @@ -2662,7 +2662,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) diff --git a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala index fe59723ed3c0..9e49f0520e08 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.Position import config.Printers.variances import reporting.trace @@ -156,8 +157,10 @@ class VarianceChecker()(implicit ctx: Context) { 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 diff --git a/compiler/src/dotty/tools/dotc/util/SourcePosition.scala b/compiler/src/dotty/tools/dotc/util/Position.scala similarity index 65% rename from compiler/src/dotty/tools/dotc/util/SourcePosition.scala rename to compiler/src/dotty/tools/dotc/util/Position.scala index 2731551c501a..99ad22ec63cc 100644 --- a/compiler/src/dotty/tools/dotc/util/SourcePosition.scala +++ b/compiler/src/dotty/tools/dotc/util/Position.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 Position(source: SourceFile, span: Span, outer: Position = NoPosition) 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) + def contains(that: Position): Boolean = + 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,26 +46,32 @@ 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: Position): Position = Position(source, span, outer) + def withSpan(range: Span) = Position(source, range, outer) + + def startPos: Position = withSpan(span.startPos) + def endPos : Position = withSpan(span.endPos) + def focus : Position = withSpan(span.focus) + def toSynthetic: Position = 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 NoPosition extends Position(NoSource, NoSpan) { override def toString: String = "?" - override def withOuter(outer: SourcePosition): SourcePosition = outer + override def withOuter(outer: Position): Position = outer } 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/SourceFile.scala b/compiler/src/dotty/tools/dotc/util/SourceFile.scala index d200fae54df3..df853d1c4bcc 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,18 @@ 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) + def this(name: String, content: String) = this(new VirtualFile(name, content.getBytes), scala.io.Codec.UTF8) /** Tab increment; can be overridden */ def tabInc: Int = 8 @@ -46,15 +59,17 @@ 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) + def pathName: PathName = file.absolutePath.toTermName + override def equals(that : Any): Boolean = that match { - case that : SourceFile => file.path == that.file.path && start == that.start + case that : SourceFile => file == that.file && start == that.start case _ => false } - override def hashCode: Int = file.path.## + start.## + override def hashCode: Int = file.hashCode * 41 + start.hashCode - def apply(idx: Int): Char = content.apply(idx) + def apply(idx: Int): Char = content().apply(idx) - val length: Int = content.length + val length: Int = content().length /** true for all source files except `NoSource` */ def exists: Boolean = true @@ -65,23 +80,23 @@ 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) - else NoSourcePosition + def atSpan(span: Span): Position = + if (span.exists) Position(underlying, span) + else NoPosition def isSelfContained: Boolean = underlying eq this /** Map a position to a position in the underlying source file. * For regular source files, simply return the argument. */ - def positionInUltimateSource(position: SourcePosition): SourcePosition = - SourcePosition(underlying, position.pos shift start) + def positionInUltimateSource(position: Position): Position = + Position(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 +107,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 +143,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 +154,55 @@ 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) + Array.copy(sourceOfChunk, 0, a, 0, chunks) + sourceOfChunk = a + } + sourceOfChunk(chunks) = this + chunks += 1 + ctr.set(id + 1) + id + } +} +object SourceFile { + implicit def eqSurce: Eq[SourceFile, SourceFile] = Eq + + implicit def fromContext(implicit ctx: Context): SourceFile = ctx.source + + type PathName = TermName + + def fromId(id: Int): SourceFile = sourceOfChunk(id >> ChunkSizeLog) + + private final val ChunkSizeLog = 10 + private final val ChunkSize = 1 << ChunkSizeLog + @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): Position = NoPosition } diff --git a/compiler/src/dotty/tools/dotc/util/Positions.scala b/compiler/src/dotty/tools/dotc/util/Spans.scala similarity index 50% rename from compiler/src/dotty/tools/dotc/util/Positions.scala rename to compiler/src/dotty/tools/dotc/util/Spans.scala index 1e6814d7caf4..5aba4366defa 100644 --- a/compiler/src/dotty/tools/dotc/util/Positions.scala +++ b/compiler/src/dotty/tools/dotc/util/Spans.scala @@ -2,20 +2,24 @@ package dotty.tools.dotc package util import language.implicitConversions -/** Position format in little endian: +/** 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 - * NoPosition encoded as -1L (this is a normally invalid position - * because point would lie beyond end. + * NoSpan encoded as -1L (this is a normally invalid span because point would lie beyond end). */ -object Positions { +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 position */ + /** The maximal representable offset in a span */ private final val MaxOffset = StartEndMask /** Convert offset `x` to an integer by sign extending the original @@ -24,97 +28,97 @@ object Positions { 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 + /** 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 Position(val coords: Long) extends AnyVal { + class Span(val coords: Long) extends AnyVal { - /** Is this position different from NoPosition? */ - def exists: Boolean = this != NoPosition + /** Is this span different from NoSpan? */ + def exists: Boolean = this != NoSpan - /** The start of this position. */ + /** The start of this span. */ def start: Int = { assert(exists) (coords & StartEndMask).toInt } - /** The end of this position */ + /** The end of this span */ def end: Int = { assert(exists) ((coords >>> StartEndBits) & StartEndMask).toInt } - /** The point of this position, returns start for synthetic positions */ + /** 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 position */ + /** The difference between point and start in this span */ def pointDelta: Int = (coords >>> (StartEndBits * 2)).toInt - def orElse(that: Position): Position = + def orElse(that: Span): Span = 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. + /** The union of two spans. This is the least range that encloses + * both spans. It is always a synthetic span. */ - def union(that: Position): Position = + def union(that: Span): Span = if (!this.exists) that else if (!that.exists) this - else Position(this.start min that.start, this.end max that.end, this.point) + else Span(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 = + /** 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 position synthetic? */ + /** Is this span synthetic? */ def isSynthetic: Boolean = pointDelta == SyntheticPointDelta - /** Is this position source-derived? */ + /** Is this span source-derived? */ def isSourceDerived: Boolean = !isSynthetic - /** Is this a zero-extent position? */ + /** Is this a zero-extent span? */ def isZeroExtent: Boolean = start == end - /** A position where all components are shifted by a given `offset` - * relative to this position. + /** A span where all components are shifted by a given `offset` + * relative to this span. */ - def shift(offset: Int): Position = + def shift(offset: Int): Span = 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 span with start and end at the point of this span */ + def focus: Span = if (exists) Span(point) else NoSpan - /** 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 span with start and end at the start of this span */ + def startPos: Span = if (exists) Span(start) else NoSpan - /** The zero-extent position with start and end at the end of this position */ - def endPos: Position = if (exists) Position(end) else NoPosition + /** 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 position with a different start */ - def withStart(start: Int): Position = + /** 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 position with a different end */ - def withEnd(end: Int): Position = + /** 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 position with a different point */ - def withPoint(point: Int): Position = + /** 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 position */ - def toSynthetic: Position = if (isSynthetic) this else Position(start, end) + /** 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 ("[", "]") @@ -127,48 +131,48 @@ object Positions { private def fromOffsets(start: Int, end: Int, pointDelta: Int) = { //assert(start <= end || start == 1 && end == 0, s"$start..$end") - new Position( + new Span( (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 = + /** A synthetic span with given start and end */ + def Span(start: Int, end: Int): Span = fromOffsets(start, end, SyntheticPointDelta) - /** A source-derived position with given start, end, and point delta */ - def Position(start: Int, end: Int, point: Int): Position = { + /** 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 position that starts and ends at given `start`. */ - def Position(start: Int): Position = Position(start, start) + /** 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 position */ - val NoPosition: Position = Position(1, 0) + /** 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 position. + * a zero-range span. */ class Coord(val encoding: Int) extends AnyVal { def isIndex: Boolean = encoding > 0 - def isPosition: Boolean = encoding <= 0 + def isSpan: Boolean = encoding <= 0 def toIndex: Int = { assert(isIndex) encoding - 1 } - def toPosition: Position = { - assert(isPosition) - if (this == NoCoord) NoPosition else Position(-1 - encoding) + 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 positionCoord(pos: Position): Coord = - if (pos.exists) new Coord(-(pos.point + 1)) + implicit def spanCoord(span: Span): Coord = + if (span.exists) new Coord(-(span.point + 1)) else NoCoord /** A sentinel for a missing coordinate */ 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/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index 9d5c89980f53..956ddf7e2dcd 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -110,7 +110,7 @@ object ParseResult { 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(source)(ctx.withSource(source)) val stats = parser.blockStatSeq() parser.accept(Tokens.EOF) stats diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index 819043fb458b..7e20f4e28313 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._ @@ -92,12 +92,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).withPosOf(expr) 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).withPosOf(expr) defs += vd case other => defs += other @@ -135,7 +135,7 @@ class ReplCompiler extends Compiler { val tmpl = Template(emptyConstructor, Nil, EmptyValDef, defs.stats) val module = ModuleDef(objectName(defs.state), tmpl) - .withPos(Position(0, defs.stats.last.pos.end)) + .withSpan(Span(0, defs.stats.last.span.end)) PackageDef(Ident(nme.EMPTY_PACKAGE), List(module)) } @@ -231,7 +231,7 @@ class ReplCompiler extends Compiler { 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)) } @@ -244,7 +244,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 +253,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 { diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 38bbaffff0e4..d81af88179a1 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -17,8 +17,8 @@ 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.{SourceFile, SourcePosition} +import dotty.tools.dotc.util.Spans.Span +import dotty.tools.dotc.util.{SourceFile, Position} import dotty.tools.dotc.{CompilationUnit, Driver} import dotty.tools.io._ import org.jline.reader._ @@ -169,7 +169,7 @@ class ReplDriver(settings: Array[String], val unit = new CompilationUnit(file) unit.tpdTree = tree implicit val ctx = state.context.fresh.setCompilationUnit(unit) - val srcPos = SourcePosition(file, Position(cursor)) + val srcPos = Position(file, Span(cursor)) val (_, completions) = Completion.completions(srcPos) completions.map(makeCandidate) } @@ -357,7 +357,7 @@ class ReplDriver(settings: Array[String], /** A `MessageRenderer` without file positions */ private val messageRenderer = new MessageRendering { - override def posStr(pos: SourcePosition, diagnosticLevel: String, message: Message)(implicit ctx: Context): String = "" + override def posStr(pos: Position, diagnosticLevel: String, message: Message)(implicit ctx: Context): String = "" } /** Render messages using the `MessageRendering` trait */ 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/parsing/ModifiersParsingTest.scala b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala index 862159505465..4dab85983368 100644 --- a/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala @@ -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/dotc/reporting/TestReporter.scala b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala index 5e9d0d8f2a03..3babffa18972 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala @@ -9,7 +9,7 @@ import core.Decorators._ import scala.collection.mutable -import util.SourcePosition +import util.Position import core.Contexts._ import Reporter._ import diagnostic.{ Message, MessageContainer, NoExplanation } @@ -29,7 +29,7 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M private[this] var _didCrash = false final def compilerCrashed: Boolean = _didCrash - protected final def inlineInfo(pos: SourcePosition)(implicit ctx: Context): String = + protected final def inlineInfo(pos: Position)(implicit ctx: Context): String = if (pos.exists) { if (pos.outer.exists) i"\ninlined at ${pos.outer}:\n" + inlineInfo(pos.outer) diff --git a/compiler/test/dotty/tools/repl/TabcompleteTests.scala b/compiler/test/dotty/tools/repl/TabcompleteTests.scala index 20b3552cdaef..5cd7f317191b 100644 --- a/compiler/test/dotty/tools/repl/TabcompleteTests.scala +++ b/compiler/test/dotty/tools/repl/TabcompleteTests.scala @@ -90,4 +90,10 @@ class TabcompleteTests extends ReplTest { val expected = List("Renamed") 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")) + } } diff --git a/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala b/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala index 4e62b2d58dfd..7b4a92ef3f3e 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala @@ -11,7 +11,7 @@ import model.comment.Comment import dotc.core.Contexts.Context import dotc.printing.Highlighting._ -import dotc.util.{ SourcePosition, NoSourcePosition } +import dotc.util.{ Position, NoPosition } class ContextDottydoc extends ContextDocstrings { import scala.collection.mutable @@ -34,30 +34,30 @@ class ContextDottydoc extends ContextDocstrings { s -> _defs.get(s).map(xs => xs + d).getOrElse(Set(d)) }) - def error(msg: String, pos: SourcePosition)(implicit ctx: Context): Unit = ctx.error({ + def error(msg: String, pos: Position)(implicit ctx: Context): Unit = ctx.error({ NoColor("[") + Red("doc error") + "] " + msg }.toString, pos) - def error(msg: String)(implicit ctx: Context): Unit = error(msg, NoSourcePosition) + def error(msg: String)(implicit ctx: Context): Unit = error(msg, NoPosition) - def warn(msg: String, pos: SourcePosition)(implicit ctx: Context): Unit = ctx.warning({ + def warn(msg: String, pos: Position)(implicit ctx: Context): Unit = ctx.warning({ NoColor("[") + Yellow("doc warn") + "] " + msg }.toString, pos) - def warn(msg: String)(implicit ctx: Context): Unit = warn(msg, NoSourcePosition) + def warn(msg: String)(implicit ctx: Context): Unit = warn(msg, NoPosition) - def echo(msg: String, pos: SourcePosition)(implicit ctx: Context): Unit = ctx.echo({ + def echo(msg: String, pos: Position)(implicit ctx: Context): Unit = ctx.echo({ "[doc info] " + msg }.toString, pos) - def echo(msg: String)(implicit ctx: Context): Unit = echo(msg, NoSourcePosition) + def echo(msg: String)(implicit ctx: Context): Unit = echo(msg, NoPosition) - def debug(msg: String, pos: SourcePosition)(implicit ctx: Context): Unit = + def debug(msg: String, pos: Position)(implicit ctx: Context): Unit = if (ctx.settings.Ydebug.value) ctx.inform({ "[doc debug] " + msg }.toString, pos) - def debug(msg: String)(implicit ctx: Context): Unit = debug(msg, NoSourcePosition) + def debug(msg: String)(implicit ctx: Context): Unit = debug(msg, NoPosition) def printSummary()(implicit ctx: Context): Unit = { def colored(part: Int, total: Int) = 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..dea25085c103 100644 --- a/doc-tool/src/dotty/tools/dottydoc/util/syntax.scala +++ b/doc-tool/src/dotty/tools/dottydoc/util/syntax.scala @@ -8,8 +8,8 @@ import model.Package import core.ContextDottydoc import dotc.core.Symbols._ -import dotc.util.{ SourcePosition, SourceFile } -import dotc.util.Positions.Position +import dotc.util.{ Position, SourceFile } +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): Position = + 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/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..879f8cb5db79 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) @@ -639,21 +639,21 @@ object DottyLanguageServer { final val RENAME_OVERRIDDEN= "Rename the base member" final val RENAME_NO_OVERRIDDEN = "Rename only this member" - /** Convert an lsp4j.Position to a SourcePosition */ - def sourcePosition(driver: InteractiveDriver, uri: URI, pos: lsp4j.Position): SourcePosition = { + /** Convert an lsp4j.Position to a util.Position */ + def sourcePosition(driver: InteractiveDriver, uri: URI, pos: lsp4j.Position): Position = { val actualPosition = if (isWorksheet(uri)) toWrappedPosition(pos) else pos val source = driver.openedFiles(uri) if (source.exists) { - val p = Positions.Position(source.lineToOffset(actualPosition.getLine) + actualPosition.getCharacter) - new SourcePosition(source, p) + val p = Spans.Span(source.lineToOffset(actualPosition.getLine) + actualPosition.getCharacter) + new Position(source, p) } - else NoSourcePosition + else NoPosition } - /** Convert a SourcePosition to an lsp4j.Range */ - def range(p: SourcePosition, positionMapper: Option[SourcePosition => SourcePosition] = None): Option[lsp4j.Range] = + /** Convert a Position to an lsp4j.Range */ + def range(p: Position, positionMapper: Option[Position => Position] = None): Option[lsp4j.Range] = if (p.exists) { val mappedPosition = positionMapper.map(_(p)).getOrElse(p) Some(new lsp4j.Range( @@ -663,8 +663,8 @@ object DottyLanguageServer { } else None - /** Convert a SourcePosition to an lsp4.Location */ - def location(p: SourcePosition, positionMapper: Option[SourcePosition => SourcePosition] = None): Option[lsp4j.Location] = + /** Convert a Position to an lsp4.Location */ + def location(p: Position, positionMapper: Option[Position => Position] = None): Option[lsp4j.Location] = for { uri <- toUriOption(p.source) r <- range(p, positionMapper) @@ -675,7 +675,7 @@ object DottyLanguageServer { * `positionMapper`. */ def diagnostic(mc: MessageContainer, - positionMapper: Option[SourcePosition => SourcePosition] = None + positionMapper: Option[Position => Position] = None )(implicit ctx: Context): Option[lsp4j.Diagnostic] = if (!mc.pos.exists) None // diagnostics without positions are not supported: https://github.com/Microsoft/language-server-protocol/issues/249 @@ -753,8 +753,8 @@ object DottyLanguageServer { * @param position The position as seen by the compiler (after wrapping) * @return The position in the actual source file (before wrapping). */ - private def toUnwrappedPosition(position: SourcePosition): SourcePosition = { - new SourcePosition(position.source, position.pos, position.outer) { + private def toUnwrappedPosition(position: Position): Position = { + new Position(position.source, position.span, position.outer) { override def startLine: Int = position.startLine - 1 override def endLine: Int = position.endLine - 1 } @@ -778,7 +778,7 @@ object DottyLanguageServer { * Returns the position mapper necessary to unwrap positions for `sourcefile`. If `sourcefile` is * not a worksheet, no mapper is necessary. Otherwise, return `toUnwrappedPosition`. */ - private def positionMapperFor(sourcefile: SourceFile): Option[SourcePosition => SourcePosition] = { + private def positionMapperFor(sourcefile: SourceFile): Option[Position => Position] = { if (isWorksheet(sourcefile)) Some(toUnwrappedPosition _) else None } @@ -865,8 +865,8 @@ object DottyLanguageServer { markupContent(buf.toString) } - /** Create an lsp4j.SymbolInfo from a Symbol and a SourcePosition */ - def symbolInfo(sym: Symbol, pos: SourcePosition, positionMapper: Option[SourcePosition => SourcePosition])(implicit ctx: Context): Option[lsp4j.SymbolInformation] = { + /** Create an lsp4j.SymbolInfo from a Symbol and a Position */ + def symbolInfo(sym: Symbol, pos: Position, positionMapper: Option[Position => Position])(implicit ctx: Context): Option[lsp4j.SymbolInformation] = { def symbolKind(sym: Symbol)(implicit ctx: Context): lsp4j.SymbolKind = { import lsp4j.{SymbolKind => SK} 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/scala/annotation/transientParam.scala b/library/src/scala/annotation/transientParam.scala new file mode 100644 index 000000000000..32b7a3b4f21d --- /dev/null +++ b/library/src/scala/annotation/transientParam.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 annotatoon is particularly useful for implicit + * parameters since for these a textual scan is not sufficient to know + * where they are used. + */ +@param class transientParam 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/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/neg/transient-param.scala b/tests/neg/transient-param.scala new file mode 100644 index 000000000000..188cd78f7baf --- /dev/null +++ b/tests/neg/transient-param.scala @@ -0,0 +1,14 @@ +import annotation.transientParam +class Context + +class Test1()(implicit @transientParam ctx: Context) { // error + def test1 = implicitly[Context] +} + +class Test2()(@transientParam ctx: Context) { // error + def test1 = ctx +} + +class Test3()(implicit @transientParam ctx: Context) { // OK + val foo = implicitly[Context] +} 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)