Skip to content

Commit d8a1451

Browse files
authored
Merge pull request #10720 from dotty-staging/feature/rename-Not-to-NotGiven
2 parents d0db6d5 + c3f1f34 commit d8a1451

File tree

10 files changed

+62
-39
lines changed

10 files changed

+62
-39
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -841,8 +841,8 @@ class Definitions {
841841
@tu lazy val TypeBox_CAP: TypeSymbol = TypeBoxClass.requiredType(tpnme.CAP)
842842

843843
@tu lazy val MatchCaseClass: ClassSymbol = requiredClass("scala.runtime.MatchCase")
844-
@tu lazy val NotClass: ClassSymbol = requiredClass("scala.util.Not")
845-
@tu lazy val Not_value: Symbol = NotClass.companionModule.requiredMethod(nme.value)
844+
@tu lazy val NotGivenClass: ClassSymbol = requiredClass("scala.util.NotGiven")
845+
@tu lazy val NotGiven_value: Symbol = NotGivenClass.companionModule.requiredMethod(nme.value)
846846

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

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,7 +1072,7 @@ trait Implicits:
10721072
else ViewProto(wildApprox(argument.tpe.widen), wildApprox(pt))
10731073
// Not clear whether we need to drop the `.widen` here. All tests pass with it in place, though.
10741074

1075-
val isNot: Boolean = wildProto.classSymbol == defn.NotClass
1075+
val isNotGiven: Boolean = wildProto.classSymbol == defn.NotGivenClass
10761076

10771077
/** Try to type-check implicit reference, after checking that this is not
10781078
* a diverging search
@@ -1201,10 +1201,10 @@ trait Implicits:
12011201
}
12021202

12031203
def negateIfNot(result: SearchResult) =
1204-
if (isNot)
1204+
if (isNotGiven)
12051205
result match {
12061206
case _: SearchFailure =>
1207-
SearchSuccess(ref(defn.Not_value), defn.Not_value.termRef, 0)(
1207+
SearchSuccess(ref(defn.NotGiven_value), defn.NotGiven_value.termRef, 0)(
12081208
ctx.typerState.fresh().setCommittable(true),
12091209
ctx.gadt
12101210
)
@@ -1220,7 +1220,7 @@ trait Implicits:
12201220
|According to the new implicit resolution rules this is no longer possible;
12211221
|the search will fail with a global ambiguity error instead.
12221222
|
1223-
|Consider using the scala.util.Not class to implement similar functionality.""",
1223+
|Consider using the scala.util.NotGiven class to implement similar functionality.""",
12241224
ctx.source.atSpan(span))
12251225

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

docs/docs/reference/contextual/givens.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,29 @@ instance named `ctx` is established by matching against the first half of the `p
106106

107107
In each case, a pattern-bound given instance consists of `given` and a type `T`. The pattern matches exactly the same selectors as the type ascription pattern `_: T`.
108108

109+
## Negated Givens
110+
111+
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.util.NotGiven` which implements negation directly.
112+
113+
For any query type `Q`, `NotGiven[Q]` succeeds if and only if the implicit
114+
search for `Q` fails, for example:
115+
116+
```scala
117+
import scala.util.NotGiven
118+
119+
trait Tagged[A]
120+
121+
case class Foo[A](value: Boolean)
122+
object Foo:
123+
given fooTagged[A](using Tagged[A]): Foo[A] = Foo(true)
124+
given fooNotTagged[A](using NotGiven[Tagged[A]]): Foo[A] = Foo(false)
125+
126+
@main def test() =
127+
given Tagged[Int] with {}
128+
assert(implicitly[Foo[Int]].value) // fooTagged is found
129+
assert(!implicitly[Foo[String]].value) // fooNotTagged is found
130+
```
131+
109132
## Given Instance Initialization
110133

111134
A given instance without type or context parameters is initialized on-demand, the first

library/src/scala/util/Not.scala renamed to library/src/scala/util/NotGiven.scala

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,38 @@ package scala.util
88
* putting them in different traits we can instead define the following:
99
*
1010
* given i1: D(using ev: C) = ...
11-
* given i2: D(using ev: Not[C]) = ...
11+
* given i2: D(using ev: NotGiven[C]) = ...
1212
*
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
13+
* `NotGiven` is treated specially in implicit search, similar to the way logical negation
14+
* is treated in Prolog: The implicit search for `NotGiven[C]` succeeds if and only if the implicit
1515
* search for `C` fails.
1616
*
1717
* In Scala 2 this form of negation can be simulated by setting up a conditional
1818
* ambiguous implicit and an unconditional fallback, the way it is done with the
1919
* `default`, `amb1` and `amb2` methods below. Due to the way these two methods are
20-
* defined, `Not` is also usable from Scala 2.
20+
* defined, `NotGiven` is also usable from Scala 2.
2121
*
2222
* In Dotty, ambiguity is a global error, and therefore cannot be used to implement negation.
23-
* Instead, `Not` is treated natively in implicit search.
23+
* Instead, `NotGiven` is treated natively in implicit search.
2424
*/
25-
final class Not[+T] private ()
25+
final class NotGiven[+T] private ()
2626

27-
trait LowPriorityNot {
27+
trait LowPriorityNotGiven {
2828

2929
/** A fallback method used to emulate negation in Scala 2 */
30-
given default[T]: Not[T] = Not.value
30+
given default[T]: NotGiven[T] = NotGiven.value
3131
}
32-
object Not extends LowPriorityNot {
32+
object NotGiven extends LowPriorityNotGiven {
3333

34-
/** A value of type `Not` to signal a successful search for `Not[C]` (i.e. a failing
34+
/** A value of type `NotGiven` to signal a successful search for `NotGiven[C]` (i.e. a failing
3535
* search for `C`). A reference to this value will be explicitly constructed by Dotty's
3636
* implicit search algorithm
3737
*/
38-
def value: Not[Nothing] = new Not[Nothing]()
38+
def value: NotGiven[Nothing] = new NotGiven[Nothing]()
3939

4040
/** One of two ambiguous methods used to emulate negation in Scala 2 */
41-
given amb1[T](using ev: T): Not[T] = ???
41+
given amb1[T](using ev: T): NotGiven[T] = ???
4242

4343
/** One of two ambiguous methods used to emulate negation in Scala 2 */
44-
given amb2[T](using ev: T): Not[T] = ???
44+
given amb2[T](using ev: T): NotGiven[T] = ???
4545
}

tests/neg-macros/i9972/Macro_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package notmacro
22

3-
import scala.util.Not
3+
import scala.util.NotGiven
44

55
object Main extends App {
6-
summon[Not[T[Int]]] // error
6+
summon[NotGiven[T[Int]]] // error
77
}

tests/neg-macros/i9972b/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11

22
def test: Unit =
3-
summon[scala.util.Not[T[Int]]] // error
3+
summon[scala.util.NotGiven[T[Int]]] // error

tests/neg/i5234a.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
object Test {
2-
import scala.util.Not
2+
import scala.util.NotGiven
33

44
class Foo
55
class Bar
66
implicit def foo: Foo = ???
77
implicitly[Foo]
8-
implicitly[Not[Foo]] // error
9-
implicitly[Not[Bar]]
8+
implicitly[NotGiven[Foo]] // error
9+
implicitly[NotGiven[Bar]]
1010
}

tests/neg/i5234b.scala

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
1-
final class Not2[T] private ()
1+
final class NotGiven2[T] private ()
22

3-
trait LowPriorityNot2 {
3+
trait LowPriorityNotGiven2 {
44

55
/** A fallback method used to emulate negation in Scala 2 */
6-
implicit def default[T]: Not2[T] = Not2.value.asInstanceOf[Not2[T]]
6+
implicit def default[T]: NotGiven2[T] = NotGiven2.value.asInstanceOf[NotGiven2[T]]
77
}
8-
object Not2 extends LowPriorityNot2 {
8+
object NotGiven2 extends LowPriorityNotGiven2 {
99

10-
/** A value of type `Not` to signal a successful search for `Not[C]` (i.e. a failing
10+
/** A value of type `NotGiven` to signal a successful search for `NotGiven[C]` (i.e. a failing
1111
* search for `C`). A reference to this value will be explicitly constructed by
1212
* Dotty's implicit search algorithm
1313
*/
14-
def value: Not2[Nothing] = new Not2[Nothing]()
14+
def value: NotGiven2[Nothing] = new NotGiven2[Nothing]()
1515

1616
/** One of two ambiguous methods used to emulate negation in Scala 2 */
17-
implicit def amb1[T](implicit ev: T): Not2[T] = ???
17+
implicit def amb1[T](implicit ev: T): NotGiven2[T] = ???
1818

1919
/** One of two ambiguous methods used to emulate negation in Scala 2 */
20-
implicit def amb2[T](implicit ev: T): Not2[T] = ???
20+
implicit def amb2[T](implicit ev: T): NotGiven2[T] = ???
2121
}
2222

2323
object Test {
2424
class Foo
2525
class Bar
2626
implicit def foo: Foo = ???
2727
implicitly[Foo]
28-
implicitly[Not2[Foo]] // error
29-
implicitly[Not2[Bar]]
28+
implicitly[NotGiven2[Foo]] // error
29+
implicitly[NotGiven2[Bar]]
3030
}

tests/neg/i5234c.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
object Test {
2-
import scala.util.Not
2+
import scala.util.NotGiven
33

44
class Foo
55
implicit def foo: Foo = ???
66

7-
def foo[T](implicit ev: Not[T]) = ???
7+
def foo[T](implicit ev: NotGiven[T]) = ???
88
foo[Foo] // error
99
}

tests/run/i3396.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import scala.util.Not
1+
import scala.util.NotGiven
22

33
object Test {
44

@@ -9,7 +9,7 @@ object Test {
99
implicit def fooDefault[A]: Foo[A] = Foo(true)
1010
}
1111
object Foo extends FooLowPrio {
12-
implicit def fooNotTagged[A](implicit ev: Not[Tagged[A]]): Foo[A] = Foo(false)
12+
implicit def fooNotTagged[A](implicit ev: NotGiven[Tagged[A]]): Foo[A] = Foo(false)
1313
}
1414

1515

0 commit comments

Comments
 (0)