Skip to content

Commit 15ae0aa

Browse files
authored
Merge pull request #9577 from dotty-staging/move-Not
Rename scala.implicits.Not to scala.util.Not
2 parents 71e9e21 + 3217bc1 commit 15ae0aa

File tree

7 files changed

+62
-11
lines changed

7 files changed

+62
-11
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,7 @@ class Definitions {
743743
@tu lazy val TypeBox_CAP: TypeSymbol = TypeBoxClass.requiredType(tpnme.CAP)
744744

745745
@tu lazy val MatchCaseClass: ClassSymbol = requiredClass("scala.internal.MatchCase")
746-
@tu lazy val NotClass: ClassSymbol = requiredClass("scala.implicits.Not")
746+
@tu lazy val NotClass: ClassSymbol = requiredClass("scala.util.Not")
747747
@tu lazy val Not_value: Symbol = NotClass.companionModule.requiredMethod(nme.value)
748748

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

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1232,7 +1232,7 @@ trait Implicits:
12321232
|According to the new implicit resolution rules this is no longer possible;
12331233
|the search will fail with a global ambiguity error instead.
12341234
|
1235-
|Consider using the scala.implicits.Not class to implement similar functionality.""",
1235+
|Consider using the scala.util.Not class to implement similar functionality.""",
12361236
ctx.source.atSpan(span))
12371237

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

compiler/test-resources/repl/importFromObj

+8-8
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

+1-1
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

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