From 58e596e73bf18a8da91250eb38186b1e99a4b2fb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 Feb 2019 14:24:27 +0100 Subject: [PATCH] Implement `the` method Replaces `infer`, has the Shapeless semantics. This required moving `DottyPredef` to src-bootstrapped since Scala 2.12 can't express the semantics of `the` in a straightforward way. --- docs/docs/reference/contextual/derivation.md | 2 +- .../inferable-by-name-parameters.md | 4 +- .../reference/contextual/inferable-params.md | 10 ++--- .../contextual/relationship-implicits.md | 6 ++- docs/docs/reference/contextual/typeclasses.md | 2 +- .../src-bootstrapped/dotty/DottyPredef.scala | 38 +++++++++++++++++++ .../dotty/DottyPredef.scala | 3 -- tests/pos/reference/instances.scala | 10 ++--- tests/pos/the.scala | 12 ++++++ tests/run/implicit-disambiguation.scala | 4 +- 10 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 library/src-bootstrapped/dotty/DottyPredef.scala rename library/{src => src-non-bootstrapped}/dotty/DottyPredef.scala (95%) create mode 100644 tests/pos/the.scala diff --git a/docs/docs/reference/contextual/derivation.md b/docs/docs/reference/contextual/derivation.md index 8a14e4958967..b43efd4844e9 100644 --- a/docs/docs/reference/contextual/derivation.md +++ b/docs/docs/reference/contextual/derivation.md @@ -317,7 +317,7 @@ calling the `error` method defined in `scala.compiletime`. ```scala implied [T] with (elemEq: Eq[T]) for Eq[Tree[T]] { def eql(x: Tree[T], y: Tree[T]): Boolean = { - val ev = infer[Generic[Tree[T]]] + val ev = the[Generic[Tree[T]]] val mx = ev.reflect(x) val my = ev.reflect(y) mx.ordinal == my.ordinal && { diff --git a/docs/docs/reference/contextual/inferable-by-name-parameters.md b/docs/docs/reference/contextual/inferable-by-name-parameters.md index 9ebdbe9f5c49..3e7c01b3ecfd 100644 --- a/docs/docs/reference/contextual/inferable-by-name-parameters.md +++ b/docs/docs/reference/contextual/inferable-by-name-parameters.md @@ -19,7 +19,7 @@ implied optionCodec[T] given (ev: => Codec[T]) for Codec[Option[T]] { } } -val s = infer[Codec[Option[Int]]] +val s = the[Codec[Option[Int]]] s.write(Some(33)) s.write(None) @@ -54,7 +54,7 @@ The precise steps for constructing an inferable argument for a by-name parameter In the example above, the definition of `s` would be expanded as follows. ```scala -val s = infer[Test.Codec[Option[Int]]]( +val s = the[Test.Codec[Option[Int]]]( optionCodec[Int](intCodec)) ``` diff --git a/docs/docs/reference/contextual/inferable-params.md b/docs/docs/reference/contextual/inferable-params.md index a652e5a8f6f2..39f5229427ae 100644 --- a/docs/docs/reference/contextual/inferable-params.md +++ b/docs/docs/reference/contextual/inferable-params.md @@ -85,16 +85,16 @@ f("abc") given ctx ## Querying Implied Instances -A method `infer` in `Predef` creates an implied instance of a given type. For example, +A method `the` in `Predef` creates an implied instance of a given type. For example, the implied instance of `Ord[List[Int]]` is generated by ```scala -infer[Ord[List[Int]]] // reduces to ListOrd given IntOrd +the[Ord[List[Int]]] // reduces to ListOrd given IntOrd ``` -The `infer` method is simply defined as the identity function over an inferable parameter. +The `the` method is simply defined as the (non-widening) identity function over an inferable parameter. ```scala -def infer[T] given (x: T) = x +def the[T] given (x: T): x.type = x ``` -Functions like `infer` that have only inferable parameters are also called _context queries_. +Functions like `the` that have only inferable parameters are also called _context queries_. ## Syntax diff --git a/docs/docs/reference/contextual/relationship-implicits.md b/docs/docs/reference/contextual/relationship-implicits.md index bfb4e3517070..fd5c5b7b21a7 100644 --- a/docs/docs/reference/contextual/relationship-implicits.md +++ b/docs/docs/reference/contextual/relationship-implicits.md @@ -75,7 +75,11 @@ Explicit arguments to inferable parameters _must_ be written using `given`, mirroring the definition syntax. E.g, `max(2, 3) given IntOrd`. Scala 2 uses normal applications `max(2, 3)(IntOrd)` instead. The Scala 2 syntax has some inherent ambiguities and restrictions which are overcome by the new syntax. For instance, multiple implicit parameter lists are not available in the old syntax, even though they can be simulated using auxiliary objects in the "Aux" pattern. -The `infer` method corresponds to `implicitly` in Scala 2. +The `the` method corresponds to `implicitly` in Scala 2. +It is precisely the same as the `the` method in Shapeless. +The difference between `the` (in both versions) and `implicitly` is +that `the` can return a more precise type than the type that was +asked for. ### Context Bounds diff --git a/docs/docs/reference/contextual/typeclasses.md b/docs/docs/reference/contextual/typeclasses.md index f14516692afc..95c7c17fcfe0 100644 --- a/docs/docs/reference/contextual/typeclasses.md +++ b/docs/docs/reference/contextual/typeclasses.md @@ -17,7 +17,7 @@ trait Monoid[T] extends SemiGroup[T] { def unit: T } object Monoid { - def apply[T] = infer[Monoid[T]] + def apply[T] = the[Monoid[T]] } implied for Monoid[String] { diff --git a/library/src-bootstrapped/dotty/DottyPredef.scala b/library/src-bootstrapped/dotty/DottyPredef.scala new file mode 100644 index 000000000000..ef2f9dd5e8c0 --- /dev/null +++ b/library/src-bootstrapped/dotty/DottyPredef.scala @@ -0,0 +1,38 @@ +package dotty + +object DottyPredef { + + @forceInline final def assert(assertion: => Boolean, message: => Any): Unit = { + if (!assertion) + assertFail(message) + } + + @forceInline final def assert(assertion: => Boolean): Unit = { + if (!assertion) + assertFail() + } + + def assertFail(): Unit = throw new java.lang.AssertionError("assertion failed") + def assertFail(message: => Any): Unit = throw new java.lang.AssertionError("assertion failed: " + message) + + @forceInline final def implicitly[T](implicit ev: T): T = ev + + @forceInline def locally[T](body: => T): T = body + + /** + * Retrieve the single value of a type with a unique inhabitant. + * + * @example {{{ + * object Foo + * val foo = valueOf[Foo.type] + * // foo is Foo.type = Foo + * + * val bar = valueOf[23] + * // bar is 23.type = 23 + * }}} + * @group utilities + */ + @forceInline def valueOf[T](implicit vt: ValueOf[T]): T = vt.value + + inline def the[T](implicit x: T): x.type = x +} diff --git a/library/src/dotty/DottyPredef.scala b/library/src-non-bootstrapped/dotty/DottyPredef.scala similarity index 95% rename from library/src/dotty/DottyPredef.scala rename to library/src-non-bootstrapped/dotty/DottyPredef.scala index be0c1af3ad94..0350629a759b 100644 --- a/library/src/dotty/DottyPredef.scala +++ b/library/src-non-bootstrapped/dotty/DottyPredef.scala @@ -4,7 +4,6 @@ import scala.forceInline object DottyPredef { - @forceInline final def assert(assertion: => Boolean, message: => Any): Unit = { if (!assertion) assertFail(message) @@ -36,6 +35,4 @@ object DottyPredef { * @group utilities */ @forceInline def valueOf[T](implicit vt: ValueOf[T]): T = vt.value - - @forceInline def infer[T](implicit x: T) = x } diff --git a/tests/pos/reference/instances.scala b/tests/pos/reference/instances.scala index d5a838845af9..cd481cb0884c 100644 --- a/tests/pos/reference/instances.scala +++ b/tests/pos/reference/instances.scala @@ -120,20 +120,20 @@ object Instances extends Common { def f() = { locally { implied for Context = this.ctx - println(infer[Context].value) + println(the[Context].value) } locally { lazy val ctx1 = this.ctx implied for Context = ctx1 - println(infer[Context].value) + println(the[Context].value) } locally { implied d[T] for D[T] - println(infer[D[Int]]) + println(the[D[Int]]) } locally { implied given Context for D[Int] - println(infer[D[Int]]) + println(the[D[Int]]) } } } @@ -205,7 +205,7 @@ object AnonymousInstances extends Common { } def sum[T: Monoid](xs: List[T]): T = - xs.foldLeft(infer[Monoid[T]].unit)(_.combine(_)) + xs.foldLeft(the[Monoid[T]].unit)(_.combine(_)) } object Implicits extends Common { diff --git a/tests/pos/the.scala b/tests/pos/the.scala new file mode 100644 index 000000000000..68c399055af8 --- /dev/null +++ b/tests/pos/the.scala @@ -0,0 +1,12 @@ +object Test { + + trait Foo { type T; val x: T } + + implied intFoo for Foo { + type T = Int + val x = 3 + } + + val y: Int = the[Foo].x + +} \ No newline at end of file diff --git a/tests/run/implicit-disambiguation.scala b/tests/run/implicit-disambiguation.scala index c1b7de40a0f5..bc346da76e7e 100644 --- a/tests/run/implicit-disambiguation.scala +++ b/tests/run/implicit-disambiguation.scala @@ -9,8 +9,8 @@ class C extends A { } object M { def f given B, C : String = { - implied a for A = infer[B] - infer[A].show + implied a for A = the[B] + the[A].show } } object Test extends App {