diff --git a/compiler/src/dotty/tools/dotc/transform/localopt/FormatChecker.scala b/compiler/src/dotty/tools/dotc/transform/localopt/FormatChecker.scala index 142a9db3a3ce..83ec7fb8399e 100644 --- a/compiler/src/dotty/tools/dotc/transform/localopt/FormatChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/localopt/FormatChecker.scala @@ -126,7 +126,7 @@ class TypedFormatChecker(partsElems: List[Tree], parts: List[String], args: List def at(g: SpecGroup): Int = descriptor.start(g.ordinal) def end(g: SpecGroup): Int = descriptor.end(g.ordinal) def offset(g: SpecGroup, i: Int = 0): Int = at(g) + i - def group(g: SpecGroup): Option[String] = Option(descriptor.group(g.ordinal)).asInstanceOf[Option[String]] + def group(g: SpecGroup): Option[String] = Option(descriptor.group(g.ordinal)) def stringOf(g: SpecGroup): String = group(g).getOrElse("") def intOf(g: SpecGroup): Option[Int] = group(g).map(_.toInt) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index a0882a81311e..c5ded4e22dbf 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1922,7 +1922,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer NoType } - pt match { + pt.stripNull() match { case pt: TypeVar if untpd.isFunctionWithUnknownParamType(tree) && !calleeType.exists => // try to instantiate `pt` if this is possible. If it does not diff --git a/library/src/scala/Option.scala b/library/src/scala/Option.scala index 894eade2445a..b2eadf2c1be3 100644 --- a/library/src/scala/Option.scala +++ b/library/src/scala/Option.scala @@ -28,7 +28,7 @@ object Option { * @param x the value * @return Some(value) if value != null, None if value == null */ - def apply[A](x: A): Option[A] = if (x == null) None else Some(x) + def apply[A](x: A | Null): Option[A] = if (x == null) None else Some(x) /** An Option factory which returns `None` in a manner consistent with * the collections hierarchy. diff --git a/library/src/scala/Predef.scala b/library/src/scala/Predef.scala index 48030f2f1232..8eb06039b2dd 100644 --- a/library/src/scala/Predef.scala +++ b/library/src/scala/Predef.scala @@ -594,10 +594,6 @@ object Predef extends LowPriorityImplicits { inline infix def ne(inline y: AnyRef | Null): Boolean = !(x eq y) - extension (opt: Option.type) - @experimental - inline def fromNullable[T](t: T | Null): Option[T] = Option(t).asInstanceOf[Option[T]] - /** A type supporting Self-based type classes. * * A is TC diff --git a/library/src/scala/concurrent/impl/Promise.scala b/library/src/scala/concurrent/impl/Promise.scala index d9bf2879e155..2ca2228d159f 100644 --- a/library/src/scala/concurrent/impl/Promise.scala +++ b/library/src/scala/concurrent/impl/Promise.scala @@ -274,7 +274,7 @@ private[concurrent] object Promise { override final def isCompleted: Boolean = value0 ne null - override final def value: Option[Try[T]] = Option(value0).asInstanceOf[Option[Try[T]]] + override final def value: Option[Try[T]] = Option(value0) @tailrec // returns null if not completed private final def value0: Try[T] | Null = { diff --git a/library/src/scala/quoted/FromExpr.scala b/library/src/scala/quoted/FromExpr.scala index 2d9e3ebc5ab6..fb230c6d22b9 100644 --- a/library/src/scala/quoted/FromExpr.scala +++ b/library/src/scala/quoted/FromExpr.scala @@ -104,7 +104,7 @@ object FromExpr { */ given OptionFromExpr[T](using Type[T], FromExpr[T]): FromExpr[Option[T]] with { def unapply(x: Expr[Option[T]])(using Quotes) = x match { - case '{ Option[T](${Expr(y)}) } => Some(Option(y)) + case '{ Option[T](${Expr(y)}: T) } => Some(Option(y)) case '{ None } => Some(None) case '{ ${Expr(opt)} : Some[T] } => Some(opt) case _ => None diff --git a/library/src/scala/runtime/stdLibPatches/Predef.scala b/library/src/scala/runtime/stdLibPatches/Predef.scala index ed4cf207c925..8fb435f39801 100644 --- a/library/src/scala/runtime/stdLibPatches/Predef.scala +++ b/library/src/scala/runtime/stdLibPatches/Predef.scala @@ -66,10 +66,6 @@ object Predef: inline infix def ne(inline y: AnyRef | Null): Boolean = !(x eq y) - extension (opt: Option.type) - @experimental - inline def fromNullable[T](t: T | Null): Option[T] = Option(t).asInstanceOf[Option[T]] - /** A type supporting Self-based type classes. * * A is TC diff --git a/scaladoc/src/dotty/tools/scaladoc/SourceLinks.scala b/scaladoc/src/dotty/tools/scaladoc/SourceLinks.scala index 9a79c5a84fe1..00344aa5ad75 100644 --- a/scaladoc/src/dotty/tools/scaladoc/SourceLinks.scala +++ b/scaladoc/src/dotty/tools/scaladoc/SourceLinks.scala @@ -74,8 +74,8 @@ class SourceLinkParser(revision: Option[String]) extends ArgParser[SourceLink]: else Right(TemplateSourceLink(supported.foldLeft(string)((template, pattern) => template.replace(pattern, SupportedScalaDocPatternReplacements(pattern))))) case KnownProvider(name: String, organization: String, repo: String, rawRevision, rawSubPath) => - val subPath = Option.fromNullable(rawSubPath).fold("")("/" + _.drop(1)) - val pathRev = Option.fromNullable(rawRevision).map(_.drop(1)).orElse(revision) + val subPath = Option(rawSubPath).fold("")("/" + _.drop(1)) + val pathRev = Option(rawRevision).map(_.drop(1)).orElse(revision) def withRevision(template: String => SourceLink) = pathRev.fold(Left(s"No revision provided"))(r => Right(template(r))) diff --git a/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteLoader.scala b/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteLoader.scala index e0834ee78ecf..af0d1208c5cb 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteLoader.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteLoader.scala @@ -116,8 +116,8 @@ class StaticSiteLoader(val root: File, val args: Scaladoc.Args)(using StaticSite def loadBlog(): Option[LoadedTemplate] = { val blogConfig = BlogParser.readYml(root) - val rootPath = Option.fromNullable(blogConfig.input).map(input => ctx.resolveNewBlogPath(input)).getOrElse(ctx.blogPath) - val defaultDirectory = Option.fromNullable(blogConfig.output).getOrElse("blog") + val rootPath = Option(blogConfig.input).map(input => ctx.resolveNewBlogPath(input)).getOrElse(ctx.blogPath) + val defaultDirectory = Option(blogConfig.output).getOrElse("blog") type Date = (String, String, String) if (!Files.exists(rootPath) || blogConfig.hidden) None diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala index a84137caa5a7..0b38af38a3b3 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala @@ -277,7 +277,7 @@ class SymOpsWithLinkCache: then externalLinkCache(csym.associatedFile) else { def calculatePath(file: AbstractFile): String = file.underlyingSource.filter(_ != file).fold("")(f => calculatePath(f) + "/") + file.path - val calculatedLink = Option.fromNullable(csym.associatedFile).map(f => calculatePath(f)).flatMap { path => + val calculatedLink = Option(csym.associatedFile).map(f => calculatePath(f)).flatMap { path => dctx.externalDocumentationLinks.find(_.originRegexes.exists(r => r.matches(path))) } externalLinkCache += (csym.associatedFile -> calculatedLink) diff --git a/tests/explicit-nulls/neg/from-nullable.scala b/tests/explicit-nulls/neg/from-nullable.scala deleted file mode 100644 index ab4ab7f63e8e..000000000000 --- a/tests/explicit-nulls/neg/from-nullable.scala +++ /dev/null @@ -1,6 +0,0 @@ -import scala.annotation.experimental - -@experimental def testFromNullable = - val s: String | Null = "abc" - val sopt1: Option[String] = Option(s) // error - val sopt2: Option[String] = Option.fromNullable(s) // ok \ No newline at end of file diff --git a/tests/explicit-nulls/run/from-nullable.scala b/tests/explicit-nulls/run/from-nullable.scala index 6f01e402e790..aa1ce876be92 100644 --- a/tests/explicit-nulls/run/from-nullable.scala +++ b/tests/explicit-nulls/run/from-nullable.scala @@ -5,8 +5,8 @@ object Test: val s1: String | Null = "hello" val s2: String | Null = null - val opts1: Option[String] = Option.fromNullable(s1) - val opts2: Option[String] = Option.fromNullable(s2) + val opts1: Option[String] = Option(s1) + val opts2: Option[String] = Option(s2) opts1 match case Some(s) => println(s) diff --git a/tests/pos/i24206.scala b/tests/pos/i24206.scala index 8f2fd7976597..f802044c7638 100644 --- a/tests/pos/i24206.scala +++ b/tests/pos/i24206.scala @@ -13,4 +13,7 @@ class DispatchQuery: trait Result def getAll(nameFilter: Option[String => Boolean]): List[Result] = ??? def get(collectionName: String): List[Result] = - getAll(Option(_.startsWith(collectionName))) \ No newline at end of file + getAll(Option(_.startsWith(collectionName))) + +def f[T](x: T | Null): T = ??? +val _: Any => Any = f(x => x) diff --git a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala index d57f19112659..c249721f6a6d 100644 --- a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala +++ b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala @@ -79,9 +79,6 @@ val experimentalDefinitionInLibrary = Set( "scala.quoted.Quotes.reflectModule.RenameSelectorModule.apply", "scala.quoted.Quotes.reflectModule.SimpleSelectorModule.apply", - // New feature: fromNullable for explicit nulls - "scala.Predef$.fromNullable", - // New feature: modularity "scala.Precise", "scala.annotation.internal.WitnessNames",