Better type inference for Scala: send us your problematic cases!

You need to make it:

  class BarImpl[T <: Types](val foo: Foo[T]) extends Bar[foo.T.type](foo.T) {
    def bar(req: T.Req): T.Resp = foo.foo(req) // compiles
  }

or alternatively:

  abstract class Bar[T <: Types] {
    val T: T
    def bar(req: T.Req): T.Resp
  }

  class BarImpl[T <: Types](val foo: Foo[T]) extends Bar[T] {
    val T: foo.T.type = foo.T
    def bar(req: T.Req): T.Resp = foo.foo(req)
  }

You are right that I have to make it val foo: Foo[T]:

  class BarImpl[T <: Types](val foo: Foo[T]) extends Bar(foo.T) {
    def bar(req: T.Req): T.Resp = foo.foo(req)
  }

But still I would like not to deal with this foo.T.type hints

You are not alone:

1 Like

You can force the type parameter of Bar to be a singleton type by using a magic Singleton upper bound:

abstract class Bar[T <: Types & Singleton]

This isn’t ideal though and we’d like to replace it by a more general mechanism (my preference would a precise keyword that can be placed on type parameter and definitions to force type inference to infer the most precise type it finds).

Found a case where Scalac infers stuff fine, but Dotty doesn’t.

Scalac 2.13. Works fine.

Dotty, doesn’t compile.

1 Like

Thanks for the example, could you open an issue for that ?

Also don’t forget to add the “compiles in Scala 2” label!

1 Like

The following is an issue I stumbled upon in 2.13.1:

trait TestInferrence[T] {

  def getInt(t: T): Int

}

object TestIntInferrence extends TestInferrence[Int] {
  override def getInt(i: Int) = i
}

object InferrenceTest {

  def createNumberHandler[T](
    testInfer: TestInferrence[T] = TestIntInferrence,
    handlers: Map[String, T => Unit] = Map.empty,
  ): T => Unit = {

    (t: T) => {
      testInfer.getInt(t)
      ()
    }

  }

}

class InferrenceTest {

  val handler = InferrenceTest.createNumberHandler()

}

Note if the handlers map argument is removed from createNumberHandler it compiles without problem.

There is a similar ticket for default arg.

A collegue of mine wanted to create a simple example showing the option type.
This is what he wrote:

Some("name").map("Hello " + _)
None.map("Hello " + _)

EDIT(see below):

Some("Hello").map(_ + " world")
None.map(_ + " world")

And it failed, since None has type Option[Nothing].

Obviously, reading it doesn’t make sense (the compiler could even tell: None.map will never be executed, because None is immutable, etc.
In real-life examples, some method will return Option[String] somewhere, and potential Nones would be properly inferred to Option[String]. But since this triggered a discussion about Scala’s type inference, maybe it “reveals” a real underlying issue so I thought it could potentially be helpful to post it here.

Sorry if it’s only a silly use-case.

Actually those two lines just work for me.

Did you mean this perhaps?

None.map(_ + "Hello")

I guess in theory you could make ???.anyNameAtAll(foo, bar) always compile to just ??? since Nothing is a subtype of everything so in theory has every method that any other type in the world potentially has. But I don’t really see what good could come of that.

Did you mean this perhaps?

Sorry, yes. I should have double-checked his example instead of relying on my memory. Apologies.

@david-sledge Looks like your example already works in Dotty.

@smarter: The following code doesn’t work:

@main def app = {
  
  
  object Nil {
    override def toString = "Nil"
  }
  
  final case class NonEmptyList[+A](head: A, tail: List[A])
  
  type List[+A] = Nil.type | NonEmptyList[A]
  
  inline def [A, B >: A](ls: List[A]) :: (elem: B): List[B] = NonEmptyList(elem, ls) 

  val x : List[Int] = Nil
  
  val xs : List[Int] =  NonEmptyList(1, NonEmptyList(2, Nil))
  
  val ys : List[Int] = 1 :: 2 :: Nil
// Error:
// Found:    (2 : Int)
// Required: List[object Nil]
  
  println(xs)
}

Looks like an inference problem. Wdyt ?

I think you need to make that:

inline def [A, B >: A](elem: B) :: (ls: List[A]): List[B] = NonEmptyList(elem, ls) 
1 Like

Works. Thank you!

This was working prior to 0.24:

trait P[M: Ordering, C] {
  def apply(s: (M, C)*): Seq[(M, C)]
  def sort(x: Seq[(M, C)]) = apply(x.sortBy((s, _) => s): _*)
                                             ^
                 cannot infer type; expected type <?> is not fully defined
}

Can you open an issue for that? Also I suspect it can be minimized further (the use of a lambda whose expected type comes from a repeated parameter is probably the important part here)

6 posts were split to a new topic: Scala 2 type inference questions