summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-01-29 19:06:56 +0300
committerEugene Burmako <xeno.by@gmail.com>2014-02-14 14:19:44 +0100
commitb5c4666be9b53a5d8e8d656a3aa597b3897a37c8 (patch)
tree69e3bcc2e7da99c28376793c6dea59e9b9d6246e
parent2c05f0139758613fbe26a5c03d60a9da29f2f5e5 (diff)
downloadscala-b5c4666be9b53a5d8e8d656a3aa597b3897a37c8.tar.gz
scala-b5c4666be9b53a5d8e8d656a3aa597b3897a37c8.tar.bz2
scala-b5c4666be9b53a5d8e8d656a3aa597b3897a37c8.zip
SI-6931 cleans up the position API
I have finally overcome my fear of positions and got to cleaning up its public interface. Apparently it isn’t so bad, since there’s a sane core of methods (thanks to whoever wrote the comments to internal#Position): 1) Checks to distinguish offsets, opaque ranges and transparent ranges 2) Essentials that inclide start, point, end and source 3) Factories that create new positions based on existing ones It looks like methods from the 3rd group are exactly what we’ve been looking for in SI-6931, so we have nothing to add in this commit.
-rw-r--r--src/reflect/scala/reflect/api/Position.scala160
-rw-r--r--src/reflect/scala/reflect/api/Printers.scala10
-rw-r--r--src/reflect/scala/reflect/internal/Printers.scala4
-rw-r--r--src/reflect/scala/reflect/internal/util/Position.scala37
-rw-r--r--test/files/neg/t6931.check10
-rw-r--r--test/files/neg/t6931/Macros_1.scala15
-rw-r--r--test/files/neg/t6931/Test_2.scala4
-rw-r--r--test/files/pos/t8013/inpervolator_1.scala2
8 files changed, 145 insertions, 97 deletions
diff --git a/src/reflect/scala/reflect/api/Position.scala b/src/reflect/scala/reflect/api/Position.scala
index 891d3a43ef..9d1b7c3812 100644
--- a/src/reflect/scala/reflect/api/Position.scala
+++ b/src/reflect/scala/reflect/api/Position.scala
@@ -5,14 +5,48 @@ package api
import scala.reflect.macros.Attachments
/**
- * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
+ * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * Position tracks the origin of [[Symbols#Symbol symbols]] and [[Trees#Tree tree nodes]]. They are commonly used when
- * displaying warnings and errors, to indicate the incorrect point in the program.
+ * Position tracks the origin of [[Symbols#Symbol symbols]] and [[Trees#Tree tree nodes]]. They are commonly used when
+ * displaying warnings and errors, to indicate the incorrect point in the program.
*
- * <b>Please note that this trait may be refactored in future versions of the Scala reflection API.</b>
+ * Every non-empty position refers to a SourceFile and three character
+ * offsets within it: start, end, and point. The point is where the ^ belongs when
+ * issuing an error message, usually a Name. A range position can be designated
+ * as transparent, which excuses it from maintaining the invariants to follow. If
+ * a transparent position has opaque children, those are considered as if they were
+ * the direct children of the transparent position's parent.
*
- * For more information about `Position`s, see the [[http://docs.scala-lang.org/overviews/reflection/annotations-names-scopes.html Reflection Guide: Annotations, Names, Scopes, and More]]
+ * Note: some of these invariants actually apply to the trees which carry
+ * the positions, but they are phrased as if the positions themselves were
+ * the parent/children for conciseness.
+ *
+ * Invariant 1: in a focused/offset position, start == point == end
+ * Invariant 2: in a range position, start <= point < end
+ * Invariant 3: an offset position never has a child with a range position
+ * Invariant 4: every range position child of a range position parent is contained within its parent
+ * Invariant 5: opaque range position siblings overlap at most at a single point
+ *
+ * The following tests are useful on positions:
+ *
+ * pos.isDefined true if position is not an UndefinedPosition (those being NoPosition and FakePos)
+ * pos.isRange true if position is a range (opaque or transparent) which implies start < end
+ * pos.isOpaqueRange true if position is an opaque range
+ *
+ * The following accessor methods are provided - an exception will be thrown if
+ * point/start/end are attempted on an UndefinedPosition.
+ *
+ * pos.source The source file of the position, or NoSourceFile if unavailable
+ * pos.point The offset of the point
+ * pos.start The (inclusive) start offset, or the point of an offset position
+ * pos.end The (exclusive) end offset, or the point of an offset position
+ *
+ * The following conversion methods are often used:
+ *
+ * pos.focus Converts a range position to an offset position focused on the point
+ * pos.makeTransparent Convert an opaque range into a transparent range
+ *
+ * For more information about `Position`s, see the [[http://docs.scala-lang.org/overviews/reflection/annotations-names-scopes.html Reflection Guide: Annotations, Names, Scopes, and More]]
*
* @groupname Common Commonly used methods
* @group ReflectionAPI
@@ -22,21 +56,7 @@ trait Position extends Attachments {
/** @inheritdoc */
type Pos >: Null <: AnyRef with Position
- /** Java file corresponding to the source file of this position.
- *
- * The return type is `scala.reflect.io.AbstractFile`, which belongs to an experimental part of Scala reflection.
- * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined
- * and exposed as a part of scala.reflect.api.
- *
- * @group Common
- */
- def source: scala.reflect.internal.util.SourceFile
-
- /** Is this position neither a NoPosition nor a FakePosition?
- * If isDefined is true, offset and source are both defined.
- * @group Common
- */
- def isDefined: Boolean
+ ////////////////// POSITION FLAVORS //////////////////
/** Is this position a range position? */
def isRange: Boolean
@@ -47,119 +67,141 @@ trait Position extends Attachments {
/** Is this position a non-transparent range position? */
def isOpaqueRange: Boolean
+ /** If this is a range position, the offset position of its point.
+ * Otherwise the position itself
+ */
+ def focus: Pos
+
/** If opaque range, make this position transparent. */
def makeTransparent: Pos
+ ////////////////// POSITION ESSENTIALS //////////////////
+
/** The start of the position's range, or the point if not a range position. */
def start: Int
- /** The start of the position's range, or point if not a range position. */
- @deprecated("Use `start` instead", "2.11.0") def startOrPoint: Int
-
/** The point (where the ^ is) of the position, which is easiest to access using the [[line]] and [[column]] values.
* The [[lineContent line content]] is also available.
* @group Common
*/
def point: Int
- /** The point (where the ^ is) of the position, or else `default` if undefined.
+ /** The end of the position's range, or the point if not a range position.
+ */
+ def end: Int
+
+ /** Java file corresponding to the source file of this position.
+ *
+ * The return type is `scala.reflect.io.AbstractFile`, which belongs to an experimental part of Scala reflection.
+ * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined
+ * and exposed as a part of scala.reflect.api.
+ *
* @group Common
*/
- def pointOrElse(default: Int): Int
+ def source: scala.reflect.internal.util.SourceFile
- /** The end of the position's range, or the point if not a range position.
+ /** The position indicates a [[column `column`]] and the `line` in the source file.
+ * @group Common
*/
- def end: Int
+ def line: Int
- /** The end of the position's range, or point if not a range position.
+ /** The position indicates a `column` and the [[line `line`]] in the source file.
+ * @group Common
*/
- @deprecated("Use `end` instead", "2.11.0") def endOrPoint: Int
+ def column: Int
- /** The same position with a different start value (if a range).
+ ////////////////// POSITION FACTORIES //////////////////
+
+ /** Returns a new position with the same attributes, but a different start value (if a range).
*/
def withStart(off: Int): Pos
- /** The same position with a different end value (if a range).
+ /** Returns a new position with the same attributes, but a different end value (if a range).
*/
def withEnd(off: Int): Pos
- /** The same position with a different point value (if a range or offset).
+ /** Returns a new position with the same attributes, but a different point value (if a range or offset).
*/
def withPoint(off: Int): Pos
- /** If this is a range, the union with the other range, with the point of this position.
- * Otherwise, this position
+ ////////////////// STUFF //////////////////
+
+ /** Is this position not a NoPosition?
+ * If isDefined is true, offset and source are both defined.
+ * @group Common
*/
- def union(pos: Pos): Pos
+ @deprecated("Removed from the public API", "2.11.0") def isDefined: Boolean
- /** If this is a range position, the offset position of its point.
- * Otherwise the position itself
+ /** The point (where the ^ is) of the position, or else `default` if undefined.
+ * @group Common
*/
- def focus: Pos
+ @deprecated("Removed from the public API", "2.11.0") def pointOrElse(default: Int): Int
+
+ /** The start of the position's range, or point if not a range position. */
+ @deprecated("Removed from the public API", "2.11.0") def startOrPoint: Int
+
+ /** The end of the position's range, or point if not a range position.
+ */
+ @deprecated("Removed from the public API", "2.11.0") def endOrPoint: Int
+
+ /** If this is a range, the union with the other range, with the point of this position.
+ * Otherwise, this position
+ */
+ @deprecated("Removed from the public API", "2.11.0") def union(pos: Pos): Pos
/** If this is a range position, the offset position of its start.
* Otherwise the position itself
*/
- def focusStart: Pos
+ @deprecated("Removed from the public API", "2.11.0") def focusStart: Pos
/** If this is a range position, the offset position of its end.
* Otherwise the position itself
*/
- def focusEnd: Pos
+ @deprecated("Removed from the public API", "2.11.0") def focusEnd: Pos
/** Does this position include the given position `pos`?
* This holds if `this` is a range position and its range [start..end]
* is the same or covers the range of the given position, which may or may not be a range position.
*/
- def includes(pos: Pos): Boolean
+ @deprecated("Removed from the public API", "2.11.0") def includes(pos: Pos): Boolean
/** Does this position properly include the given position `pos` ("properly" meaning their
* ranges are not the same)?
*/
- def properlyIncludes(pos: Pos): Boolean
+ @deprecated("Removed from the public API", "2.11.0") def properlyIncludes(pos: Pos): Boolean
/** Does this position precede that position?
* This holds if both positions are defined and the end point of this position
* is not larger than the start point of the given position.
*/
- def precedes(pos: Pos): Boolean
+ @deprecated("Removed from the public API", "2.11.0") def precedes(pos: Pos): Boolean
/** Does this position properly precede the given position `pos` ("properly" meaning their ranges
* do not share a common point).
*/
- def properlyPrecedes(pos: Pos): Boolean
+ @deprecated("Removed from the public API", "2.11.0") def properlyPrecedes(pos: Pos): Boolean
/** Does this position overlap with that position?
* This holds if both positions are ranges and there is an interval of
* non-zero length that is shared by both position ranges.
*/
- def overlaps(pos: Pos): Boolean
+ @deprecated("Removed from the public API", "2.11.0") def overlaps(pos: Pos): Boolean
/** Does this position cover the same range as that position?
* Holds only if both position are ranges
*/
- def sameRange(pos: Pos): Boolean
-
- /** The position indicates a [[column `column`]] and the `line` in the source file.
- * @group Common
- */
- def line: Int
-
- /** The position indicates a `column` and the [[line `line`]] in the source file.
- * @group Common
- */
- def column: Int
+ @deprecated("Removed from the public API", "2.11.0") def sameRange(pos: Pos): Boolean
/** Convert this to a position around `point` that spans a single source line
*/
- def toSingleLine: Pos
+ @deprecated("Removed from the public API", "2.11.0") def toSingleLine: Pos
/** The content of the line this Position refers to.
* @group Common
*/
- def lineContent: String
+ @deprecated("Removed from the public API", "2.11.0") def lineContent: String
/** Show a textual representation of the position.
*/
- def show: String
+ @deprecated("Use `universe.show(position)` instead", "2.11.0") def show: String
}
diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala
index ae1ad30527..96e111f759 100644
--- a/src/reflect/scala/reflect/api/Printers.scala
+++ b/src/reflect/scala/reflect/api/Printers.scala
@@ -248,11 +248,21 @@ trait Printers { self: Universe =>
*/
def show(flags: FlagSet): String
+ /** Renders a prettified representation of a position.
+ * @group Printers
+ */
+ def show(position: Position): String
+
/** Renders internal structure of a flag set.
* @group Printers
*/
def showRaw(flags: FlagSet): String = flags.toString
+ /** Renders internal structure of a position.
+ * @group Printers
+ */
+ def showRaw(position: Position): String = position.toString
+
/** Renders a string that represents a declaration of this symbol written in Scala.
* @group Printers
*/
diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala
index b287a3884a..0a9e291abe 100644
--- a/src/reflect/scala/reflect/internal/Printers.scala
+++ b/src/reflect/scala/reflect/internal/Printers.scala
@@ -1238,6 +1238,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
}
}
+ def show(position: Position): String = {
+ position.show
+ }
+
def showDeclaration(sym: Symbol): String = {
if (!isCompilerUniverse) definitions.fullyInitializeSymbol(sym)
sym.defString
diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala
index f3eedb88e7..5cec575b77 100644
--- a/src/reflect/scala/reflect/internal/util/Position.scala
+++ b/src/reflect/scala/reflect/internal/util/Position.scala
@@ -8,43 +8,6 @@ package reflect
package internal
package util
-/** The Position class and its subclasses represent positions of ASTs and symbols.
- * Every subclass of DefinedPosition refers to a SourceFile and three character
- * offsets within it: start, end, and point. The point is where the ^ belongs when
- * issuing an error message, usually a Name. A range position can be designated
- * as transparent, which excuses it from maintaining the invariants to follow. If
- * a transparent position has opaque children, those are considered as if they were
- * the direct children of the transparent position's parent.
- *
- * Note: some of these invariants actually apply to the trees which carry
- * the positions, but they are phrased as if the positions themselves were
- * the parent/children for conciseness.
- *
- * Invariant 1: in a focused/offset position, start == point == end
- * Invariant 2: in a range position, start <= point < end
- * Invariant 3: an offset position never has a child with a range position
- * Invariant 4: every range position child of a range position parent is contained within its parent
- * Invariant 5: opaque range position siblings overlap at most at a single point
- *
- * The following tests are useful on positions:
- *
- * pos.isDefined true if position is not an UndefinedPosition (those being NoPosition and FakePos)
- * pos.isRange true if position is a range (opaque or transparent) which implies start < end
- * pos.isOpaqueRange true if position is an opaque range
- *
- * The following accessor methods are provided - an exception will be thrown if
- * point/start/end are attempted on an UndefinedPosition.
- *
- * pos.source The source file of the position, or NoSourceFile if unavailable
- * pos.point The offset of the point
- * pos.start The (inclusive) start offset, or the point of an offset position
- * pos.end The (exclusive) end offset, or the point of an offset position
- *
- * The following conversion methods are often used:
- *
- * pos.focus Converts a range position to an offset position focused on the point
- * pos.makeTransparent Convert an opaque range into a transparent range
- */
class Position extends scala.reflect.api.Position with InternalPositionImpl with DeprecatedPosition {
type Pos = Position
def pos: Position = this
diff --git a/test/files/neg/t6931.check b/test/files/neg/t6931.check
new file mode 100644
index 0000000000..7cf804a936
--- /dev/null
+++ b/test/files/neg/t6931.check
@@ -0,0 +1,10 @@
+Test_2.scala:3: error: 1
+ err"123"
+ ^
+Test_2.scala:3: error: 2
+ err"123"
+ ^
+Test_2.scala:3: error: 3
+ err"123"
+ ^
+three errors found
diff --git a/test/files/neg/t6931/Macros_1.scala b/test/files/neg/t6931/Macros_1.scala
new file mode 100644
index 0000000000..56da075d1f
--- /dev/null
+++ b/test/files/neg/t6931/Macros_1.scala
@@ -0,0 +1,15 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+object Macros {
+ implicit class Error(ctx: StringContext) {
+ def err(args: Any*): Unit = macro impl
+ }
+
+ def impl(c: Context)(args: c.Tree*): c.Tree = {
+ import c.universe._
+ val q"Macros.Error(scala.StringContext.apply($arg)).err()" = c.macroApplication
+ for (i <- 1 to 3) c.error(arg.pos.withPoint(arg.pos.point + i - 1), i.toString)
+ q"()"
+ }
+} \ No newline at end of file
diff --git a/test/files/neg/t6931/Test_2.scala b/test/files/neg/t6931/Test_2.scala
new file mode 100644
index 0000000000..6a6f645904
--- /dev/null
+++ b/test/files/neg/t6931/Test_2.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ import Macros._
+ err"123"
+} \ No newline at end of file
diff --git a/test/files/pos/t8013/inpervolator_1.scala b/test/files/pos/t8013/inpervolator_1.scala
index 89b7c22709..612e1d727d 100644
--- a/test/files/pos/t8013/inpervolator_1.scala
+++ b/test/files/pos/t8013/inpervolator_1.scala
@@ -18,7 +18,7 @@ object Perverse {
def pImpl(c: Context)(args: c.Expr[Any]*): c.Expr[String] = {
import c.universe._
val macroPos = c.macroApplication.pos
- val text = macroPos.lineContent substring macroPos.column
+ val text = macroPos.source.lineToString(macroPos.line - 1) substring macroPos.column
val tt = Literal(Constant(text))
val tree = q"t8013.Perverse.pervert($tt)"
c.Expr[String](tree)