Why could not infer the type of extension method?

Firstly, the follow code works as excepted:
(All codes are in https://scastie.scala-lang.org/A0245eqTRqafqh8m9j1nxg)

scala> type Elem[T] = T match
     |   case String   => Char
     |   case Seq[e]   => e
     |   case Array[e] => e
     |
     |
     | extension[Coll](coll: Coll)
     |   def insert0(elem: Elem[Coll]): Coll = ???
     |
     | Array(1, 2).insert0

val res0: Int => Array[Int] = Lambda$1818/0x0000000800946040@797ee1a9

Now I want to implement a format operator % like python’s, plus with compile time type safe:

import scala.compiletime.ops.string.*

type Args[Fmt <: String] <: Tuple = Length[Fmt] match
 case 0 | 1   => EmptyTuple
 case _       => Substring[Fmt, 0, 2] match
   case "%%"  => Args[Substring[Fmt, 2, Length[Fmt]]]
   case "%s"  => String *: Args[Substring[Fmt, 2, Length[Fmt]]]
   case "%d"  => Int    *: Args[Substring[Fmt, 2, Length[Fmt]]]
   case "%f"  => Double *: Args[Substring[Fmt, 2, Length[Fmt]]]
   case _     => Args[Substring[Fmt, 1, Length[Fmt]]]
     
extension[Fmt <: String & Singleton](fmt: Fmt)
 def % (args: Args[Fmt]): String =
   val itr = args.productIterator
   def format(f: String): String = f match
     case ""       => ""
     case s"%%$tail" => "%" + format(tail)
     case s"%s$tail" => itr.next.toString + format(tail)
     case s"%d$tail" => itr.next.toString + format(tail)
     case s"%f$tail" => itr.next.toString + format(tail)
     case _       => f.take(1) + format(f.drop(1))
   format(fmt)

I would expect the following f1 as a function instance of type ((Int, Int, String)) => String, but it does not. Why?

scala> val s1 = "%d + %d = %s" % (1, 2, "three")
val s1: String = 1 + 2 = three

scala> val f1 = "%d + %d = %s" % _
-- [E081] Type Error: --------------------------------------------------------------------------------------------------------------------------------------------------
1 |val f1 = "%d + %d = %s" % _
  |                          ^
  |                          Missing parameter type
  |
  |                          I could not infer the type of the parameter _$1 of expanded function:
  |                          _$1 => "%d + %d = %s" % _$1.
1 error found

I found that I could kind of make it work by changing the method to return a function. See this scastie Scastie - An interactive playground for Scala.

It’s not exactly what you want though, and scastie can’t seem to show the type if you don’t bind it to a val

1 Like