Skip to content

Conversion behave differently depending on if implicit def or given is used #21757

Closed
@tribbloid

Description

@tribbloid

Compiler version

3.5.1

Minimized code

The following 2 examples demonstrating hypothetical syllogism are almost identical, but the second failed, because implicit def is used instead of given

(example 1)

  object AlmostNewStyle {

    class A(val value: Int)

    class B(val a: A)

    class C(val b: B)

    trait Conv[A, B] extends Conversion[A, B]

    given ab: Conv[A, B] = { (a: A) => new B(a) }

    given bc: Conv[B, C] = { (b: B) => new C(b) }

    object ConvUtils {
      given hypotheticalSyllogism[A, B, C](
          using
          ab: Conv[A, B],
          bc: Conv[B, C]
      ): Conv[A, C] = {

        new Conv[A, C] {
          def apply(a: A): C = bc(ab(a))
        }
      }
    }
    import ConvUtils.given

    def demo(): Unit = {
      val a = new A(42)
      val c: C = a
      println(c.b.a.value) // Outputs: 42
    }
  }

(example 2)

  object OldStyle {

    class A(val value: Int)

    class B(val a: A)

    class C(val b: B)

    trait Conv[A, B] extends Conversion[A, B]

    given ab: Conv[A, B] = { (a: A) => new B(a) }

    given bc: Conv[B, C] = { (b: B) => new C(b) }

    object ConvUtils {
      implicit def hypotheticalSyllogism[A, B, C](
          using
          ab: Conv[A, B],
          bc: Conv[B, C]
      ): Conv[A, C] = {

        new Conv[A, C] {
          def apply(a: A): C = bc(ab(a))
        }
      }
    }
    import ConvUtils.given

    def demo(): Unit = {
      val a = new A(42)
      val c: C = a
      println(c.b.a.value) // Outputs: 42
    }
  }

Output

the error of example 2 is:


[Error] /home/peng/git/dottyspike/core/src/main/scala/com/tribbloids/spike/dotty/TransitiveConversion.scala:109:18: Found:    (a : com.tribbloids.spike.dotty.TransitiveConversion.OldStyle.A)
Required: com.tribbloids.spike.dotty.TransitiveConversion.OldStyle.C
Note that implicit conversions cannot be applied because they are ambiguous;
both given instance ab in object OldStyle and given instance bc in object OldStyle match type com.tribbloids.spike.dotty.TransitiveConversion.OldStyle.Conv[A, B]

Explanation
===========

Tree: a
I tried to show that
  (a : com.tribbloids.spike.dotty.TransitiveConversion.OldStyle.A)
conforms to
  com.tribbloids.spike.dotty.TransitiveConversion.OldStyle.C
but none of the attempts shown below succeeded:

  ==> (a : com.tribbloids.spike.dotty.TransitiveConversion.OldStyle.A)  <:  com.tribbloids.spike.dotty.TransitiveConversion.OldStyle.C class dotty.tools.dotc.core.Types$CachedTermRef class dotty.tools.dotc.core.Types$CachedTypeRef
    ==> com.tribbloids.spike.dotty.TransitiveConversion.OldStyle.A  <:  com.tribbloids.spike.dotty.TransitiveConversion.OldStyle.C class dotty.tools.dotc.core.Types$CachedTypeRef class dotty.tools.dotc.core.Types$CachedTypeRef  = false

Expectation

despite the deprecation warning of implicit keyword, the 2 examples should use the same algorithm and behave identically

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions