Using abstract type in given instance not compiling with explicit type in summoned instance

The type class Type should handle container types and their element types. The container type is given as type parameter, whereas the element type is given as abstract type.

This seems to work as long as the type of the summoned type class is inferred. Once the type for the summoned type class is explicitly defined it doesn’t compile anymore, see last line in the code example.

What is wrong with this code and how could I fix it?

import org.scalatest.freespec.AnyFreeSpec

trait Type[A]:
  type B
  def convert(value: String): B
  def collect(values: Seq[B]): A

given tp: Type[Option[Int]] with
  type B = Int
  def convert(value: String): Int = value.toInt
  def collect(values: Seq[Int]): Option[Int] = values.lastOption

class TypeTest extends AnyFreeSpec:
  "inferred type" in: 
    val t = summon[Type[Option[Int]]] 
    val a: Int = t.convert("7")

  "explicit type" in:
    val t: Type[Option[Int]] = summon[Type[Option[Int]]]
    val a: Int = t.convert("7")

See in scastie

Yes, in the explicit type you are explicitly erasing and forgetting what B is.
You could either be fully explicit Type[Option[Int]] { type B = Int } or use an Aux pattern to simplify that.

Is this not exactly what is done in the given instance creation?

given tp: Type[Option[Int]] with
  type B = Int
  def convert(value: String): Int = value.toInt
  def collect(values: Seq[Int]): Option[Int] = values.lastOption

The given isn’t the problem, it’s the summon[T] which will return a value of type T. When you wrote summon[Type[Option[Int]]] you lost the knowledge of the abstract type.

Hm, actually I have two summon[Type[Option[Int]]].

This is perfectly working:

  "inferred type" in: 
    val t = summon[Type[Option[Int]]] 
    val a: Int = t.convert("7")

But this is not working:

 "explicit type" in:
    val t: Type[Option[Int]] = summon[Type[Option[Int]]]
    val a: Int = t.convert("7")

The only difference is the explicit type declaration of the summoned var. I would expect t1 has exactly the same type as t2:

val t1 = summon[Type[Option[Int]]]                     //Ok
val t2: Type[Option[Int]] = summon[Type[Option[Int]]]  //Not Ok

They, dont. That is what I just told you.
The one being inferred is more precise than the one you are typing. If you want both to be the same, you have to be fully precise.

Sure, but again you are erasing that when providing the explicit type.
For example, 1 has the literal type 1 but when you do val x: Int = 1 you erase that knowledge of a more precise type and leave it just as an Int

-Vprint:typer to see what it infers:

    val t: given_Type_Option.type = given_Type_Option
    val u: Type[Option[Int]] = given_Type_Option