Iltotore / iron

Strong type constraints for Scala
https://iltotore.github.io/iron/docs/
Apache License 2.0
457 stars 43 forks source link

Ambiguous RuntimeConstraint given instances in RefinedTypeOps #178

Closed ajaychandran closed 12 months ago

ajaychandran commented 1 year ago

Describe the bug Scala environment: JVM Scala version: 3.3.1 Iron version: 2.2.1-10-cbbd01-SNAPSHOT

Reproduction steps

package data

import io.github.iltotore.iron.*
import io.github.iltotore.iron.constraint.numeric.GreaterEqual

import scala.util.*

trait Parse[A]:
  def parse(s: String): Try[A]

object Parse:
  given Parse[Int] = s => Try(s.toInt)

  extension [A](self: Parse[A])
    def refineParse[C](using C: RuntimeConstraint[A, C]): Parse[A :| C] =
      self
        .parse(_)
        .flatMap(a =>
          if C.test(a) then Success(a.assume)
          else Failure(RuntimeException(C.message))
        )

type IsNatural = GreaterEqual[1]
opaque type Natural <: Int = Int :| IsNatural
object Natural:

  given Parse[Natural] =
    summon[Parse[Int]].refineParse[IsNatural]

type IsWhole = GreaterEqual[0]
opaque type Whole <: Int = Int :| IsWhole
object Whole extends RefinedTypeOps[Int, IsWhole, Whole]:

  given Parse[Whole] =
    summon[Parse[Int]].refineParse[IsWhole]

Expected behavior Compiles successfully.

Current behavior

Ambiguous given instances: both given instance rtc in trait RefinedTypeOps and given instance given_RuntimeConstraint_A_C in trait RefinedTypeOps match type io.github.iltotore.iron.RuntimeConstraint[Int, data.Parse$package.IsWhole] of parameter C of method refineParse in object Parse

Explicitly specifying the instance works but is this an implementation detail leaking out?

type IsWhole = GreaterEqual[0]
opaque type Whole <: Int = Int :| IsWhole
object Whole extends RefinedTypeOps[Int, IsWhole, Whole]:

  given Parse[Whole] =
    summon[Parse[Int]].refineParse(using rtc)
Iltotore commented 1 year ago

You're right. The problems seems to be caused by:

trait RefinedTypeOps[A, C, T](using val rtc: RuntimeConstraint[A, C]):

  /**
   * R
   * @return
   */
  inline protected given RuntimeConstraint[A, C] = rtc

Here, both the inline protected given and rtc are given instances, causing the ambiguity error. It seems that implicit trait parameters keep their implicit behaviour. Not sure it's a Scala bug or something intented.

Anyway, it should be easily fixable by removing the second given and instance and making rtc protected