Skip to content

Commit 844dff3

Browse files
authored
Merge pull request #350 from scala/backport-lts-3.3-20578
Backport "Warn if interpolator uses toString" to 3.3 LTS
2 parents f66e5c5 + 538799d commit 844dff3

File tree

8 files changed

+72
-58
lines changed

8 files changed

+72
-58
lines changed

compiler/src/dotty/tools/dotc/interactive/Completion.scala

+5-5
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,12 @@ object Completion:
172172
case _ => None
173173

174174
private object StringContextApplication:
175-
def unapply(path: List[tpd.Tree]): Option[tpd.Apply] =
175+
def unapply(path: List[tpd.Tree]): Option[tpd.Apply] =
176176
path match
177-
case tpd.Select(qual @ tpd.Apply(tpd.Select(tpd.Select(_, StdNames.nme.StringContext), _), _), _) :: _ =>
177+
case tpd.Select(qual @ tpd.Apply(tpd.Select(tpd.Select(_, nme.StringContext), _), _), _) :: _ =>
178178
Some(qual)
179179
case _ => None
180-
180+
181181

182182
/** Inspect `path` to determine the offset where the completion result should be inserted. */
183183
def completionOffset(untpdPath: List[untpd.Tree]): Int =
@@ -229,8 +229,8 @@ object Completion:
229229
// See example in dotty.tools.languageserver.CompletionTest.syntheticThis
230230
case tpd.Select(qual @ tpd.This(_), _) :: _ if qual.span.isSynthetic => completer.scopeCompletions
231231
case StringContextApplication(qual) =>
232-
completer.scopeCompletions ++ completer.selectionCompletions(qual)
233-
case tpd.Select(qual, _) :: _ if qual.typeOpt.hasSimpleKind =>
232+
completer.scopeCompletions ++ completer.selectionCompletions(qual)
233+
case tpd.Select(qual, _) :: _ if qual.typeOpt.hasSimpleKind =>
234234
completer.selectionCompletions(qual)
235235
case tpd.Select(qual, _) :: _ => Map.empty
236236
case (tree: tpd.ImportOrExport) :: _ => completer.directMemberCompletions(tree.expr)

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

+1
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
222222
case EnumMayNotBeValueClassesID // errorNumber: 206
223223
case IllegalUnrollPlacementID // errorNumber: 207 - unused in LTS
224224
case ExtensionHasDefaultID // errorNumber: 208
225+
case FormatInterpolationErrorID // errorNumber: 209
225226

226227
def errorNumber = ordinal - 1
227228

compiler/src/dotty/tools/dotc/reporting/MessageKind.scala

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ enum MessageKind:
2323
case PotentialIssue
2424
case UnusedSymbol
2525
case Staging
26+
case Interpolation
2627

2728
/** Human readable message that will end up being shown to the user.
2829
* NOTE: This is only used in the situation where you have multiple words

compiler/src/dotty/tools/dotc/reporting/messages.scala

+5
Original file line numberDiff line numberDiff line change
@@ -3208,3 +3208,8 @@ final class EnumMayNotBeValueClasses(sym: Symbol)(using Context) extends SyntaxM
32083208

32093209
def explain(using Context) = ""
32103210
end EnumMayNotBeValueClasses
3211+
3212+
class BadFormatInterpolation(errorText: String)(using Context) extends Message(FormatInterpolationErrorID):
3213+
def kind = MessageKind.Interpolation
3214+
def msg(using Context) = errorText
3215+
def explain(using Context) = ""

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

+11-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import dotty.tools.dotc.core.Contexts.*
1212
import dotty.tools.dotc.core.Symbols.*
1313
import dotty.tools.dotc.core.Types.*
1414
import dotty.tools.dotc.core.Phases.typerPhase
15+
import dotty.tools.dotc.reporting.BadFormatInterpolation
1516
import dotty.tools.dotc.util.Spans.Span
1617
import dotty.tools.dotc.util.chaining.*
1718

@@ -276,10 +277,16 @@ class TypedFormatChecker(partsElems: List[Tree], parts: List[String], args: List
276277
val pos = partsElems(index).sourcePos
277278
val bgn = pos.span.start + offset
278279
val fin = if end < 0 then pos.span.end else pos.span.start + end
279-
pos.withSpan(Span(bgn, fin, bgn))
280+
pos.withSpan(Span(start = bgn, end = fin, point = bgn))
280281

281282
extension (r: report.type)
282-
def argError(message: String, index: Int): Unit = r.error(message, args(index).srcPos).tap(_ => reported = true)
283-
def partError(message: String, index: Int, offset: Int, end: Int = -1): Unit = r.error(message, partPosAt(index, offset, end)).tap(_ => reported = true)
284-
def partWarning(message: String, index: Int, offset: Int, end: Int = -1): Unit = r.warning(message, partPosAt(index, offset, end)).tap(_ => reported = true)
283+
def argError(message: String, index: Int): Unit =
284+
r.error(BadFormatInterpolation(message), args(index).srcPos)
285+
.tap(_ => reported = true)
286+
def partError(message: String, index: Int, offset: Int, end: Int = -1): Unit =
287+
r.error(BadFormatInterpolation(message), partPosAt(index, offset, end))
288+
.tap(_ => reported = true)
289+
def partWarning(message: String, index: Int, offset: Int, end: Int): Unit =
290+
r.warning(BadFormatInterpolation(message), partPosAt(index, offset, end))
291+
.tap(_ => reported = true)
285292
end TypedFormatChecker

tests/neg/f-interpolator-neg.check

+46-46
Large diffs are not rendered by default.

tests/neg/f-interpolator-tests.check

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
-- Error: tests/neg/f-interpolator-tests.scala:4:19 --------------------------------------------------------------------
1+
-- [E209] Interpolation Error: tests/neg/f-interpolator-tests.scala:4:19 -----------------------------------------------
22
4 | def `um uh` = f"$s%d" // error
33
| ^
44
| Found: (T.this.s : String), Required: Int, Long, Byte, Short, BigInt
5-
-- Error: tests/neg/f-interpolator-tests.scala:10:10 -------------------------------------------------------------------
5+
-- [E209] Interpolation Error: tests/neg/f-interpolator-tests.scala:10:10 ----------------------------------------------
66
10 | f"x % y = ${x % y}%d" // error: illegal conversion character 'y'
77
| ^
88
| illegal conversion character 'y'

tests/neg/fEscapes.check

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- Error: tests/neg/fEscapes.scala:5:18 --------------------------------------------------------------------------------
1+
-- [E209] Interpolation Error: tests/neg/fEscapes.scala:5:18 -----------------------------------------------------------
22
5 | val fEscape = f"\u$octal%04x" // error
33
| ^^
44
| invalid unicode escape at index 1 of \u

0 commit comments

Comments
 (0)