Dotty: No warning/error when matching unrelated object types

Created on 7 Sep 2020  路  9Comments  路  Source: lampepfl/dotty

Minimized code

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")
  }

Output

Nothing

Expectation

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")
pattern-matching bug

All 9 comments

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.

@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 equals in RecoveryCompleted is 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.

Was this page helpful?
0 / 5 - 0 ratings