-
Notifications
You must be signed in to change notification settings - Fork 530
/
typeoperators.scala
174 lines (151 loc) · 5.55 KB
/
typeoperators.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
* Copyright (c) 2011-15 Miles Sabin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package shapeless
import scala.language.dynamics
import scala.language.experimental.macros
import scala.reflect.macros.Context
import scala.util.Try
object tag {
def apply[U] = new Tagger[U]
trait Tagged[U]
type @@[+T, U] = T with Tagged[U]
class Tagger[U] {
def apply[T](t : T) : T @@ U = t.asInstanceOf[T @@ U]
}
}
object newtype {
/**
* Creates a value of the newtype given a value of its representation type.
*/
def apply[Repr, Ops](r : Repr) : Newtype[Repr, Ops] = r.asInstanceOf[Any with Newtype[Repr, Ops]]
/**
* New type with `Repr` as representation type and operations provided by `Ops`.
*
* Values of the newtype will not add any additional boxing beyond what's required for
* values of the representation type to conform to Any. In practice this means that value
* types will receive their standard Scala AnyVal boxing and reference types will be unboxed.
*/
type Newtype[Repr, Ops] = { type Tag = NewtypeTag[Repr, Ops] }
trait NewtypeTag[Repr, Ops]
/**
* Implicit conversion of newtype to `Ops` type for the selection of `Ops` newtype operations.
*
* The implicit conversion `Repr => Ops` would typically be provided by publishing the companion
* object of the `Ops` type as an implicit value.
*/
implicit def newtypeOps[Repr, Ops](t : Newtype[Repr, Ops])(implicit mkOps : Repr => Ops) : Ops = t.asInstanceOf[Repr]
}
/**
* An enhanced alternative to `Predef.implicitly`.
*
* Used as a term `the[T]` yields the unique implicit value of type `T` in the current
* implicit scope, if any. It is a compile time error if there is no such value. Its
* primary advantage over `Predef.implicitly` is that it will preserve any refinement that
* the implicit definition has, resulting in more precisely typed, and hence often more
* useful, values,
*
* {{{
* scala> trait Foo { type T ; val t: T }
* defined trait Foo
*
* scala> implicit val intFoo: Foo { type T = Int } = new Foo { type T = Int ; val t = 23 }
* intFoo: Foo{type T = Int} = \$anon\$1@6067b682
*
* scala> implicitly[Foo].t // implicitly loses precision
* res0: Foo#T = 23
*
* scala> implicitly[Foo].t+13
* <console>:13: error: type mismatch;
* found : Int(13)
* required: String
* implicitly[Foo].t+13
* ^
*
* scala> the[Foo].t // the retains it
* res1: Int = 23
*
* scala> the[Foo].t+13
* res2: Int = 36
* }}}
*
* Unlike `implicitly`, `the` can also be used in type position, thanks to a trick
* due to Denys Shabalin (@den_sh) and Eugene Burmako (@xeno_by). Here we use a
* combination of `selectDynamic` and backticks to embed a type in a path which
* appears to the compiler as stable,
*
* {{{
* scala> val i: implicitly[Foo].T = 23 // syntax error
* <console>:1: error: ';' expected but '.' found.
* val i: implicitly[Foo].T = 23
* ^
* scala> val i: the.`Foo`.T = 23 // OK
* i: Int = 23
* }}}
*/
object the extends Dynamic {
def apply[T](implicit t: T): T = macro TheMacros.applyImpl[T]
def selectDynamic(tpeSelector: String): Any = macro TheMacros.implicitlyImpl
}
class TheMacros[C <: Context](val c: C) {
import c.universe.{ Try => _, _ }
def applyImpl(t: Tree): Tree = t
def implicitlyImpl(tpeSelector: Tree): Tree = {
val q"${tpeString: String}" = tpeSelector
val dummyNme = c.fresh
val tpe =
(for {
parsed <- Try(c.parse(s"{ type $dummyNme = "+tpeString+" }")).toOption
checked = c.typeCheck(parsed, silent = true)
if !checked.isEmpty
} yield {
val q"{ type $dummyNme = $tpt }" = checked
tpt.tpe
}).getOrElse(c.abort(c.enclosingPosition, s"Malformed type $tpeString"))
// Bail for primitives because the resulting trees with type set to Unit
// will crash the compiler
if(tpe.typeSymbol.asClass.isPrimitive)
c.abort(c.enclosingPosition, s"Primitive type $tpe may not be used in this context")
val inferred = c.inferImplicitValue(tpe, silent = true)
if(inferred.isEmpty)
c.abort(c.enclosingPosition, s"Could not infer implicit value for $tpe")
// We can't yield a useful value here, so return Unit instead which is at least guaranteed
// to result in a runtime exception if the value is used in term position.
Literal(Constant(())).setType(inferred.tpe)
}
}
object TheMacros {
def inst(c: Context) = new TheMacros[c.type](c)
def applyImpl[T](c: Context)(t: c.Expr[T]): c.Expr[T] =
c.Expr[T](inst(c).applyImpl(t.tree))
def implicitlyImpl(c: Context)(tpeSelector: c.Expr[String]): c.Expr[Any] =
c.Expr[Any](inst(c).implicitlyImpl(tpeSelector.tree))
}
/**
* Type class witnessing the least upper bound of a pair of types and providing conversions from each to their common
* supertype.
*
* @author Miles Sabin
*/
trait Lub[-A, -B, Out] extends Serializable {
def left(a : A): Out
def right(b : B): Out
}
object Lub {
implicit def lub[T] = new Lub[T, T, T] {
def left(a : T): T = a
def right(b : T): T = b
}
}