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