This issue seems to be 100% unrelated to extension methods.
My guess is that it is related to how the scala3 typer works. When trying to resolve an expression, it will find the “most common denominator” of the types involved in order to accept the expression, in the absence of explicit types, when types have to be inferred. It seems that types are not inferred the same way when their specifications come from two different “sites”. We can see it at work below. In the case of “C”, the constraints on X and Y come from one “site”, in the case of “D”, they come from two “sites”. In the case of “C”, we can see that the term b is considered as a A, while in the case of “D”, the term b is really considered a B.
I do not really understand why the presence of the classtags is determinant to make this code works as expected (cases D and F below ).
Sorry for the approximate language, my knowledge of compilers is limited to Wirth’s PL/0 
package cc.lemieux.poweroff.playzone
import scala.reflect.ClassTag
object Test:
class A:
override def toString(): String = "a"
class B extends A:
override def toString(): String = "b"
private def print[X, Y](from: String, x: X, xTag: ClassTag[X], y: Y, yTag: ClassTag[Y]): Unit =
def typeof(tag: ClassTag[?]) = Option(tag).map("type " + _.runtimeClass.getSimpleName()).getOrElse("")
println()
println(s"$from: x = $x ${typeof(xTag)}")
println(s"$from: y = $y ${typeof(yTag)}")
private case class C[X](x: X):
def func[Y <: X](y: Y)(using
xTag: ClassTag[X],
yTag: ClassTag[Y]
): Unit =
print[X, Y]("C", x, xTag, y, yTag)
private case class D[X](x: X)(using
xTag: ClassTag[X]
):
def func[Y <: X](y: Y)(using
yTag: ClassTag[Y]
): Unit =
print[X, Y]("D", x, xTag, y, yTag)
private case class E[X](x: X):
def func[Y <: X](y: Y): Unit =
print[X, Y]("E", x, null, y, null)
private case class F[X](x: X)(using
xTag: ClassTag[X]
):
def func[Y <: X](y: Y): Unit =
print[X, Y]("F", x, xTag, y, null)
def main(args: Array[String]): Unit =
val a = A()
val b = B()
C(a).func(b)
C(b).func(a)
D(a).func(b)
// D(b).func(a) => Does not compile
E(a).func(b)
E(b).func(a)
F(a).func(b)
// F(b).func(a) => Does not compile
Output:
C: x = a type A
C: y = b type B
C: x = b type A
C: y = a type A
D: x = a type A
D: y = b type B
E: x = a
E: y = b
E: x = b
E: y = a
F: x = a type A
F: y = b