`this.type` results in `? <:` breaking inference

trait Base

class A extends Base
class B extends Base

I want to implement infix + in A() + B() as an alias for Set(a, b)

trait Base:
  infix def +[X <: Base](x: X) =
    Set(this, x)

but it fails

val set = A() + B()

def f(set: Set[A | B]) = {}

f(set)
// ^
// Found:    (Playground.set : Set[? >: Playground.B <: Playground.A | Playground.B])
// Required: Set[Playground.A | Playground.B]

the this.type behavior is breaking it, resulting in this irritating ? >: instead of simply B.

It works if I do prefix notation (useless to me though)

def `+`[T <: Base, K <: Base](t: T, k: K): Set[T | K] = Set(t, k)

val set = `+`(A(), B())

def f(set: Set[A | B]) = {}

f(set)

Scastie

As an extension:

object Base:
  extension [T <: Base](b: T)
    def +[X <: Base](x: X): Set[T | X] = Set(b, x)
1 Like

Well, just make it an extension.

extension [T <: Base](t: T)
  infix def +[U <: Base](u: U): Set[T | U] = Set(t, u)

The problem with having this on the parent trait, is that there is no way to talk about the “current” type. And this.type is probably too specific since Set is invariant.

Not sure if using a transparent inline can help, something like:

trait Base:
  transparent inline infix def +[X <: Base](x: X): Set[Base | X] =
    Set(this, x)
1 Like