Skip to content

Unhelpful error message with -Yexplicit-nulls or unhelpful typing of String#trim #7883

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

Closed
milessabin opened this issue Dec 31, 2019 · 4 comments

Comments

@milessabin
Copy link
Contributor

milessabin commented Dec 31, 2019

The following compiles as expected without -Yexplicit-nulls, but with -Yexplicit-nulls specified produces an at best unhelpful error message,

import scala.util.matching.Regex

object Test extends App {
  def head(s: String, r: Regex): Option[(String, String)] =
    s.trim match {
      case r(hd, tl) => Some((hd, tl))
      case _ => None
    }
}
sbt:dotty> dotc -Yexplicit-nulls -d local/classes local/nulls.scala
[warn] Multiple main classes detected.  Run 'show discoveredMainClasses' to see the list
[info] Running (fork) dotty.tools.dotc.Main -classpath /home/miles/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.13.1.jar:/home/miles/projects/dotty/library/../out/bootstrap/dotty-library-bootstrapped/scala-0.22/dotty-library_0.22-0.22.0-bin-SNAPSHOT.jar -Yexplicit-nulls -d local/classes local/nulls.scala
-- [E127] Syntax Error: local/nulls.scala:6:11 ---------------------------------
6 |      case r(hd, tl) => Some((hd, tl))
  |           ^
  |r cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method

longer explanation available when compiling with `-explain`
-- [E006] Unbound Identifier Error: local/nulls.scala:6:30 ---------------------
6 |      case r(hd, tl) => Some((hd, tl))
  |                              ^^
  |                              Not found: hd

longer explanation available when compiling with `-explain`
-- [E006] Unbound Identifier Error: local/nulls.scala:6:34 ---------------------
6 |      case r(hd, tl) => Some((hd, tl))
  |                                  ^^
  |                                  Not found: tl

longer explanation available when compiling with `-explain`
3 errors found

Desugaring the match a bit to,

def head(s: String, r: Regex): Option[(String, String)] = {
  val st = s.trim
  r.unapplySeq(st) match {
      case Some(List(hd, tl)) => Some((hd, tl))
      case _ => None
    }
}

shows that the issue is the result type of String#trim,

sbt:dotty> dotc -Yexplicit-nulls -d local/classes local/nulls.scala
[warn] Multiple main classes detected.  Run 'show discoveredMainClasses' to see the list
[info] Running (fork) dotty.tools.dotc.Main -classpath /home/miles/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.13.1.jar:/home/miles/projects/dotty/library/../out/bootstrap/dotty-library-bootstrapped/scala-0.22/dotty-library_0.22-0.22.0-bin-SNAPSHOT.jar -Yexplicit-nulls -d local/classes local/nulls.scala
-- [E134] Type Mismatch Error: local/nulls.scala:16:8 --------------------------
16 |      r.unapplySeq(st) match {
   |      ^^^^^^^^^^^^
   |None of the overloaded alternatives of method unapplySeq in class Regex with types
   | (m: scala.util.matching.Regex.Match): Option[List[String]]
   | (c: Char): Option[List[Char]]
   | (s: CharSequence): Option[List[String]]
   |match arguments ((st : String | Null))
-- [E006] Unbound Identifier Error: local/nulls.scala:17:41 --------------------
17 |        case Some(List(hd, tl)) => Some((hd, tl))
   |                                         ^^
   |                                         Not found: hd

longer explanation available when compiling with `-explain`
-- [E006] Unbound Identifier Error: local/nulls.scala:17:45 --------------------
17 |        case Some(List(hd, tl)) => Some((hd, tl))
   |                                             ^^
   |                                             Not found: tl

longer explanation available when compiling with `-explain`
3 errors found

A workaround is to explicitly test the result of s.trim against null,

def head(s: String, r: Regex): Option[(String, String)] = {
  val st = s.trim
  if (st == null) None
  else
    st match {
      case r(hd, tl) => Some((hd, tl))
      case _ => None
    }
}
@milessabin milessabin changed the title Unhelpful error message with -Yexplicit-nulls or unhelpful typing of String#trim Unhelpful error message with -Yexplicit-nulls or unhelpful typing of String#trim Dec 31, 2019
@hrhino
Copy link
Contributor

hrhino commented Jan 1, 2020

Maybe something as simple as changing the error to value r of type (String|Null) cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method would suffice?

@milessabin
Copy link
Contributor Author

@hrhino that's not it though ... r is of type Regex. The problem is the type of s.trim.

@hrhino
Copy link
Contributor

hrhino commented Jan 1, 2020

Ah shoot; you're right.

@abeln
Copy link
Contributor

abeln commented Jan 10, 2020

This seems like a special case of #7871

@odersky odersky self-assigned this Mar 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants