-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Compiler ignores instance of typeclass and tries to derive it instead #15997
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I'm not sure what this has to do with type class derivation, isn't it implicit resolution that drives the method selected? |
This issue was picked for the Issue Spree No. 23 of 08 November 2022 which takes place in a week from now. @dwijnand, @nmcb, @markehammons will be working on it. If you have any insight into the issue or guidance on how to fix it, please leave it here. |
At this moment, we don't think this is a bug, but it's a definite change in implicit resolution order. At issue are 4 givens:
Previously, given 1 was higher priority than given 2, but in Scala 3.2.1, 2 is being selected to convert The NoSymbol issue is a red-herring. We may revisit this issue later to ascertain what exactly this new ordering is, and why 2 is chosen over 1 when converting In the short term, the desired behavior can be achieved by shoving given 2 into a trait that is extended by object |
After further review, it appears to me that the fact your code works in 3.2.0 at all is a bug in 3.2.0. As stated in the other comment, the inline given is chosen because the given When given_Conversion_CC_JsArray is in use, the JsValueMapper being searched for is of type One of the precedence rules for implicit resolution (or maybe we should be calling it context resolution now) is that the more specific context result is chosen. On a basic level, that means that To see this in action: given [A]: Option[A] = ???
given [B[_], A]: Option[B[A]] = ???
summon[Option[List[Int]]]
//scala.NotImplementedError: an implementation is missing
// at scala.Predef$.$qmark$qmark$qmark(Predef.scala:344)
// at rs$line$5$.given_Option_B(rs$line$5:1)
// ... 32 elided In this code, given_Option_B will always be chosen over Applying this principle to a facsimile of your code yields the same results: import scala.collection.IterableOps
enum JsValue:
case JsArray(a: Int)
object JsValue:
given a[A]: Conversion[A, JsValue] =
println("a")
???
given b[A, B[x] <: IterableOps[x, B, B[x]]]: Conversion[B[A], JsArray] =
println("b")
???
val x = Map(4 -> 3): JsValue //b is printed This precedence applies on both Scala 3.2.0 and 3.2.1. It seems to be a bug in the context resolution of 3.2.0 that given_Conversion_T_JsValue was selected over the more specific given_Conversion_CC_JsArray. In any case, like said before, if you want given_Conversion_CC_JsArray to be lower priority than given_Conversion_T_JsValue, you will need to force it by defining it inside a trait that the JsValue object extends. |
@odersky do you agree with @markehammons summary? (TL;DR current 3.2.1 behaviour is correct) |
@markehammons Thanks for the analysis, which looks correct to me. Nevertheless, it would be good to know what commit caused the difference since AFAIK implicit search rules have not changed in the recent past. Can we do a bisect? |
I will try to do a bisect this evening. |
926d5bd is the commit that caused the change between 3.2.0 and 3.2.1. Double checked that its parent commit still behaves the way the author expects, and it does. |
@markehammons Thanks for digging this out! Very interesting. So it is due to a change in derivation after all, not a change to implicit resolution. The question is: Should we demand a fully defined type before going searching for a mirror? I think it's reasonable but maybe @bishabosha wants to comment, too. |
@odersky I'm not really the expert here, but I prefer the behavior of 3.2.1 here compared to 3.2.0. implicit search precedence is already really complicated, and one more exception that can change precedence so drastically makes the rules even harder to grasp. Just in my opinion. |
I think it was important to add perhaps there could be an alternative solution to the contravariance issue - but if indeed not using it causes incorrect implicit precedence then it seems 926d5bd fixed two bugs, not one |
@bishabosha Yes, looks like this was the right move. I think wjson needs to be updated. |
Regression found in Open CB #4758 for wangzaixiang/wjson
Part of the 3.2.1-RC1 regressions tracker #15949
There seem to be 2 reasons why code now fails to compile:
given [T:JsValueMapper]: JsValueMapper[Map[String, T]]
in 3.2.1 it tries to derive type class instead usinggiven [T: JsValueMapper, CC[x] <: IterableOps[x, CC, CC[x]]]: Conversion[CC[T], JsArray]
. See AST belowMap[String, Int]
TypeTree.of[T].symbol
whereT=Tuple2[String, Int]
returns NoSymbolCompiler version
3.2.1-RC1
Minimized code
Output
AST in Scala 3.2.0
AST in Scala 3.2.1-RC1
Expectation
Should compile
The text was updated successfully, but these errors were encountered: