Skip to content

Commit 79ce853

Browse files
authored
Better support for nullability in Option.apply and drop Option.fromNullable (#24238)
Yes, this is not the most ideal signature for `Option.apply` but it allows at least to drop `Option.fromNullable` and an easier migration to explicit nulls (no need to add `fromNullable` everywhere). Superseed #24231 in the sense where we focus here on the nullability issue rather than the more global issue. Reverts #24230 Relates to #24206
2 parents 41d321d + e603af7 commit 79ce853

File tree

14 files changed

+16
-30
lines changed

14 files changed

+16
-30
lines changed

compiler/src/dotty/tools/dotc/transform/localopt/FormatChecker.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class TypedFormatChecker(partsElems: List[Tree], parts: List[String], args: List
126126
def at(g: SpecGroup): Int = descriptor.start(g.ordinal)
127127
def end(g: SpecGroup): Int = descriptor.end(g.ordinal)
128128
def offset(g: SpecGroup, i: Int = 0): Int = at(g) + i
129-
def group(g: SpecGroup): Option[String] = Option(descriptor.group(g.ordinal)).asInstanceOf[Option[String]]
129+
def group(g: SpecGroup): Option[String] = Option(descriptor.group(g.ordinal))
130130
def stringOf(g: SpecGroup): String = group(g).getOrElse("")
131131
def intOf(g: SpecGroup): Option[Int] = group(g).map(_.toInt)
132132

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1922,7 +1922,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
19221922
NoType
19231923
}
19241924

1925-
pt match {
1925+
pt.stripNull() match {
19261926
case pt: TypeVar
19271927
if untpd.isFunctionWithUnknownParamType(tree) && !calleeType.exists =>
19281928
// try to instantiate `pt` if this is possible. If it does not

library/src/scala/Option.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ object Option {
2828
* @param x the value
2929
* @return Some(value) if value != null, None if value == null
3030
*/
31-
def apply[A](x: A): Option[A] = if (x == null) None else Some(x)
31+
def apply[A](x: A | Null): Option[A] = if (x == null) None else Some(x)
3232

3333
/** An Option factory which returns `None` in a manner consistent with
3434
* the collections hierarchy.

library/src/scala/Predef.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -594,10 +594,6 @@ object Predef extends LowPriorityImplicits {
594594
inline infix def ne(inline y: AnyRef | Null): Boolean =
595595
!(x eq y)
596596

597-
extension (opt: Option.type)
598-
@experimental
599-
inline def fromNullable[T](t: T | Null): Option[T] = Option(t).asInstanceOf[Option[T]]
600-
601597
/** A type supporting Self-based type classes.
602598
*
603599
* A is TC

library/src/scala/concurrent/impl/Promise.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ private[concurrent] object Promise {
275275

276276
override final def isCompleted: Boolean = value0 ne null
277277

278-
override final def value: Option[Try[T]] = Option(value0).asInstanceOf[Option[Try[T]]]
278+
override final def value: Option[Try[T]] = Option(value0)
279279

280280
@tailrec // returns null if not completed
281281
private final def value0: Try[T] | Null = {

library/src/scala/quoted/FromExpr.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ object FromExpr {
104104
*/
105105
given OptionFromExpr[T](using Type[T], FromExpr[T]): FromExpr[Option[T]] with {
106106
def unapply(x: Expr[Option[T]])(using Quotes) = x match {
107-
case '{ Option[T](${Expr(y)}) } => Some(Option(y))
107+
case '{ Option[T](${Expr(y)}: T) } => Some(Option(y))
108108
case '{ None } => Some(None)
109109
case '{ ${Expr(opt)} : Some[T] } => Some(opt)
110110
case _ => None

library/src/scala/runtime/stdLibPatches/Predef.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,6 @@ object Predef:
6666
inline infix def ne(inline y: AnyRef | Null): Boolean =
6767
!(x eq y)
6868

69-
extension (opt: Option.type)
70-
@experimental
71-
inline def fromNullable[T](t: T | Null): Option[T] = Option(t).asInstanceOf[Option[T]]
72-
7369
/** A type supporting Self-based type classes.
7470
*
7571
* A is TC

scaladoc/src/dotty/tools/scaladoc/SourceLinks.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ class SourceLinkParser(revision: Option[String]) extends ArgParser[SourceLink]:
7474
else Right(TemplateSourceLink(supported.foldLeft(string)((template, pattern) =>
7575
template.replace(pattern, SupportedScalaDocPatternReplacements(pattern)))))
7676
case KnownProvider(name: String, organization: String, repo: String, rawRevision, rawSubPath) =>
77-
val subPath = Option.fromNullable(rawSubPath).fold("")("/" + _.drop(1))
78-
val pathRev = Option.fromNullable(rawRevision).map(_.drop(1)).orElse(revision)
77+
val subPath = Option(rawSubPath).fold("")("/" + _.drop(1))
78+
val pathRev = Option(rawRevision).map(_.drop(1)).orElse(revision)
7979

8080
def withRevision(template: String => SourceLink) =
8181
pathRev.fold(Left(s"No revision provided"))(r => Right(template(r)))

scaladoc/src/dotty/tools/scaladoc/site/StaticSiteLoader.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ class StaticSiteLoader(val root: File, val args: Scaladoc.Args)(using StaticSite
116116

117117
def loadBlog(): Option[LoadedTemplate] = {
118118
val blogConfig = BlogParser.readYml(root)
119-
val rootPath = Option.fromNullable(blogConfig.input).map(input => ctx.resolveNewBlogPath(input)).getOrElse(ctx.blogPath)
120-
val defaultDirectory = Option.fromNullable(blogConfig.output).getOrElse("blog")
119+
val rootPath = Option(blogConfig.input).map(input => ctx.resolveNewBlogPath(input)).getOrElse(ctx.blogPath)
120+
val defaultDirectory = Option(blogConfig.output).getOrElse("blog")
121121

122122
type Date = (String, String, String)
123123
if (!Files.exists(rootPath) || blogConfig.hidden) None

scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ class SymOpsWithLinkCache:
277277
then externalLinkCache(csym.associatedFile)
278278
else {
279279
def calculatePath(file: AbstractFile): String = file.underlyingSource.filter(_ != file).fold("")(f => calculatePath(f) + "/") + file.path
280-
val calculatedLink = Option.fromNullable(csym.associatedFile).map(f => calculatePath(f)).flatMap { path =>
280+
val calculatedLink = Option(csym.associatedFile).map(f => calculatePath(f)).flatMap { path =>
281281
dctx.externalDocumentationLinks.find(_.originRegexes.exists(r => r.matches(path)))
282282
}
283283
externalLinkCache += (csym.associatedFile -> calculatedLink)

0 commit comments

Comments
 (0)