Description
We can observe a strange behaviour under the new givens resolution. Currently the implicit search reports 2 ambiguous implicits: 1 is the LowercaseNonEmptyText.type
so the singleton object and the second one is given instance
defined withing the as
trait. Removing the given instance
when trying to get rid of these warning leads to compilation leads to not finding any instances of implicit value.
Based on OpenCB failure in @makiftutuncu /as - build logs
Compiler version
3.5.x and 3.6 nightly
Minimized code
infix trait as[Raw, Refined](using narrow: Raw <:< Refined, widen: Refined =:= Raw):
extension (refined: Refined)
def value: Raw = widen(refined)
def undefinedValue: Raw
lazy val undefined: Refined = narrow(undefinedValue)
def apply(raw: Raw): Refined = narrow(raw)
given instance: (Raw as Refined) = this // comment out to make case1 compile and make case2 fail
extension [Raw](raw: Raw)
def as[Refined](using r: Raw as Refined): Refined = r.apply(raw)
object model:
opaque type LowercaseNonEmptyText <: String = String
object LowercaseNonEmptyText extends (String as LowercaseNonEmptyText):
override val undefinedValue: String = " "
@main def Test =
import model.LowercaseNonEmptyText
val case1 = LowercaseNonEmptyText("foo").value
val case2 = "bar".as[LowercaseNonEmptyText].value
Output
-source:3.5
-- Warning: /Users/wmazur/projects/sandbox/src/main/scala/test.scala:20:35 -----
20 | val case1 = LowercaseNonEmptyText("foo").value
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|Given search preference for ?{ value: ? } between alternatives model.LowercaseNonEmptyText.type and (model.LowercaseNonEmptyText.instance : String as model.LowercaseNonEmptyText) will change
|Current choice : the first alternative
|New choice from Scala 3.6: none - it's ambiguous
-- Warning: /Users/wmazur/projects/sandbox/src/main/scala/test.scala:21:14 -----
21 | val case2 = "bar".as[LowercaseNonEmptyText].value
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|Given search preference for ?{ value: ? } between alternatives model.LowercaseNonEmptyText.type and (model.LowercaseNonEmptyText.instance : String as model.LowercaseNonEmptyText) will change
|Current choice : the first alternative
|New choice from Scala 3.6: none - it's ambiguous
2 warnings found
Both warnings are elevated to errors under -source:3.6
-source:3.5 (or -source:3.5) + commented out given instance
-- [E172] Type Error: /Users/wmazur/projects/sandbox/src/main/scala/test.scala:21:45
21 | val case2 = "bar".as[LowercaseNonEmptyText].value
| ^
|No given instance of type String as model.LowercaseNonEmptyText was found for parameter r of method as
Expectation
Ambigious implicits should not be reported
Workarounds
1st
Replacing
given instance: (Raw as Refined) = this
with
given instance: this.type = this
solves the problem
2nd
Replacing
object LowercaseNonEmptyText extends (String as LowercaseNonEmptyText)
with
implicit object LowercaseNonEmptyText extends (String as LowercaseNonEmptyText)
This workaround seems to be less Scala 3 idiomatic by the usage of implicit
keyword that's going to probably be deprecated at some point in the future.
However this version below does also work:
given LowercaseNonEmptyText: (String as LowercaseNonEmptyText) with
override val undefinedValue: String = " "