🌐 AI搜索 & 代理 主页
Skip to content

Conversation

@dwijnand
Copy link
Member

@dwijnand dwijnand commented Jul 6, 2021

When the static type matches the type test, there's no need for a
ClassTag. So it shouldn't emit an unchecked warning (checkCheckable).

Also, in that case, even if a ClassTag is available, there's no need to
use one (extractorForUncheckedType).

Compared to previously, two additional things will change: if the value
isn't of its static type (e.g. a cast was used) or it's null,
previously this would fail early with the case not matching. Now,
instead, the case will match and (likely) it will fail as soon as the
value is used.

Fixes scala/bug#12406

When the static type matches the type test, there's no need for a
ClassTag.  So it shouldn't emit an unchecked warning (checkCheckable).

Also, in that case, even if a ClassTag is available, there's no need to
use one (extractorForUncheckedType).

Compared to previously, two additional things will change: if the value
isn't of its static type (e.g. a cast was used) or it's _null_,
previously this would fail early with the case not matching.  Now,
instead, the case will match and (likely) it will fail as soon as the
value is used.
@scala-jenkins scala-jenkins added this to the 2.13.7 milestone Jul 6, 2021
@retronym
Copy link
Member

retronym commented Jul 8, 2021

My vote here would be to do nothing.

Let's revisit the motivating test:

  def foo[T : scala.reflect.ClassTag](bar: Either[String, T]): Boolean = bar match {
    case Left(_) => false
    case Right(_: T) => true
  }

If I were reviewing this code I would strongly suggest to remove the ClassTag bound, and add an explicit null check if needed (that's the only semantic difference assuming the values for bar and the class tag are "trustworthy", ie the haven't been asInstanceOf-ed by the caller.) The resulting code would be clearer and would not incur the warning.

  def foo[T](bar: Either[String, T]): Boolean = bar match {
    case Left(_) => false
    case Right(t) => true // or if (t == null) x else y
  }

A valid use case might be:

object Scabug {
  def foo[T : scala.reflect.ClassTag](bar: Either[String, Any]): Boolean = bar match {
    case Left(_) => false
    case Right(_: T) => true
  }
}

Here the non-exhaustive warning is helpful.

@dwijnand
Copy link
Member Author

dwijnand commented Jul 8, 2021

I'm still inclined to try to get rid of the unhelpful non-exhaustive warning in the motivating case, but likely it's spurred on by my cost fallacy.

I'm fairly certain the previous version of that motivating case didn't have the ClassTag, but the type test was causing the unchecked warning that led to the introduction of the ClassTag. This PR also gets rid of that unchecked warning because we're happy to trust that T means T.

Worth going on? Worth trying to find a way to keep that part only? That's probably just that 1-line checkCheckable call change.

@lrytz
Copy link
Member

lrytz commented Jul 8, 2021

As mentioned offline, IMO we cannot change the semantics wrt to how null is matched.

@retronym
Copy link
Member

retronym commented Jul 8, 2021

Yeah, there is an inconsistency between this pattern that gives a warning:

object O {
 def foo[T](bar: Either[String, T]): Boolean = bar match {
    case Left(_) => false
    case Right(_: T) => true // warning: abstract type pattern T is unchecked since it is eliminated by erasure
  }
}

vs:

object O {
 def foo[T](bar: Either[String, T]): Boolean = bar match {
    case _: Left[String, T] => false
    case _: Right[String, T] => true // no warning, a runtime test of `bar.isInstanceOf[Right]` implies that the value is a `Right[String, T]`
  }
}

But the question still stands, is it common enough to write Right(_: T) in this sort of code? This part of the compiler is hard to change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Invalid "may not be exhaustive" compiler warning with matches and ClassTag[T] in 2.13.4+

4 participants