@@ -29,8 +29,9 @@ class TypedFormatChecker(partsElems: List[Tree], parts: List[String], args: List
2929 def argType (argi : Int , types : Type * ): Type =
3030 require(argi < argc, s " $argi out of range picking from $types" )
3131 val tpe = argTypes(argi)
32- types.find(t => argConformsTo(argi, tpe, t))
33- .orElse(types.find(t => argConvertsTo(argi, tpe, t)))
32+ types.find(t => t != defn.AnyType && argConformsTo(argi, tpe, t))
33+ .orElse(types.find(t => t != defn.AnyType && argConvertsTo(argi, tpe, t)))
34+ .orElse(types.find(t => t == defn.AnyType && argConformsTo(argi, tpe, t)))
3435 .getOrElse {
3536 report.argError(s " Found: ${tpe.show}, Required: ${types.map(_.show).mkString(" , " )}" , argi)
3637 actuals += args(argi)
@@ -72,15 +73,16 @@ class TypedFormatChecker(partsElems: List[Tree], parts: List[String], args: List
7273 @ tailrec
7374 def loop (remaining : List [String ], n : Int ): Unit =
7475 remaining match
75- case part0 :: more =>
76+ case part0 :: remaining =>
7677 def badPart (t : Throwable ): String = " " .tap(_ => report.partError(t.getMessage.nn, index = n, offset = 0 ))
7778 val part = try StringContext .processEscapes(part0) catch badPart
7879 val matches = formatPattern.findAllMatchIn(part)
7980
8081 def insertStringConversion (): Unit =
8182 amended += " %s" + part
82- convert += Conversion (formatPattern.findAllMatchIn(" %s" ).next(), n) // improve
83- argType(n- 1 , defn.AnyType )
83+ val cv = Conversion (n)
84+ cv.accepts(argType(n- 1 , defn.AnyType ))
85+ convert += cv
8486 def errorLeading (op : Conversion ) = op.errorAt(Spec )(s " conversions must follow a splice; ${Conversion .literalHelp}" )
8587 def accept (op : Conversion ): Unit =
8688 if ! op.isLeading then errorLeading(op)
@@ -104,8 +106,8 @@ class TypedFormatChecker(partsElems: List[Tree], parts: List[String], args: List
104106 if n == 0 && cv.hasFlag('<' ) then cv.badFlag('<' , " No last arg" )
105107 else if ! cv.isLiteral && ! cv.isIndexed then errorLeading(cv)
106108
107- loop(more , n + 1 )
108- case Nil => ()
109+ loop(remaining , n + 1 )
110+ case Nil =>
109111 end loop
110112
111113 loop(parts, n = 0 )
@@ -146,9 +148,10 @@ class TypedFormatChecker(partsElems: List[Tree], parts: List[String], args: List
146148 // the conversion char is the head of the op string (but see DateTimeXn)
147149 val cc : Char =
148150 kind match
149- case ErrorXn => if op.isEmpty then '?' else op(0 )
150- case DateTimeXn => if op.length > 1 then op(1 ) else '?'
151- case _ => op(0 )
151+ case ErrorXn => if op.isEmpty then '?' else op(0 )
152+ case DateTimeXn => if op.length <= 1 then '?' else op(1 )
153+ case StringXn => if op.isEmpty then 's' else op(0 ) // accommodate the default %s
154+ case _ => op(0 )
152155
153156 def isIndexed : Boolean = index.nonEmpty || hasFlag('<' )
154157 def isError : Boolean = kind == ErrorXn
@@ -209,10 +212,9 @@ class TypedFormatChecker(partsElems: List[Tree], parts: List[String], args: List
209212 def accepts (arg : Type ): Boolean =
210213 kind match
211214 case BooleanXn => arg == defn.BooleanType orElse warningAt(CC )(" Boolean format is null test for non-Boolean" )
212- case IntegralXn =>
213- arg == BigIntType || ! cond(cc) {
214- case 'o' | 'x' | 'X' if hasAnyFlag(" + (" ) => " + (" .filter(hasFlag).foreach(bad => badFlag(bad, s " only use ' $bad' for BigInt conversions to o, x, X " )) ; true
215- }
215+ case IntegralXn => arg == BigIntType || ! cond(cc) {
216+ case 'o' | 'x' | 'X' if hasAnyFlag(" + (" ) => " + (" .filter(hasFlag).foreach(bad => badFlag(bad, s " only use ' $bad' for BigInt conversions to o, x, X " )); true
217+ }
216218 case _ => true
217219
218220 // what arg type if any does the conversion accept
@@ -267,6 +269,8 @@ class TypedFormatChecker(partsElems: List[Tree], parts: List[String], args: List
267269 case Some (cc) => new Conversion (m, i, kindOf(cc(0 ))).tap(_.verify)
268270 case None => new Conversion (m, i, ErrorXn ).tap(_.errorAt(Spec )(s " Missing conversion operator in ' ${m.matched}'; $literalHelp" ))
269271 end apply
272+ // construct a default %s conversion
273+ def apply (i : Int ): Conversion = new Conversion (formatPattern.findAllMatchIn(" %" ).next(), i, StringXn )
270274 val literalHelp = " use %% for literal %, %n for newline"
271275 end Conversion
272276
0 commit comments