Dotty 0.27-RC1
object Main:
abstract class RecoveryCompleted
case object RecoveryCompleted extends RecoveryCompleted
abstract class TypedRecoveryCompleted
case object TypedRecoveryCompleted extends TypedRecoveryCompleted
TypedRecoveryCompleted match {
case RecoveryCompleted => println("Recovery completed")
case TypedRecoveryCompleted => println("Typed recovery completed")
}
Nothing
Something like:
pattern type is incompatible with expected type;
found : ammonite.$sess.cmd5.RecoveryCompleted.type
required: ammonite.$sess.cmd7.TypedRecoveryCompleted.type
case RecoveryCompleted => println("Recovery completed")
This seems to be the correct behavior. See the following example:
class Error {
abstract class RecoveryCompleted
case object RecoveryCompleted extends RecoveryCompleted {
override def equals(that: Any): Boolean = that == TypedRecoveryCompleted
}
abstract class TypedRecoveryCompleted
case object TypedRecoveryCompleted extends TypedRecoveryCompleted
TypedRecoveryCompleted match {
case RecoveryCompleted => println("Recovery completed")
case TypedRecoveryCompleted => println("Typed recovery completed")
}
}
object Test {
def main(args: Array[String]): Unit = new Error
}
The first branch matches.
Related: #3200 https://github.com/scala/bug/issues/1503
@liufengyun
This fails in 2.13, I just assumed this would also fail in Dotty.
pattern type is incompatible with expected type
[error] found : Error.this.RecoveryCompleted.type
[error] required: Error.this.TypedRecoveryCompleted.type
The context for this is that I never got a RecoveryCompleted signal to fire in an Akka persistent actor, there are two of those classes, one for classic actors and one for typed, and I had imported and used the wrong one.
@olofwalker Thanks for clarifying the context. It's a difference between Scala 2 and Scala 3.
Maybe Scala 3 should be more conservative here to prevent such mistakes.
@liufengyun I think I would have been helped by a warning, its a bit like Scala 2, you unknowingly import an implicit, and all of a sudden things work differently.
We can't just copy what 2.13 is doing here as demonstrated by Fengyun's example in https://github.com/lampepfl/dotty/issues/9740#issuecomment-688157605, scalac wrongly emits an error even though this code is correct. We would have to check if equals in RecoveryCompleted is compiler-generated first
We can't just copy what 2.13 is doing here as demonstrated by Fengyun's example in #9740 (comment), scalac wrongly emits an error even though this code is correct. We would have to check if
equalsinRecoveryCompletedis compiler-generated first
It is incomplete, but it seems sound/safe to reject the code. The additional expressiveness seems to be not useful in practice, and usually implies something goes wrong.
It's safe but it might be annoying to someone :). But I think if we only emit the warning if scrutinee.is(Case) && scrutineeEqualsMethod.is(Synthetic) then it's fine and catch the cases we're interested in.
Oops actually we want to check the symbol of the case, not the symbol of the scrutinee.