Skip to content

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

Closed
@milessabin

Description

@milessabin

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions