From 3217bc14a309718a79a4d7a99553664974a8d754 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Mon, 17 Aug 2020 16:50:41 +0200 Subject: [PATCH] Rename scala.implicits.Not to scala.util.Not Having a package just for this type seems weird, especially since we no longer call them "implicits". After discussion it was deemed not useful enough to go in the root scala package, so `scala.util` it is. --- .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../dotty/tools/dotc/typer/Implicits.scala | 2 +- compiler/test-resources/repl/importFromObj | 16 +++---- .../changed-features/implicit-resolution.md | 2 +- .../scala/implicits/package.scala | 6 +++ library/src-bootstrapped/scala/util/Not.scala | 45 +++++++++++++++++++ .../scala/implicits/Not.scala | 0 7 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 library/src-bootstrapped/scala/implicits/package.scala create mode 100644 library/src-bootstrapped/scala/util/Not.scala rename library/{src => src-non-bootstrapped}/scala/implicits/Not.scala (100%) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index a8004c8230bb..86f90b2c505e 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -738,7 +738,7 @@ class Definitions { @tu lazy val TypeBox_CAP: TypeSymbol = TypeBoxClass.requiredType(tpnme.CAP) @tu lazy val MatchCaseClass: ClassSymbol = requiredClass("scala.internal.MatchCase") - @tu lazy val NotClass: ClassSymbol = requiredClass("scala.implicits.Not") + @tu lazy val NotClass: ClassSymbol = requiredClass("scala.util.Not") @tu lazy val Not_value: Symbol = NotClass.companionModule.requiredMethod(nme.value) @tu lazy val ValueOfClass: ClassSymbol = requiredClass("scala.ValueOf") diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 85bbafdc3426..267ed18ffbc4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1234,7 +1234,7 @@ trait Implicits: |According to the new implicit resolution rules this is no longer possible; |the search will fail with a global ambiguity error instead. | - |Consider using the scala.implicits.Not class to implement similar functionality.""", + |Consider using the scala.util.Not class to implement similar functionality.""", ctx.source.atSpan(span)) /** A relation that influences the order in which implicits are tried. diff --git a/compiler/test-resources/repl/importFromObj b/compiler/test-resources/repl/importFromObj index 4192e6d8d4c5..144859891519 100644 --- a/compiler/test-resources/repl/importFromObj +++ b/compiler/test-resources/repl/importFromObj @@ -11,11 +11,11 @@ scala> buf += xs | Required: Int scala> buf ++= xs val res0: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3) -scala> import util.foo -1 | import util.foo - | ^^^ - | value foo is not a member of util -scala> import util.foo.bar -1 | import util.foo.bar - | ^^^^^^^^ - | value foo is not a member of util +scala> import util.foobar +1 | import util.foobar + | ^^^^^^ + | value foobar is not a member of util +scala> import util.foobar.bar +1 | import util.foobar.bar + | ^^^^^^^^^^^ + | value foobar is not a member of util diff --git a/docs/docs/reference/changed-features/implicit-resolution.md b/docs/docs/reference/changed-features/implicit-resolution.md index 6732e7e706d5..174baa089f83 100644 --- a/docs/docs/reference/changed-features/implicit-resolution.md +++ b/docs/docs/reference/changed-features/implicit-resolution.md @@ -107,7 +107,7 @@ which means that the alternative `c` would be chosen as solution! Scala 2's somewhat puzzling behavior with respect to ambiguity has been exploited to implement the analogue of a "negated" search in implicit resolution, where a query `Q1` fails if some other query `Q2` succeeds and `Q1` succeeds if `Q2` fails. With the new cleaned up behavior -these techniques no longer work. But there is now a new special type `scala.implicits.Not` +these techniques no longer work. But there is now a new special type `scala.util.Not` which implements negation directly. For any query type `Q`: `Not[Q]` succeeds if and only if the implicit search for `Q` fails. diff --git a/library/src-bootstrapped/scala/implicits/package.scala b/library/src-bootstrapped/scala/implicits/package.scala new file mode 100644 index 000000000000..089096d6ff59 --- /dev/null +++ b/library/src-bootstrapped/scala/implicits/package.scala @@ -0,0 +1,6 @@ +package scala + +package object implicits { + @deprecated("scala.implicits.Not has been renamed scala.util.Not", "0.27.0") + type Not[A] = scala.util.Not[A] +} diff --git a/library/src-bootstrapped/scala/util/Not.scala b/library/src-bootstrapped/scala/util/Not.scala new file mode 100644 index 000000000000..398b620747b8 --- /dev/null +++ b/library/src-bootstrapped/scala/util/Not.scala @@ -0,0 +1,45 @@ +package scala.util + +/** A special class used to implement negation in implicit search. + * + * Consider the problem of using implicit `i1` for a query type `D` if an implicit + * for some other class `C` is available, and using an implicit `i2` if no implicit + * value of type `C` is available. If we do not want to prioritize `i1` and `i2` by + * putting them in different traits we can instead define the following: + * + * given i1: D(using ev: C) = ... + * given i2: D(using ev: Not[C]) = ... + * + * `Not` is treated specially in implicit search, similar to the way logical negation + * is treated in Prolog: The implicit search for `Not[C]` succeeds if and only if the implicit + * search for `C` fails. + * + * In Scala 2 this form of negation can be simulated by setting up a conditional + * ambiguous implicit and an unconditional fallback, the way it is done with the + * `default`, `amb1` and `amb2` methods below. Due to the way these two methods are + * defined, `Not` is also usable from Scala 2. + * + * In Dotty, ambiguity is a global error, and therefore cannot be used to implement negation. + * Instead, `Not` is treated natively in implicit search. + */ +final class Not[+T] private () + +trait LowPriorityNot { + + /** A fallback method used to emulate negation in Scala 2 */ + given default[T] as Not[T] = Not.value +} +object Not extends LowPriorityNot { + + /** A value of type `Not` to signal a successful search for `Not[C]` (i.e. a failing + * search for `C`). A reference to this value will be explicitly constructed by Dotty's + * implicit search algorithm + */ + def value: Not[Nothing] = new Not[Nothing]() + + /** One of two ambiguous methods used to emulate negation in Scala 2 */ + given amb1[T](using ev: T) as Not[T] = ??? + + /** One of two ambiguous methods used to emulate negation in Scala 2 */ + given amb2[T](using ev: T) as Not[T] = ??? +} diff --git a/library/src/scala/implicits/Not.scala b/library/src-non-bootstrapped/scala/implicits/Not.scala similarity index 100% rename from library/src/scala/implicits/Not.scala rename to library/src-non-bootstrapped/scala/implicits/Not.scala