diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 855147ac44ff..d7a5c7be03b5 100644 --- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -480,7 +480,7 @@ class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{ implicit def positionHelper(a: Position): PositionHelper = new PositionHelper { def isDefined: Boolean = a.exists - def line: Int = sourcePos(a).line + def line: Int = sourcePos(a).line + 1 def finalPosition: Position = a } diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index b790772455a6..2a42a7fa9bcf 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -192,7 +192,7 @@ object Parsers { case _ => if (mustStartStat && in.isAfterLineEnd() && - isLeqIndented(in.offset, lastStatOffset)) + isLeqIndented(in.offset, lastStatOffset max 0)) return } in.nextToken() diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index f07f43a63675..26e6324eb803 100644 --- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -25,7 +25,7 @@ class ConsoleReporter( printMessage(pos.lineContents.stripLineEnd) def printColumnMarker(pos: SourcePosition) = - if (pos.exists) { printMessage(" " * (pos.column - 1) + "^") } + if (pos.exists) { printMessage(" " * pos.column + "^") } /** Prints the message. */ def printMessage(msg: String): Unit = { writer.print(msg + "\n"); writer.flush() } diff --git a/src/dotty/tools/dotc/util/SourceFile.scala b/src/dotty/tools/dotc/util/SourceFile.scala index 45119a881538..5e8f85e2806f 100644 --- a/src/dotty/tools/dotc/util/SourceFile.scala +++ b/src/dotty/tools/dotc/util/SourceFile.scala @@ -72,7 +72,7 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) { def positionInUltimateSource(position: SourcePosition): SourcePosition = SourcePosition(underlying, position.pos shift start) - def isLineBreak(idx: Int) = + private def isLineBreak(idx: Int) = if (idx >= length) false else { val ch = content(idx) // don't identify the CR in CR LF as a line break, since LF will do. @@ -80,7 +80,7 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) { else isLineBreakChar(ch) } - def calculateLineIndices(cs: Array[Char]) = { + private def calculateLineIndices(cs: Array[Char]) = { val buf = new ArrayBuffer[Int] buf += 0 for (i <- 0 until cs.length) if (isLineBreak(i)) buf += i + 1 @@ -103,22 +103,29 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) { lastLine } - def startOfLine(offset: Int): Int = lineToOffset(offsetToLine(offset)) + /** The index of the first character of the line containing position `offset` */ + def startOfLine(offset: Int): Int = { + require(offset >= 0) + lineToOffset(offsetToLine(offset)) + } + /** The start index of the line following the one containing position `offset` */ def nextLine(offset: Int): Int = lineToOffset(offsetToLine(offset) + 1 min lineIndices.length - 1) + /** The contents of the line containing position `offset` */ def lineContents(offset: Int): String = content.slice(startOfLine(offset), nextLine(offset)).mkString + /** The column corresponding to `offset`, starting at 0 */ def column(offset: Int): Int = { var idx = startOfLine(offset) var col = 0 while (idx != offset) { - col += (if (content(idx) == '\t') tabInc - col % tabInc else 1) + col += (if (content(idx) == '\t') (tabInc - col) % tabInc else 1) idx += 1 } - col + 1 + col } override def toString = file.toString diff --git a/src/dotty/tools/dotc/util/SourcePosition.scala b/src/dotty/tools/dotc/util/SourcePosition.scala index 3d6352a1a0f3..c88cbc78b181 100644 --- a/src/dotty/tools/dotc/util/SourcePosition.scala +++ b/src/dotty/tools/dotc/util/SourcePosition.scala @@ -10,7 +10,11 @@ case class SourcePosition(source: SourceFile, pos: Position) { def exists = pos.exists def lineContents: String = source.lineContents(point) + + /** The line of the position, starting at 0 */ def line: Int = source.offsetToLine(point) + + /** The column of the position, starting at 0 */ def column: Int = source.column(point) override def toString = diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 1aa35e3ee66b..520abc222f1a 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -140,6 +140,7 @@ class tests extends CompilerTest { @Test def neg_shadowedImplicits = compileFile(negDir, "arrayclone-new", xerrors = 2) @Test def neg_traitParamsTyper = compileFile(negDir, "traitParamsTyper", xerrors = 5) @Test def neg_traitParamsMixin = compileFile(negDir, "traitParamsMixin", xerrors = 2) + @Test def neg_firstError = compileFile(negDir, "firstError", xerrors = 3) @Test def run_all = runFiles(runDir) diff --git a/tests/neg/firstError.scala b/tests/neg/firstError.scala new file mode 100644 index 000000000000..317adcceddcc --- /dev/null +++ b/tests/neg/firstError.scala @@ -0,0 +1,4 @@ +. + +\u890u3084eu + diff --git a/tests/run/origins.check b/tests/run/origins.check index 771baf9fde10..db9bf29a4f80 100644 --- a/tests/run/origins.check +++ b/tests/run/origins.check @@ -1,6 +1,6 @@ >> Origins tag 'boop' logged 65 calls from 3 distinguished sources. - 50 Test$.$anonfun$f3$1(origins.scala:21) - 10 Test$.$anonfun$f2$1(origins.scala:20) - 5 Test$.$anonfun$f1$1(origins.scala:19) + 50 Test$.$anonfun$f3$1(origins.scala:22) + 10 Test$.$anonfun$f2$1(origins.scala:21) + 5 Test$.$anonfun$f1$1(origins.scala:20)