From b9eb88fe8d8b0dc7d1d8689053f901d4adacb737 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 25 Mar 2019 10:34:43 +0100 Subject: [PATCH] Add TASTy reflect error with custom positions Having custom positions is necessary to emit errors inside string interpolators such as ```scala xml"<" ^^ Some parsing error here ``` --- community-build/community-projects/minitest | 2 +- community-build/community-projects/sourcecode | 2 +- .../tools/dotc/tastyreflect/KernelImpl.scala | 18 ++++++++++++++- library/src/scala/tasty/reflect/Core.scala | 5 +++- library/src/scala/tasty/reflect/Kernel.scala | 23 +++++++++++++++++-- .../src/scala/tasty/reflect/PositionOps.scala | 12 +++++++++- .../scala/tasty/reflect/ReportingOps.scala | 5 ++++ tests/neg/tasty-macro-positions.check | 4 ++++ .../neg/tasty-macro-positions/quoted_1.scala | 17 ++++++++++++++ .../neg/tasty-macro-positions/quoted_2.scala | 11 +++++++++ .../run/tasty-macro-positions/quoted_1.scala | 2 +- tests/run/tasty-positioned/quoted_1.scala | 2 +- 12 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 tests/neg/tasty-macro-positions.check create mode 100644 tests/neg/tasty-macro-positions/quoted_1.scala create mode 100644 tests/neg/tasty-macro-positions/quoted_2.scala diff --git a/community-build/community-projects/minitest b/community-build/community-projects/minitest index 01ca3a595248..500c0e60d7f9 160000 --- a/community-build/community-projects/minitest +++ b/community-build/community-projects/minitest @@ -1 +1 @@ -Subproject commit 01ca3a595248e99973aa46e07fb9bd1626306790 +Subproject commit 500c0e60d7f9617c270c799355888873261cb0bd diff --git a/community-build/community-projects/sourcecode b/community-build/community-projects/sourcecode index 94d81945b199..54291ae38493 160000 --- a/community-build/community-projects/sourcecode +++ b/community-build/community-projects/sourcecode @@ -1 +1 @@ -Subproject commit 94d81945b1993d7651ce06c1f27f639cea8f8d78 +Subproject commit 54291ae384937a6d140b17502848a0bf96873d61 diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala index 5ea4b8aa21a7..5318083d7d41 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala @@ -36,9 +36,15 @@ class KernelImpl(val rootContext: core.Contexts.Context, val rootPosition: util. def error(msg: => String, pos: Position)(implicit ctx: Context): Unit = ctx.error(msg, pos) + def error(msg: => String, sourceFile: SourceFile, start: Int, end: Int)(implicit ctx: Context): Unit = + ctx.error(msg, util.SourcePosition(sourceFile, util.Spans.Span(start, end))) + def warning(msg: => String, pos: Position)(implicit ctx: Context): Unit = ctx.warning(msg, pos) + def warning(msg: => String, sourceFile: SourceFile, start: Int, end: Int)(implicit ctx: Context): Unit = + ctx.error(msg, util.SourcePosition(sourceFile, util.Spans.Span(start, end))) + // // Settings // @@ -1297,7 +1303,7 @@ class KernelImpl(val rootContext: core.Contexts.Context, val rootPosition: util. def Position_exists(self: Position): Boolean = self.exists - def Position_sourceFile(self: Position): java.nio.file.Path = self.source.file.jpath + def Position_sourceFile(self: Position): SourceFile = self.source def Position_startLine(self: Position): Int = self.startLine @@ -1310,6 +1316,16 @@ class KernelImpl(val rootContext: core.Contexts.Context, val rootPosition: util. def Position_sourceCode(self: Position): String = new String(self.source.content(), self.start, self.end - self.start) + // + // SOURCE FILES + // + + type SourceFile = util.SourceFile + + def SourceFile_jpath(self: SourceFile): java.nio.file.Path = self.file.jpath + + def SourceFile_content(self: SourceFile): String = new String(self.content()) + // // COMMENTS // diff --git a/library/src/scala/tasty/reflect/Core.scala b/library/src/scala/tasty/reflect/Core.scala index d1e6fb4709bc..6bcfcc8a3c45 100644 --- a/library/src/scala/tasty/reflect/Core.scala +++ b/library/src/scala/tasty/reflect/Core.scala @@ -407,9 +407,12 @@ trait Core { /** JVM signature of a method */ type Signature = kernel.Signature - /** Source position */ + /** Position in a source file */ type Position = kernel.Position + /** Scala source file */ + type SourceFile = kernel.SourceFile + /** Comment */ type Comment = kernel.Comment diff --git a/library/src/scala/tasty/reflect/Kernel.scala b/library/src/scala/tasty/reflect/Kernel.scala index 1b0144ed9335..6c4886f73a93 100644 --- a/library/src/scala/tasty/reflect/Kernel.scala +++ b/library/src/scala/tasty/reflect/Kernel.scala @@ -145,9 +145,15 @@ trait Kernel { /** Report a compilation error with the given message at the given position */ def error(msg: => String, pos: Position)(implicit ctx: Context): Unit + /** Report a compilation error with the given message at the given position range */ + def error(msg: => String, source: SourceFile, start: Int, end: Int)(implicit ctx: Context): Unit + /** Report a compilation warning with the given message at the given position */ def warning(msg: => String, pos: Position)(implicit ctx: Context): Unit + /** Report a compilation warning with the given message at the given position range */ + def warning(msg: => String, source: SourceFile, start: Int, end: Int)(implicit ctx: Context): Unit + // // Settings // @@ -1037,7 +1043,7 @@ trait Kernel { // POSITIONS // - /** Source position */ + /** Position in a source file */ type Position <: AnyRef /** The start offset in the source file */ @@ -1050,7 +1056,7 @@ trait Kernel { def Position_exists(self: Position): Boolean /** Source file in which this position is located */ - def Position_sourceFile(self: Position): java.nio.file.Path + def Position_sourceFile(self: Position): SourceFile /** The start line in the source file */ def Position_startLine(self: Position): Int @@ -1067,6 +1073,19 @@ trait Kernel { /** Source code within the position */ def Position_sourceCode(self: Position): String + // + // SOURCE FILE + // + + /** Scala source file */ + type SourceFile <: AnyRef + + /** Path to a source file */ + def SourceFile_jpath(self: SourceFile): java.nio.file.Path + + /** Content of a source file */ + def SourceFile_content(self: SourceFile): String + // // COMMENTS // diff --git a/library/src/scala/tasty/reflect/PositionOps.scala b/library/src/scala/tasty/reflect/PositionOps.scala index f2141925fd28..5e714b3bc9b4 100644 --- a/library/src/scala/tasty/reflect/PositionOps.scala +++ b/library/src/scala/tasty/reflect/PositionOps.scala @@ -14,7 +14,7 @@ trait PositionOps extends Core { def exists: Boolean = kernel.Position_exists(pos) /** Source file in which this position is located */ - def sourceFile: java.nio.file.Path = kernel.Position_sourceFile(pos) + def sourceFile: SourceFile = kernel.Position_sourceFile(pos) /** The start line in the source file */ def startLine: Int = kernel.Position_startLine(pos) @@ -33,4 +33,14 @@ trait PositionOps extends Core { } + implicit class SourceFileAPI(sourceFile: SourceFile) { + + /** Path to this source file */ + def jpath: java.nio.file.Path = kernel.SourceFile_jpath(sourceFile) + + /** Content of this source file */ + def content: String = kernel.SourceFile_content(sourceFile) + + } + } diff --git a/library/src/scala/tasty/reflect/ReportingOps.scala b/library/src/scala/tasty/reflect/ReportingOps.scala index 947991278b7f..a2c43fad2020 100644 --- a/library/src/scala/tasty/reflect/ReportingOps.scala +++ b/library/src/scala/tasty/reflect/ReportingOps.scala @@ -5,7 +5,12 @@ trait ReportingOps extends Core { def error(msg: => String, pos: Position)(implicit ctx: Context): Unit = kernel.error(msg, pos) + def error(msg: => String, source: SourceFile, start: Int, end: Int)(implicit ctx: Context): Unit = + kernel.error(msg, source, start, end) + def warning(msg: => String, pos: Position)(implicit ctx: Context): Unit = kernel.warning(msg, pos) + def warning(msg: => String, source: SourceFile, start: Int, end: Int)(implicit ctx: Context): Unit = + kernel.warning(msg, source, start, end) } diff --git a/tests/neg/tasty-macro-positions.check b/tests/neg/tasty-macro-positions.check new file mode 100644 index 000000000000..04bd51fbdb51 --- /dev/null +++ b/tests/neg/tasty-macro-positions.check @@ -0,0 +1,4 @@ +<122..125> in quoted_2.scala +here (+5) is the the argument is foo +[117..120] in quoted_2.scala +here is the the argument is foo diff --git a/tests/neg/tasty-macro-positions/quoted_1.scala b/tests/neg/tasty-macro-positions/quoted_1.scala new file mode 100644 index 000000000000..fd5c20a6f58c --- /dev/null +++ b/tests/neg/tasty-macro-positions/quoted_1.scala @@ -0,0 +1,17 @@ +import scala.quoted._ + +import scala.tasty._ + +object Macros { + + inline def fun(x: Any): Unit = ${ impl('x) } + + def impl(x: Expr[Any])(implicit reflect: Reflection): Expr[Unit] = { + import reflect._ + val pos = x.unseal.underlyingArgument.pos + error("here is the the argument is " + x.unseal.underlyingArgument.showCode, pos) + error("here (+5) is the the argument is " + x.unseal.underlyingArgument.showCode, pos.sourceFile, pos.start + 5, pos.end + 5) + '{} + } + +} diff --git a/tests/neg/tasty-macro-positions/quoted_2.scala b/tests/neg/tasty-macro-positions/quoted_2.scala new file mode 100644 index 000000000000..632a24446cab --- /dev/null +++ b/tests/neg/tasty-macro-positions/quoted_2.scala @@ -0,0 +1,11 @@ + +import Macros._ + +object Test { + def main(args: Array[String]): Unit = { + def foo: String = "abc" + fun( + foo // error // error + ) + } +} diff --git a/tests/run/tasty-macro-positions/quoted_1.scala b/tests/run/tasty-macro-positions/quoted_1.scala index e9722ff1d6ae..a21e2fafdb73 100644 --- a/tests/run/tasty-macro-positions/quoted_1.scala +++ b/tests/run/tasty-macro-positions/quoted_1.scala @@ -32,6 +32,6 @@ object Macros { def posStr(relfection: Reflection)(pos: relfection.Position): Expr[String] = { import relfection._ - s"${pos.sourceFile.getFileName.toString}:[${pos.start}..${pos.end}]".toExpr + s"${pos.sourceFile.jpath.getFileName.toString}:[${pos.start}..${pos.end}]".toExpr } } diff --git a/tests/run/tasty-positioned/quoted_1.scala b/tests/run/tasty-positioned/quoted_1.scala index c1c82a7b5231..58b20cf0d031 100644 --- a/tests/run/tasty-positioned/quoted_1.scala +++ b/tests/run/tasty-positioned/quoted_1.scala @@ -15,7 +15,7 @@ object Positioned { import reflect.{Position => _, _} val pos = rootPosition - val path = pos.sourceFile.toString.toExpr + val path = pos.sourceFile.jpath.toString.toExpr val start = pos.start.toExpr val end = pos.end.toExpr val startLine = pos.startLine.toExpr