@@ -137,10 +137,38 @@ class StringInterpolatorOpt extends MiniPhase:
137137 case _ => false
138138 // Perform format checking and normalization, then make it StringOps(fmt).format(args1) with tweaked args
139139 def transformF (fun : Tree , args : Tree ): Tree =
140- val (fmt, args1) = FormatInterpolatorTransform .checked(fun, args)
140+ // For f"${arg}%xpart", check format conversions and return (format, args) for String.format(format, args).
141+ def checked (args0 : Tree )(using Context ): (Tree , Tree ) =
142+ val (partsExpr, parts) = fun match
143+ case TypeApply (Select (Apply (_, (parts : SeqLiteral ) :: Nil ), _), _) =>
144+ (parts.elems, parts.elems.map { case Literal (Constant (s : String )) => s })
145+ case _ =>
146+ report.error(" Expected statically known StringContext" , fun.srcPos)
147+ (Nil , Nil )
148+ val (args, elemtpt) = args0 match
149+ case seqlit : SeqLiteral => (seqlit.elems, seqlit.elemtpt)
150+ case _ =>
151+ report.error(" Expected statically known argument list" , args0.srcPos)
152+ (Nil , EmptyTree )
153+
154+ def literally (s : String ) = Literal (Constant (s))
155+ if parts.lengthIs != args.length + 1 then
156+ val badParts =
157+ if parts.isEmpty then " there are no parts"
158+ else s " too ${if parts.lengthIs > args.length + 1 then " few" else " many" } arguments for interpolated string "
159+ report.error(badParts, fun.srcPos)
160+ (literally(" " ), args0)
161+ else
162+ val checker = TypedFormatChecker (partsExpr, parts, args)
163+ val (format, formatArgs) = checker.checked
164+ if format.isEmpty then (literally(parts.mkString), args0) // on error just use unchecked inputs
165+ else (literally(format.mkString), SeqLiteral (formatArgs.toList, elemtpt))
166+ end checked
167+ val (fmt, args1) = checked(args)
141168 resolveConstructor(defn.StringOps .typeRef, List (fmt))
142169 .select(nme.format)
143170 .appliedTo(args1)
171+ end transformF
144172 // Starting with Scala 2.13, s and raw are macros in the standard
145173 // library, so we need to expand them manually.
146174 // sc.s(args) --> standardInterpolator(processEscapes, args, sc.parts)
0 commit comments