Skip to content

Commit a9c8fe3

Browse files
author
Sara Alemanno
committed
Fixed indexed argument errors
1 parent f4ceaf3 commit a9c8fe3

File tree

3 files changed

+18
-14
lines changed

3 files changed

+18
-14
lines changed

library/src-3.x/dotty/internal/StringContextMacro.scala

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -367,19 +367,20 @@ object StringContextMacro {
367367
* @param offset the index in the part where there might be an error
368368
* @param relative true if relative indexing is used, false otherwise
369369
* @param argumentIndex the argument index parameter in the formatting String
370+
* @param expected true if we have an expectedArgumentIndex, false otherwise
370371
* @param expectedArgumentIndex the expected argument index parameter
371372
* @param maxArgumentIndex the maximum argument index parameter that can be used
372373
* @return reports a warning if relative indexing is used but an argument is still given,
373374
* an error is the argument index is not in the bounds [1, number of arguments]
374375
*/
375-
def checkArgumentIndex(partIndex : Int, offset : Int, relative : Boolean, argumentIndex : Int, expectedArgumentIndex : Int, maxArgumentIndex : Int) = {
376+
def checkArgumentIndex(partIndex : Int, offset : Int, relative : Boolean, argumentIndex : Int, expected : Boolean, expectedArgumentIndex : Int, maxArgumentIndex : Int) = {
376377
if (relative)
377378
reporter.partWarning("Argument index ignored if '<' flag is present", partIndex, offset)
378379

379380
if (argumentIndex > maxArgumentIndex || argumentIndex <= 0)
380381
reporter.partError("Argument index out of range", partIndex, offset)
381382

382-
if (expectedArgumentIndex != argumentIndex && !reporter.hasReported())
383+
if (expected && expectedArgumentIndex != argumentIndex && !reporter.hasReported())
383384
reporter.partWarning("Index is not this arg", partIndex, offset)
384385
}
385386

@@ -560,6 +561,7 @@ object StringContextMacro {
560561
* @param hasArgumentIndex
561562
* @param actualArgumentIndex
562563
* @param expectedArgumentIndex
564+
* @param firstFormattingSubstring true if it is the first in the list, i.e. not an indexed argument
563565
* @param maxArgumentIndex
564566
* @param hasRelative
565567
* @param hasWidth
@@ -571,12 +573,14 @@ object StringContextMacro {
571573
* @return the argument index and its type if there is an argument, the flags and the conversion parameter
572574
* reports an error/warning if the formatting parameters are not allowed/wrong, nothing otherwise
573575
*/
574-
def checkFormatSpecifiers(partIndex : Int, hasArgumentIndex : Boolean, actualArgumentIndex : Int, expectedArgumentIndex : Option[Int], maxArgumentIndex : Option[Int],
576+
def checkFormatSpecifiers(partIndex : Int, hasArgumentIndex : Boolean, actualArgumentIndex : Int, expectedArgumentIndex : Option[Int], firstFormattingSubstring : Boolean, maxArgumentIndex : Option[Int],
575577
hasRelative : Boolean, hasWidth : Boolean, width : Int, hasPrecision : Boolean, precision : Int, flags : List[(Char, Int)], conversion : Int, argType : Option[Type], part : String) : (Option[(Type, Int)], Char, List[(Char, Int)])= {
576578
val conversionChar = part.charAt(conversion)
577579

578-
if (hasArgumentIndex && expectedArgumentIndex.nonEmpty && maxArgumentIndex.nonEmpty)
579-
checkArgumentIndex(partIndex, actualArgumentIndex, hasRelative, part.charAt(actualArgumentIndex).asDigit, expectedArgumentIndex.get, maxArgumentIndex.get)
580+
if (hasArgumentIndex && expectedArgumentIndex.nonEmpty && maxArgumentIndex.nonEmpty && firstFormattingSubstring)
581+
checkArgumentIndex(partIndex, actualArgumentIndex, hasRelative, part.charAt(actualArgumentIndex).asDigit, true, expectedArgumentIndex.get, maxArgumentIndex.get)
582+
else if(hasArgumentIndex && maxArgumentIndex.nonEmpty && !firstFormattingSubstring)
583+
checkArgumentIndex(partIndex, actualArgumentIndex, hasRelative, part.charAt(actualArgumentIndex).asDigit, false, 0, maxArgumentIndex.get)
580584

581585
conversionChar match {
582586
case 'c' | 'C' => checkCharacterConversion(partIndex, flags, hasPrecision, precision)
@@ -690,7 +694,7 @@ object StringContextMacro {
690694
case Some(argIndex, arg) => {
691695
val (hasArgumentIndex, argumentIndex, flags, hasWidth, width, hasPrecision, precision, hasRelative, relativeIndex, conversion) = getFormatSpecifiers(part, argIndex, argIndex + 1, false, formattingStart)
692696
if (!reporter.hasReported()){
693-
val conversionWithType = checkFormatSpecifiers(argIndex + 1, hasArgumentIndex, argumentIndex, Some(argIndex + 1), maxArgumentIndex, hasRelative, hasWidth, width, hasPrecision, precision, flags, conversion, Some(arg.unseal.tpe), part)
697+
val conversionWithType = checkFormatSpecifiers(argIndex + 1, hasArgumentIndex, argumentIndex, Some(argIndex + 1), start == 0, maxArgumentIndex, hasRelative, hasWidth, width, hasPrecision, precision, flags, conversion, Some(arg.unseal.tpe), part)
694698
nextStart = conversion + 1
695699
conversionWithType :: checkPart(part, nextStart, argument, maxArgumentIndex)
696700
} else checkPart(part, conversion + 1, argument, maxArgumentIndex)
@@ -702,7 +706,7 @@ object StringContextMacro {
702706
if (hasRelative)
703707
reporter.partError("No last arg", 0, relativeIndex)
704708
if (!reporter.hasReported()){
705-
val conversionWithType = checkFormatSpecifiers(0, hasArgumentIndex, argumentIndex, None, maxArgumentIndex, hasRelative, hasWidth, width, hasPrecision, precision, flags, conversion, None, part)
709+
val conversionWithType = checkFormatSpecifiers(0, hasArgumentIndex, argumentIndex, None, start == 0, maxArgumentIndex, hasRelative, hasWidth, width, hasPrecision, precision, flags, conversion, None, part)
706710
nextStart = conversion + 1
707711
if (!reporter.hasReported() && part.charAt(conversion) != '%' && part.charAt(conversion) != 'n' && !hasArgumentIndex && !hasRelative)
708712
reporter.partError("conversions must follow a splice; use %% for literal %, %n for newline", 0, part.indexOf('%'))

tests/run-macros/f-interpolator-tests.check

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ Bob is 123 years old!
3030
Bob is 123 years old!
3131
Bob is 123 years old!
3232
Bob is 123%2d years old!
33-
The boolean is false
34-
The boolean is true
33+
The boolean is false false
34+
The boolean is true true
3535
a
36-
The string is null
37-
The string is
38-
The string is string1
36+
The string is null null null
37+
The string is
38+
The string is string1 string1 string1
3939
The string is null
4040
The string is
4141
The string is string2

tests/run-macros/f-interpolator-tests.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ object Test {
6161

6262
def generalArgsTests = {
6363

64-
def booleanTest(b : Boolean) = println(f"The boolean is $b%b")
64+
def booleanTest(b : Boolean) = println(f"The boolean is $b%b %<b")
6565

6666
def hTest(arg : Int) = println(f"$arg%h")
6767

68-
def stringTest(s : String) = println(f"The string is $s%s")
68+
def stringTest(s : String) = println(f"The string is $s%s $s%s %1$$s")
6969

7070
def noFormatHasStringDefault(s : String) = println(f"The string is $s")
7171

0 commit comments

Comments
 (0)