Skip to content

Commit 3217bc1

Browse files
committed
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.
1 parent d5efc05 commit 3217bc1

File tree

7 files changed

+62
-11
lines changed

7 files changed

+62
-11
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ class Definitions {
738738
@tu lazy val TypeBox_CAP: TypeSymbol = TypeBoxClass.requiredType(tpnme.CAP)
739739

740740
@tu lazy val MatchCaseClass: ClassSymbol = requiredClass("scala.internal.MatchCase")
741-
@tu lazy val NotClass: ClassSymbol = requiredClass("scala.implicits.Not")
741+
@tu lazy val NotClass: ClassSymbol = requiredClass("scala.util.Not")
742742
@tu lazy val Not_value: Symbol = NotClass.companionModule.requiredMethod(nme.value)
743743

744744
@tu lazy val ValueOfClass: ClassSymbol = requiredClass("scala.ValueOf")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1234,7 +1234,7 @@ trait Implicits:
12341234
|According to the new implicit resolution rules this is no longer possible;
12351235
|the search will fail with a global ambiguity error instead.
12361236
|
1237-
|Consider using the scala.implicits.Not class to implement similar functionality.""",
1237+
|Consider using the scala.util.Not class to implement similar functionality.""",
12381238
ctx.source.atSpan(span))
12391239

12401240
/** A relation that influences the order in which implicits are tried.

compiler/test-resources/repl/importFromObj

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ scala> buf += xs
1111
| Required: Int
1212
scala> buf ++= xs
1313
val res0: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)
14-
scala> import util.foo
15-
1 | import util.foo
16-
| ^^^
17-
| value foo is not a member of util
18-
scala> import util.foo.bar
19-
1 | import util.foo.bar
20-
| ^^^^^^^^
21-
| value foo is not a member of util
14+
scala> import util.foobar
15+
1 | import util.foobar
16+
| ^^^^^^
17+
| value foobar is not a member of util
18+
scala> import util.foobar.bar
19+
1 | import util.foobar.bar
20+
| ^^^^^^^^^^^
21+
| value foobar is not a member of util

docs/docs/reference/changed-features/implicit-resolution.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ which means that the alternative `c` would be chosen as solution!
107107
Scala 2's somewhat puzzling behavior with respect to ambiguity has been exploited to implement
108108
the analogue of a "negated" search in implicit resolution, where a query `Q1` fails if some
109109
other query `Q2` succeeds and `Q1` succeeds if `Q2` fails. With the new cleaned up behavior
110-
these techniques no longer work. But there is now a new special type `scala.implicits.Not`
110+
these techniques no longer work. But there is now a new special type `scala.util.Not`
111111
which implements negation directly. For any query type `Q`: `Not[Q]` succeeds if and only if
112112
the implicit search for `Q` fails.
113113

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package scala
2+
3+
package object implicits {
4+
@deprecated("scala.implicits.Not has been renamed scala.util.Not", "0.27.0")
5+
type Not[A] = scala.util.Not[A]
6+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package scala.util
2+
3+
/** A special class used to implement negation in implicit search.
4+
*
5+
* Consider the problem of using implicit `i1` for a query type `D` if an implicit
6+
* for some other class `C` is available, and using an implicit `i2` if no implicit
7+
* value of type `C` is available. If we do not want to prioritize `i1` and `i2` by
8+
* putting them in different traits we can instead define the following:
9+
*
10+
* given i1: D(using ev: C) = ...
11+
* given i2: D(using ev: Not[C]) = ...
12+
*
13+
* `Not` is treated specially in implicit search, similar to the way logical negation
14+
* is treated in Prolog: The implicit search for `Not[C]` succeeds if and only if the implicit
15+
* search for `C` fails.
16+
*
17+
* In Scala 2 this form of negation can be simulated by setting up a conditional
18+
* ambiguous implicit and an unconditional fallback, the way it is done with the
19+
* `default`, `amb1` and `amb2` methods below. Due to the way these two methods are
20+
* defined, `Not` is also usable from Scala 2.
21+
*
22+
* In Dotty, ambiguity is a global error, and therefore cannot be used to implement negation.
23+
* Instead, `Not` is treated natively in implicit search.
24+
*/
25+
final class Not[+T] private ()
26+
27+
trait LowPriorityNot {
28+
29+
/** A fallback method used to emulate negation in Scala 2 */
30+
given default[T] as Not[T] = Not.value
31+
}
32+
object Not extends LowPriorityNot {
33+
34+
/** A value of type `Not` to signal a successful search for `Not[C]` (i.e. a failing
35+
* search for `C`). A reference to this value will be explicitly constructed by Dotty's
36+
* implicit search algorithm
37+
*/
38+
def value: Not[Nothing] = new Not[Nothing]()
39+
40+
/** One of two ambiguous methods used to emulate negation in Scala 2 */
41+
given amb1[T](using ev: T) as Not[T] = ???
42+
43+
/** One of two ambiguous methods used to emulate negation in Scala 2 */
44+
given amb2[T](using ev: T) as Not[T] = ???
45+
}

0 commit comments

Comments
 (0)