Skip to content

Commit 047779a

Browse files
committed
Drop special reporter
1 parent 5e62091 commit 047779a

File tree

2 files changed

+32
-98
lines changed

2 files changed

+32
-98
lines changed

compiler/src/dotty/tools/dotc/transform/localopt/FormatChecker.scala

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import dotty.tools.dotc.core.Types._
1717
import dotty.tools.dotc.core.Phases.typerPhase
1818

1919
/** Formatter string checker. */
20-
class TypedFormatChecker(args: List[Tree])(using Context)(using reporter: InterpolationReporter):
20+
class TypedFormatChecker(partsElems: List[Tree], parts: List[String], args: List[Tree])(using Context):
2121

2222
val argTypes = args.map(_.tpe)
2323
val actuals = ListBuffer.empty[Tree]
@@ -33,7 +33,7 @@ class TypedFormatChecker(args: List[Tree])(using Context)(using reporter: Interp
3333
types.find(t => argConformsTo(argi, tpe, t))
3434
.orElse(types.find(t => argConvertsTo(argi, tpe, t)))
3535
.getOrElse {
36-
reporter.argError(s"Found: ${tpe.show}, Required: ${types.mkString(", ")}", argi)
36+
report.argError(s"Found: ${tpe.show}, Required: ${types.mkString(", ")}", argi)
3737
actuals += args(argi)
3838
types.head
3939
}
@@ -64,20 +64,17 @@ class TypedFormatChecker(args: List[Tree])(using Context)(using reporter: Interp
6464

6565
/** For N part strings and N-1 args to interpolate, normalize parts and check arg types.
6666
*
67-
* Returns parts, possibly updated with explicit leading "%s",
68-
* and conversions for each arg.
69-
*
70-
* Implementation must emit conversions required by invocations of `argType`.
67+
* Returns normalized part strings and args, where args correcpond to conversions in tail of parts.
7168
*/
72-
def checked(parts0: List[String]): (List[String], List[Conversion]) =
69+
def checked: (List[String], List[Tree]) =
7370
val amended = ListBuffer.empty[String]
7471
val convert = ListBuffer.empty[Conversion]
7572

7673
@tailrec
77-
def loop(parts: List[String], n: Int): Unit =
78-
parts match
74+
def loop(remaining: List[String], n: Int): Unit =
75+
remaining match
7976
case part0 :: more =>
80-
def badPart(t: Throwable): String = "".tap(_ => reporter.partError(t.getMessage, index = n, offset = 0))
77+
def badPart(t: Throwable): String = "".tap(_ => report.partError(t.getMessage, index = n, offset = 0))
8178
val part = try StringContext.processEscapes(part0) catch badPart
8279
val matches = formatPattern.findAllMatchIn(part)
8380

@@ -112,8 +109,11 @@ class TypedFormatChecker(args: List[Tree])(using Context)(using reporter: Interp
112109
case Nil => ()
113110
end loop
114111

115-
loop(parts0, n = 0)
116-
(amended.toList, convert.toList)
112+
loop(parts, n = 0)
113+
if reported then (Nil, Nil)
114+
else
115+
assert(argc == actuals.size, s"Expected ${argc} args but got ${actuals.size} for [${parts.mkString(", ")}]")
116+
(amended.toList, actuals.toList)
117117
end checked
118118

119119
extension (descriptor: Match)
@@ -146,7 +146,7 @@ class TypedFormatChecker(args: List[Tree])(using Context)(using reporter: Interp
146146
// the conversion char is the head of the op string (but see DateTimeXn)
147147
val cc: Char =
148148
kind match
149-
case ErrorXn => '?'
149+
case ErrorXn => if op.isEmpty then '?' else op(0)
150150
case DateTimeXn => if op.length > 1 then op(1) else '?'
151151
case _ => op(0)
152152

@@ -243,8 +243,8 @@ class TypedFormatChecker(args: List[Tree])(using Context)(using reporter: Interp
243243
val i = flags.indexOf(f) match { case -1 => 0 case j => j }
244244
errorAt(Flags, i)(msg)
245245

246-
def errorAt(g: SpecGroup, i: Int = 0)(msg: String) = reporter.partError(msg, argi, descriptor.offset(g, i))
247-
def warningAt(g: SpecGroup, i: Int = 0)(msg: String) = reporter.partWarning(msg, argi, descriptor.offset(g, i))
246+
def errorAt(g: SpecGroup, i: Int = 0)(msg: String) = report.partError(msg, argi, descriptor.offset(g, i))
247+
def warningAt(g: SpecGroup, i: Int = 0)(msg: String) = report.partWarning(msg, argi, descriptor.offset(g, i))
248248

249249
object Conversion:
250250
def apply(m: Match, i: Int): Conversion =
@@ -269,4 +269,15 @@ class TypedFormatChecker(args: List[Tree])(using Context)(using reporter: Interp
269269
end apply
270270
val literalHelp = "use %% for literal %, %n for newline"
271271
end Conversion
272+
273+
var reported = false
274+
275+
private def partPosAt(index: Int, offset: Int) =
276+
val pos = partsElems(index).sourcePos
277+
pos.withSpan(pos.span.shift(offset))
278+
279+
extension (r: report.type)
280+
def argError(message: String, index: Int): Unit = r.error(message, args(index).srcPos).tap(_ => reported = true)
281+
def partError(message: String, index: Int, offset: Int): Unit = r.error(message, partPosAt(index, offset)).tap(_ => reported = true)
282+
def partWarning(message: String, index: Int, offset: Int): Unit = r.warning(message, partPosAt(index, offset)).tap(_ => reported = true)
272283
end TypedFormatChecker

compiler/src/dotty/tools/dotc/transform/localopt/FormatInterpolatorTransform.scala

Lines changed: 6 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,6 @@ import dotty.tools.dotc.core.Contexts.*
77

88
object FormatInterpolatorTransform:
99

10-
class PartsReporter(fun: Tree, args0: Tree, parts: List[Tree], args: List[Tree])(using Context) extends InterpolationReporter:
11-
private var reported = false
12-
private var oldReported = false
13-
private def partPosAt(index: Int, offset: Int) =
14-
val pos = parts(index).sourcePos
15-
pos.withSpan(pos.span.shift(offset))
16-
def partError(message: String, index: Int, offset: Int): Unit =
17-
reported = true
18-
report.error(message, partPosAt(index, offset))
19-
def partWarning(message: String, index: Int, offset: Int): Unit =
20-
reported = true
21-
report.warning(message, partPosAt(index, offset))
22-
def argError(message: String, index: Int): Unit =
23-
reported = true
24-
report.error(message, args(index).srcPos)
25-
def strCtxError(message: String): Unit =
26-
reported = true
27-
report.error(message, fun.srcPos)
28-
def argsError(message: String): Unit =
29-
reported = true
30-
report.error(message, args0.srcPos)
31-
def hasReported: Boolean = reported
32-
def resetReported(): Unit =
33-
oldReported = reported
34-
reported = false
35-
def restoreReported(): Unit = reported = oldReported
36-
end PartsReporter
37-
3810
/** For f"${arg}%xpart", check format conversions and return (format, args)
3911
* suitable for String.format(format, args).
4012
*/
@@ -50,67 +22,18 @@ object FormatInterpolatorTransform:
5022
case _ =>
5123
report.error("Expected statically known argument list", args0.srcPos)
5224
(Nil, EmptyTree)
53-
given reporter: InterpolationReporter = PartsReporter(fun, args0, partsExpr, args)
5425

5526
def literally(s: String) = Literal(Constant(s))
56-
inline val skip = false
5727
if parts.lengthIs != args.length + 1 then
58-
reporter.strCtxError {
28+
val badParts =
5929
if parts.isEmpty then "there are no parts"
6030
else s"too ${if parts.lengthIs > args.length + 1 then "few" else "many"} arguments for interpolated string"
61-
}
31+
report.error(badParts, fun.srcPos)
6232
(literally(""), args0)
63-
else if skip then
64-
val checked = parts.head :: parts.tail.map(p => if p.startsWith("%") then p else "%s" + p)
65-
(literally(checked.mkString), args0)
6633
else
67-
val checker = TypedFormatChecker(args)
68-
val (checked, cvs) = checker.checked(parts)
69-
if reporter.hasReported then (literally(parts.mkString), args0)
70-
else
71-
assert(checker.argc == checker.actuals.size, s"Expected ${checker.argc}, actuals size is ${checker.actuals.size} for [${parts.mkString(", ")}]")
72-
(literally(checked.mkString), SeqLiteral(checker.actuals.toList, elemtpt))
34+
val checker = TypedFormatChecker(partsExpr, parts, args)
35+
val (format, formatArgs) = checker.checked
36+
if format.isEmpty then (literally(parts.mkString), args0)
37+
else (literally(format.mkString), SeqLiteral(formatArgs.toList, elemtpt))
7338
end checked
7439
end FormatInterpolatorTransform
75-
76-
/** This trait defines a tool to report errors/warnings that do not depend on Position. */
77-
trait InterpolationReporter:
78-
79-
/** Reports error/warning of size 1 linked with a part of the StringContext.
80-
*
81-
* @param message the message to report as error/warning
82-
* @param index the index of the part inside the list of parts of the StringContext
83-
* @param offset the index in the part String where the error is
84-
* @return an error/warning depending on the function
85-
*/
86-
def partError(message: String, index: Int, offset: Int): Unit
87-
def partWarning(message: String, index: Int, offset: Int): Unit
88-
89-
/** Reports error linked with an argument to format.
90-
*
91-
* @param message the message to report as error/warning
92-
* @param index the index of the argument inside the list of arguments of the format function
93-
* @return an error depending on the function
94-
*/
95-
def argError(message: String, index: Int): Unit
96-
97-
/** Reports error linked with the list of arguments or the StringContext.
98-
*
99-
* @param message the message to report in the error
100-
* @return an error
101-
*/
102-
def strCtxError(message: String): Unit
103-
def argsError(message: String): Unit
104-
105-
/** Claims whether an error or a warning has been reported
106-
*
107-
* @return true if an error/warning has been reported, false
108-
*/
109-
def hasReported: Boolean
110-
111-
/** Stores the old value of the reported and reset it to false */
112-
def resetReported(): Unit
113-
114-
/** Restores the value of the reported boolean that has been reset */
115-
def restoreReported(): Unit
116-
end InterpolationReporter

0 commit comments

Comments
 (0)